1 // Created on: 2013-09-05
2 // Created by: Anton POLETAEV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <OpenGl_CappingAlgo.hxx>
18 #include <OpenGl_ClippingIterator.hxx>
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>
24 #include <OpenGl_Structure.hxx>
25 #include <OpenGl_ShaderManager.hxx>
29 //! Auxiliary sentry object managing stencil test.
30 struct StencilTestSentry
32 StencilTestSentry() : myDepthFuncPrev (0) {}
34 //! Restore previous application state.
37 if (myDepthFuncPrev != 0)
39 glClear (GL_STENCIL_BUFFER_BIT);
40 glDepthFunc (myDepthFuncPrev);
41 glStencilFunc (GL_ALWAYS, 0, 0xFF);
42 glDisable (GL_STENCIL_TEST);
46 //! Prepare for rendering the clip planes.
49 if (myDepthFuncPrev == 0)
51 glEnable (GL_STENCIL_TEST);
52 glGetIntegerv (GL_DEPTH_FUNC, &myDepthFuncPrev);
53 glDepthFunc (GL_LESS);
58 GLint myDepthFuncPrev;
61 //! Render infinite capping plane.
62 //! @param theWorkspace [in] the GL workspace, context state.
63 //! @param thePlane [in] the graphical plane, for which the capping surface is rendered.
64 static void renderPlane (const Handle(OpenGl_Workspace)& theWorkspace,
65 const Handle(OpenGl_CappingPlaneResource)& thePlane)
67 const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
68 const bool wasCullAllowed = theWorkspace->SetAllowFaceCulling (true);
70 // set identity model matrix
71 aContext->ModelWorldState.Push();
72 aContext->ModelWorldState.SetCurrent (thePlane->Orientation());
73 aContext->ApplyModelViewMatrix();
75 thePlane->Primitives().Render (theWorkspace);
77 aContext->ModelWorldState.Pop();
78 aContext->ApplyModelViewMatrix();
80 theWorkspace->SetAllowFaceCulling (wasCullAllowed);
83 //! Render capping for specific structure.
84 static void renderCappingForStructure (StencilTestSentry& theStencilSentry,
85 const Handle(OpenGl_Workspace)& theWorkspace,
86 const OpenGl_Structure& theStructure,
87 const Handle(Graphic3d_ClipPlane)& theClipChain,
88 const Standard_Integer theSubPlaneIndex,
89 const Handle(OpenGl_CappingPlaneResource)& thePlane)
91 const Standard_Integer aPrevFilter = theWorkspace->RenderFilter();
92 const Standard_Integer anAnyFilter = aPrevFilter & ~(Standard_Integer )(OpenGl_RenderFilter_OpaqueOnly | OpenGl_RenderFilter_TransparentOnly);
94 const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
95 const Handle(Graphic3d_ClipPlane)& aRenderPlane = thePlane->Plane();
96 for (OpenGl_Structure::GroupIterator aGroupIter (theStructure.Groups()); aGroupIter.More(); aGroupIter.Next())
98 if (!aGroupIter.Value()->IsClosed())
103 // clear stencil only if something has been actually drawn
104 theStencilSentry.Init();
106 // check if capping plane should be rendered within current pass (only opaque / only transparent)
107 const OpenGl_Aspects* anObjAspectFace = aRenderPlane->ToUseObjectProperties() ? aGroupIter.Value()->GlAspects() : NULL;
108 thePlane->Update (aContext, anObjAspectFace != NULL ? anObjAspectFace->Aspect() : Handle(Graphic3d_Aspects)());
109 theWorkspace->SetAspects (thePlane->AspectFace());
110 theWorkspace->SetRenderFilter (aPrevFilter);
111 if (!theWorkspace->ShouldRender (&thePlane->Primitives(), aGroupIter.Value()))
116 // suppress only opaque/transparent filter since for filling stencil the whole geometry should be drawn
117 theWorkspace->SetRenderFilter (anAnyFilter);
119 // enable only the rendering plane to generate stencil mask
120 aContext->ChangeClipping().DisableAllExcept (theClipChain, theSubPlaneIndex);
121 aContext->ShaderManager()->UpdateClippingState();
123 glClear (GL_STENCIL_BUFFER_BIT);
124 const bool aColorMaskBack = aContext->SetColorMask (false);
126 // override aspects, disable culling
127 theWorkspace->SetAspects (&theWorkspace->NoneCulling());
128 theWorkspace->ApplyAspects();
130 // evaluate number of pair faces
131 if (theWorkspace->UseZBuffer())
133 glDisable (GL_DEPTH_TEST);
135 if (theWorkspace->UseDepthWrite())
137 glDepthMask (GL_FALSE);
139 glStencilFunc (GL_ALWAYS, 1, 0x01);
140 glStencilOp (GL_KEEP, GL_INVERT, GL_INVERT);
142 // render closed primitives
143 if (aRenderPlane->ToUseObjectProperties())
145 aGroupIter.Value()->Render (theWorkspace);
149 for (; aGroupIter.More(); aGroupIter.Next())
151 if (aGroupIter.Value()->IsClosed())
153 aGroupIter.Value()->Render (theWorkspace);
158 // override material, cull back faces
159 theWorkspace->SetAspects (&theWorkspace->FrontCulling());
160 theWorkspace->ApplyAspects();
162 // enable all clip plane except the rendered one
163 aContext->ChangeClipping().EnableAllExcept (theClipChain, theSubPlaneIndex);
164 aContext->ShaderManager()->UpdateClippingState();
166 // render capping plane using the generated stencil mask
167 aContext->SetColorMask (aColorMaskBack);
168 if (theWorkspace->UseDepthWrite())
170 glDepthMask (GL_TRUE);
172 glStencilFunc (GL_EQUAL, 1, 0x01);
173 glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
174 if (theWorkspace->UseZBuffer())
176 glEnable (GL_DEPTH_TEST);
179 theWorkspace->SetAspects (thePlane->AspectFace());
180 renderPlane (theWorkspace, thePlane);
182 // turn on the current plane to restore initial state
183 aContext->ChangeClipping().ResetCappingFilter();
184 aContext->ShaderManager()->RevertClippingState();
185 aContext->ShaderManager()->RevertClippingState();
188 if (theStructure.InstancedStructure() != NULL)
190 renderCappingForStructure (theStencilSentry, theWorkspace, *theStructure.InstancedStructure(), theClipChain, theSubPlaneIndex, thePlane);
195 // =======================================================================
196 // function : RenderCapping
198 // =======================================================================
199 void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorkspace,
200 const OpenGl_Structure& theStructure)
202 const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
203 if (!aContext->Clipping().IsCappingOn())
205 // do not perform algorithm if there is nothing to render
209 // remember current aspect face defined in workspace
210 const OpenGl_Aspects* aFaceAsp = theWorkspace->Aspects();
212 // only filled primitives should be rendered
213 const Standard_Integer aPrevFilter = theWorkspace->RenderFilter();
214 theWorkspace->SetRenderFilter (aPrevFilter | OpenGl_RenderFilter_FillModeOnly);
215 StencilTestSentry aStencilSentry;
217 // generate capping for every clip plane
218 for (OpenGl_ClippingIterator aCappingIt (aContext->Clipping()); aCappingIt.More(); aCappingIt.Next())
220 // get plane being rendered
221 const Handle(Graphic3d_ClipPlane)& aClipChain = aCappingIt.Value();
222 if (!aClipChain->IsCapping()
223 || aCappingIt.IsDisabled())
228 Standard_Integer aSubPlaneIndex = 1;
229 for (const Graphic3d_ClipPlane* aSubPlaneIter = aClipChain.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get(), ++aSubPlaneIndex)
231 // get resource for the plane
232 const TCollection_AsciiString& aResId = aSubPlaneIter->GetId();
233 Handle(OpenGl_CappingPlaneResource) aPlaneRes;
234 if (!aContext->GetResource (aResId, aPlaneRes))
236 // share and register for release once the resource is no longer used
237 aPlaneRes = new OpenGl_CappingPlaneResource (aSubPlaneIter);
238 aContext->ShareResource (aResId, aPlaneRes);
241 renderCappingForStructure (aStencilSentry, theWorkspace, theStructure, aClipChain, aSubPlaneIndex, aPlaneRes);
243 // set delayed resource release
245 aContext->ReleaseResource (aResId, Standard_True);
249 // restore rendering aspects
250 theWorkspace->SetAspects (aFaceAsp);
251 theWorkspace->SetRenderFilter (aPrevFilter);