0029729: Visualization, Graphic3d_ClipPlane - add support of clipping plane chains
[occt.git] / src / OpenGl / OpenGl_CappingAlgo.cxx
CommitLineData
4269bd1b 1// Created on: 2013-09-05
2// Created by: Anton POLETAEV
d5f74e42 3// Copyright (c) 2013-2014 OPEN CASCADE SAS
4269bd1b 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
4269bd1b 6//
d5f74e42 7// This library is free software; you can redistribute it and/or modify it under
8// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 9// by the Free Software Foundation, with special exception defined in the file
10// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11// distribution for complete text of the license and disclaimer of any warranty.
4269bd1b 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
4269bd1b 15
16#include <OpenGl_CappingAlgo.hxx>
deb02f86 17
25c35042 18#include <OpenGl_ClippingIterator.hxx>
4269bd1b 19#include <OpenGl_Workspace.hxx>
20#include <OpenGl_Context.hxx>
21#include <OpenGl_PrimitiveArray.hxx>
22#include <OpenGl_CappingPlaneResource.hxx>
23#include <OpenGl_Vec.hxx>
b64d84be 24#include <OpenGl_Structure.hxx>
deb02f86 25#include <OpenGl_ShaderManager.hxx>
4269bd1b 26
92efcf78 27IMPLEMENT_STANDARD_RTTIEXT(OpenGl_CappingAlgoFilter,OpenGl_RenderFilter)
28
4269bd1b 29namespace
30{
3e05329c 31 //! Render infinite capping plane.
32 //! @param theWorkspace [in] the GL workspace, context state.
33 //! @param thePlane [in] the graphical plane, for which the capping surface is rendered.
34 static void renderPlane (const Handle(OpenGl_Workspace)& theWorkspace,
35 const Handle(OpenGl_CappingPlaneResource)& thePlane,
36 const OpenGl_AspectFace* theAspectFace)
37 {
38 const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
39 thePlane->Update (aContext, theAspectFace != NULL ? theAspectFace->Aspect() : Handle(Graphic3d_AspectFillArea3d)());
40
25c35042 41 bool wasCullAllowed = theWorkspace->SetAllowFaceCulling (true);
3e05329c 42 const OpenGl_AspectFace* aFaceAspect = theWorkspace->AspectFace();
43 theWorkspace->SetAspectFace (thePlane->AspectFace());
44
45 // set identity model matrix
46 aContext->ModelWorldState.Push();
47 aContext->ModelWorldState.SetCurrent (OpenGl_Mat4::Map (*thePlane->Orientation()->mat));
48 aContext->ApplyModelViewMatrix();
49
50 thePlane->Primitives().Render (theWorkspace);
51
52 aContext->ModelWorldState.Pop();
53 aContext->ApplyModelViewMatrix();
54
25c35042 55 theWorkspace->SetAllowFaceCulling (wasCullAllowed);
3e05329c 56 theWorkspace->SetAspectFace (aFaceAspect);
57 }
58
59 //! Render capping for specific structure.
60 static void renderCappingForStructure (const Handle(OpenGl_Workspace)& theWorkspace,
61 const OpenGl_Structure& theStructure,
25c35042 62 const Handle(Graphic3d_ClipPlane)& theClipChain,
63 const Standard_Integer theSubPlaneIndex,
3e05329c 64 const Handle(OpenGl_CappingPlaneResource)& thePlane)
65 {
3202bf1e 66 const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
67 const Handle(Graphic3d_ClipPlane)& aRenderPlane = thePlane->Plane();
3e05329c 68 for (OpenGl_Structure::GroupIterator aGroupIter (theStructure.Groups()); aGroupIter.More(); aGroupIter.Next())
69 {
70 if (!aGroupIter.Value()->IsClosed())
71 {
72 continue;
73 }
74
75 // enable only the rendering plane to generate stencil mask
25c35042 76 aContext->ChangeClipping().DisableAllExcept (theClipChain, theSubPlaneIndex);
3e05329c 77 aContext->ShaderManager()->UpdateClippingState();
78
79 glClear (GL_STENCIL_BUFFER_BIT);
f88457e6 80 const bool aColorMaskBack = aContext->SetColorMask (false);
3e05329c 81
82 // override aspects, disable culling
83 theWorkspace->SetAspectFace (&theWorkspace->NoneCulling());
84 theWorkspace->ApplyAspectFace();
85
86 // evaluate number of pair faces
a1073ae2 87 if (theWorkspace->UseZBuffer())
88 {
89 glDisable (GL_DEPTH_TEST);
90 }
91 if (theWorkspace->UseDepthWrite())
92 {
93 glDepthMask (GL_FALSE);
94 }
3e05329c 95 glStencilFunc (GL_ALWAYS, 1, 0x01);
96 glStencilOp (GL_KEEP, GL_INVERT, GL_INVERT);
97
98 // render closed primitives
99 if (aRenderPlane->ToUseObjectProperties())
100 {
101 aGroupIter.Value()->Render (theWorkspace);
102 }
103 else
104 {
105 for (; aGroupIter.More(); aGroupIter.Next())
106 {
107 if (aGroupIter.Value()->IsClosed())
108 {
109 aGroupIter.Value()->Render (theWorkspace);
110 }
111 }
112 }
113
114 // override material, cull back faces
115 theWorkspace->SetAspectFace (&theWorkspace->FrontCulling());
116 theWorkspace->ApplyAspectFace();
117
118 // enable all clip plane except the rendered one
25c35042 119 aContext->ChangeClipping().EnableAllExcept (theClipChain, theSubPlaneIndex);
3e05329c 120 aContext->ShaderManager()->UpdateClippingState();
121
122 // render capping plane using the generated stencil mask
f88457e6 123 aContext->SetColorMask (aColorMaskBack);
a1073ae2 124 if (theWorkspace->UseDepthWrite())
125 {
126 glDepthMask (GL_TRUE);
127 }
3e05329c 128 glStencilFunc (GL_EQUAL, 1, 0x01);
129 glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
a1073ae2 130 if (theWorkspace->UseZBuffer())
131 {
132 glEnable (GL_DEPTH_TEST);
133 }
3e05329c 134
25c35042 135 renderPlane (theWorkspace, thePlane,
136 aRenderPlane->ToUseObjectProperties() ? aGroupIter.Value()->AspectFace() : NULL);
3e05329c 137
3202bf1e 138 // turn on the current plane to restore initial state
25c35042 139 aContext->ChangeClipping().ResetCappingFilter();
3e05329c 140 aContext->ShaderManager()->RevertClippingState();
141 aContext->ShaderManager()->RevertClippingState();
142 }
143
144 if (theStructure.InstancedStructure() != NULL)
145 {
25c35042 146 renderCappingForStructure (theWorkspace, *theStructure.InstancedStructure(), theClipChain, theSubPlaneIndex, thePlane);
3e05329c 147 }
148 }
ca3c13d1 149}
4269bd1b 150
151// =======================================================================
152// function : RenderCapping
153// purpose :
154// =======================================================================
cc6852f3 155void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorkspace,
156 const OpenGl_Structure& theStructure)
4269bd1b 157{
4269bd1b 158 const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
3202bf1e 159 if (!aContext->Clipping().IsCappingOn())
b859a34d 160 {
3202bf1e 161 // do not perform algorithm if there is nothing to render
4269bd1b 162 return;
b859a34d 163 }
4269bd1b 164
4269bd1b 165 // remember current aspect face defined in workspace
f9ba5c4d 166 const OpenGl_AspectFace* aFaceAsp = theWorkspace->AspectFace();
4269bd1b 167
168 // replace primitive groups rendering filter
4269bd1b 169 Handle(OpenGl_RenderFilter) aRenderFilter = theWorkspace->GetRenderFilter();
a1073ae2 170 Handle(OpenGl_CappingAlgoFilter) aCappingFilter = theWorkspace->DefaultCappingAlgoFilter();
171 aCappingFilter->SetPreviousFilter (aRenderFilter);
172 theWorkspace->SetRenderFilter (aCappingFilter);
4269bd1b 173
174 // prepare for rendering the clip planes
175 glEnable (GL_STENCIL_TEST);
176
347423b2 177 // remember current state of depth
178 // function and change its value
179 GLint aDepthFuncPrev;
180 glGetIntegerv (GL_DEPTH_FUNC, &aDepthFuncPrev);
181 glDepthFunc (GL_LESS);
182
4269bd1b 183 // generate capping for every clip plane
3202bf1e 184 for (OpenGl_ClippingIterator aCappingIt (aContext->Clipping()); aCappingIt.More(); aCappingIt.Next())
4269bd1b 185 {
186 // get plane being rendered
25c35042 187 const Handle(Graphic3d_ClipPlane)& aClipChain = aCappingIt.Value();
188 if (!aClipChain->IsCapping()
3202bf1e 189 || aCappingIt.IsDisabled())
4269bd1b 190 {
191 continue;
192 }
193
25c35042 194 Standard_Integer aSubPlaneIndex = 1;
195 for (const Graphic3d_ClipPlane* aSubPlaneIter = aClipChain.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get(), ++aSubPlaneIndex)
4269bd1b 196 {
25c35042 197 // get resource for the plane
198 const TCollection_AsciiString& aResId = aSubPlaneIter->GetId();
199 Handle(OpenGl_CappingPlaneResource) aPlaneRes;
200 if (!aContext->GetResource (aResId, aPlaneRes))
201 {
202 // share and register for release once the resource is no longer used
203 aPlaneRes = new OpenGl_CappingPlaneResource (aSubPlaneIter);
204 aContext->ShareResource (aResId, aPlaneRes);
205 }
4269bd1b 206
25c35042 207 renderCappingForStructure (theWorkspace, theStructure, aClipChain, aSubPlaneIndex, aPlaneRes);
4269bd1b 208
25c35042 209 // set delayed resource release
210 aPlaneRes.Nullify();
211 aContext->ReleaseResource (aResId, Standard_True);
212 }
4269bd1b 213 }
214
215 // restore previous application state
216 glClear (GL_STENCIL_BUFFER_BIT);
347423b2 217 glDepthFunc (aDepthFuncPrev);
4269bd1b 218 glStencilFunc (GL_ALWAYS, 0, 0xFF);
219 glDisable (GL_STENCIL_TEST);
220
4269bd1b 221 // restore rendering aspects
222 theWorkspace->SetAspectFace (aFaceAsp);
223 theWorkspace->SetRenderFilter (aRenderFilter);
224}
225
4269bd1b 226// =======================================================================
227// function : CanRender
228// purpose :
229// =======================================================================
a1073ae2 230Standard_Boolean OpenGl_CappingAlgoFilter::ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace,
231 const OpenGl_Element* theGlElement)
4269bd1b 232{
a1073ae2 233 if (!myFilter.IsNull() && !myFilter->ShouldRender (theWorkspace, theGlElement))
234 {
235 return Standard_False;
236 }
237
64c6d8df 238 return theGlElement->IsFillDrawMode();
4269bd1b 239}