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> |
b9280b8b |
19 | #include <OpenGl_RenderFilter.hxx> |
4269bd1b |
20 | #include <OpenGl_Context.hxx> |
4269bd1b |
21 | #include <OpenGl_CappingPlaneResource.hxx> |
b64d84be |
22 | #include <OpenGl_Structure.hxx> |
deb02f86 |
23 | #include <OpenGl_ShaderManager.hxx> |
4269bd1b |
24 | |
4269bd1b |
25 | namespace |
26 | { |
1b661a81 |
27 | //! Auxiliary sentry object managing stencil test. |
28 | struct StencilTestSentry |
29 | { |
8f7159cb |
30 | StencilTestSentry (const Handle(OpenGl_Context)& theCtx) |
31 | : myCtx (theCtx.get()), myDepthFuncPrev (0) {} |
1b661a81 |
32 | |
33 | //! Restore previous application state. |
34 | ~StencilTestSentry() |
35 | { |
36 | if (myDepthFuncPrev != 0) |
37 | { |
8f7159cb |
38 | myCtx->core11fwd->glClear (GL_STENCIL_BUFFER_BIT); |
39 | myCtx->core11fwd->glDepthFunc (myDepthFuncPrev); |
40 | myCtx->core11fwd->glStencilFunc (GL_ALWAYS, 0, 0xFF); |
41 | myCtx->core11fwd->glDisable (GL_STENCIL_TEST); |
1b661a81 |
42 | } |
43 | } |
44 | |
45 | //! Prepare for rendering the clip planes. |
46 | void Init() |
47 | { |
48 | if (myDepthFuncPrev == 0) |
49 | { |
8f7159cb |
50 | myCtx->core11fwd->glEnable (GL_STENCIL_TEST); |
51 | myCtx->core11fwd->glGetIntegerv (GL_DEPTH_FUNC, &myDepthFuncPrev); |
52 | myCtx->core11fwd->glDepthFunc (GL_LESS); |
1b661a81 |
53 | } |
54 | } |
55 | |
56 | private: |
8f7159cb |
57 | OpenGl_Context* myCtx; |
1b661a81 |
58 | GLint myDepthFuncPrev; |
59 | }; |
60 | |
3e05329c |
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, |
1b661a81 |
65 | const Handle(OpenGl_CappingPlaneResource)& thePlane) |
3e05329c |
66 | { |
67 | const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext(); |
1b661a81 |
68 | const bool wasCullAllowed = theWorkspace->SetAllowFaceCulling (true); |
3e05329c |
69 | |
70 | // set identity model matrix |
71 | aContext->ModelWorldState.Push(); |
a2af24d1 |
72 | aContext->ModelWorldState.SetCurrent (thePlane->Orientation()); |
3e05329c |
73 | aContext->ApplyModelViewMatrix(); |
74 | |
75 | thePlane->Primitives().Render (theWorkspace); |
76 | |
77 | aContext->ModelWorldState.Pop(); |
78 | aContext->ApplyModelViewMatrix(); |
79 | |
25c35042 |
80 | theWorkspace->SetAllowFaceCulling (wasCullAllowed); |
3e05329c |
81 | } |
82 | |
83 | //! Render capping for specific structure. |
1b661a81 |
84 | static void renderCappingForStructure (StencilTestSentry& theStencilSentry, |
85 | const Handle(OpenGl_Workspace)& theWorkspace, |
3e05329c |
86 | const OpenGl_Structure& theStructure, |
25c35042 |
87 | const Handle(Graphic3d_ClipPlane)& theClipChain, |
88 | const Standard_Integer theSubPlaneIndex, |
3e05329c |
89 | const Handle(OpenGl_CappingPlaneResource)& thePlane) |
90 | { |
1b661a81 |
91 | const Standard_Integer aPrevFilter = theWorkspace->RenderFilter(); |
92 | const Standard_Integer anAnyFilter = aPrevFilter & ~(Standard_Integer )(OpenGl_RenderFilter_OpaqueOnly | OpenGl_RenderFilter_TransparentOnly); |
93 | |
3202bf1e |
94 | const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext(); |
95 | const Handle(Graphic3d_ClipPlane)& aRenderPlane = thePlane->Plane(); |
3e05329c |
96 | for (OpenGl_Structure::GroupIterator aGroupIter (theStructure.Groups()); aGroupIter.More(); aGroupIter.Next()) |
97 | { |
98 | if (!aGroupIter.Value()->IsClosed()) |
99 | { |
100 | continue; |
101 | } |
102 | |
1b661a81 |
103 | // clear stencil only if something has been actually drawn |
104 | theStencilSentry.Init(); |
105 | |
106 | // check if capping plane should be rendered within current pass (only opaque / only transparent) |
bf5f0ca2 |
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()); |
1b661a81 |
110 | theWorkspace->SetRenderFilter (aPrevFilter); |
4552cb85 |
111 | if (!theWorkspace->ShouldRender (&thePlane->Primitives(), aGroupIter.Value())) |
1b661a81 |
112 | { |
113 | continue; |
114 | } |
115 | |
116 | // suppress only opaque/transparent filter since for filling stencil the whole geometry should be drawn |
117 | theWorkspace->SetRenderFilter (anAnyFilter); |
118 | |
3e05329c |
119 | // enable only the rendering plane to generate stencil mask |
25c35042 |
120 | aContext->ChangeClipping().DisableAllExcept (theClipChain, theSubPlaneIndex); |
3e05329c |
121 | aContext->ShaderManager()->UpdateClippingState(); |
122 | |
8f7159cb |
123 | aContext->core11fwd->glClear (GL_STENCIL_BUFFER_BIT); |
f88457e6 |
124 | const bool aColorMaskBack = aContext->SetColorMask (false); |
3e05329c |
125 | |
126 | // override aspects, disable culling |
bf5f0ca2 |
127 | theWorkspace->SetAspects (&theWorkspace->NoneCulling()); |
128 | theWorkspace->ApplyAspects(); |
3e05329c |
129 | |
130 | // evaluate number of pair faces |
a1073ae2 |
131 | if (theWorkspace->UseZBuffer()) |
132 | { |
8f7159cb |
133 | aContext->core11fwd->glDisable (GL_DEPTH_TEST); |
a1073ae2 |
134 | } |
135 | if (theWorkspace->UseDepthWrite()) |
136 | { |
8f7159cb |
137 | aContext->core11fwd->glDepthMask (GL_FALSE); |
a1073ae2 |
138 | } |
8f7159cb |
139 | aContext->core11fwd->glStencilFunc (GL_ALWAYS, 1, 0x01); |
140 | aContext->core11fwd->glStencilOp (GL_KEEP, GL_INVERT, GL_INVERT); |
3e05329c |
141 | |
142 | // render closed primitives |
143 | if (aRenderPlane->ToUseObjectProperties()) |
144 | { |
145 | aGroupIter.Value()->Render (theWorkspace); |
146 | } |
147 | else |
148 | { |
149 | for (; aGroupIter.More(); aGroupIter.Next()) |
150 | { |
151 | if (aGroupIter.Value()->IsClosed()) |
152 | { |
153 | aGroupIter.Value()->Render (theWorkspace); |
154 | } |
155 | } |
156 | } |
157 | |
158 | // override material, cull back faces |
bf5f0ca2 |
159 | theWorkspace->SetAspects (&theWorkspace->FrontCulling()); |
160 | theWorkspace->ApplyAspects(); |
3e05329c |
161 | |
162 | // enable all clip plane except the rendered one |
25c35042 |
163 | aContext->ChangeClipping().EnableAllExcept (theClipChain, theSubPlaneIndex); |
3e05329c |
164 | aContext->ShaderManager()->UpdateClippingState(); |
165 | |
166 | // render capping plane using the generated stencil mask |
f88457e6 |
167 | aContext->SetColorMask (aColorMaskBack); |
a1073ae2 |
168 | if (theWorkspace->UseDepthWrite()) |
169 | { |
8f7159cb |
170 | aContext->core11fwd->glDepthMask (GL_TRUE); |
a1073ae2 |
171 | } |
8f7159cb |
172 | aContext->core11fwd->glStencilFunc (GL_EQUAL, 1, 0x01); |
173 | aContext->core11fwd->glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); |
a1073ae2 |
174 | if (theWorkspace->UseZBuffer()) |
175 | { |
8f7159cb |
176 | aContext->core11fwd->glEnable (GL_DEPTH_TEST); |
a1073ae2 |
177 | } |
3e05329c |
178 | |
bf5f0ca2 |
179 | theWorkspace->SetAspects (thePlane->AspectFace()); |
1b661a81 |
180 | renderPlane (theWorkspace, thePlane); |
3e05329c |
181 | |
3202bf1e |
182 | // turn on the current plane to restore initial state |
25c35042 |
183 | aContext->ChangeClipping().ResetCappingFilter(); |
3e05329c |
184 | aContext->ShaderManager()->RevertClippingState(); |
185 | aContext->ShaderManager()->RevertClippingState(); |
186 | } |
187 | |
188 | if (theStructure.InstancedStructure() != NULL) |
189 | { |
1b661a81 |
190 | renderCappingForStructure (theStencilSentry, theWorkspace, *theStructure.InstancedStructure(), theClipChain, theSubPlaneIndex, thePlane); |
3e05329c |
191 | } |
192 | } |
ca3c13d1 |
193 | } |
4269bd1b |
194 | |
195 | // ======================================================================= |
196 | // function : RenderCapping |
197 | // purpose : |
198 | // ======================================================================= |
cc6852f3 |
199 | void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorkspace, |
200 | const OpenGl_Structure& theStructure) |
4269bd1b |
201 | { |
4269bd1b |
202 | const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext(); |
3202bf1e |
203 | if (!aContext->Clipping().IsCappingOn()) |
b859a34d |
204 | { |
3202bf1e |
205 | // do not perform algorithm if there is nothing to render |
4269bd1b |
206 | return; |
b859a34d |
207 | } |
4269bd1b |
208 | |
4269bd1b |
209 | // remember current aspect face defined in workspace |
bf5f0ca2 |
210 | const OpenGl_Aspects* aFaceAsp = theWorkspace->Aspects(); |
4269bd1b |
211 | |
1b661a81 |
212 | // only filled primitives should be rendered |
213 | const Standard_Integer aPrevFilter = theWorkspace->RenderFilter(); |
214 | theWorkspace->SetRenderFilter (aPrevFilter | OpenGl_RenderFilter_FillModeOnly); |
8f7159cb |
215 | StencilTestSentry aStencilSentry (aContext); |
347423b2 |
216 | |
4269bd1b |
217 | // generate capping for every clip plane |
3202bf1e |
218 | for (OpenGl_ClippingIterator aCappingIt (aContext->Clipping()); aCappingIt.More(); aCappingIt.Next()) |
4269bd1b |
219 | { |
220 | // get plane being rendered |
25c35042 |
221 | const Handle(Graphic3d_ClipPlane)& aClipChain = aCappingIt.Value(); |
222 | if (!aClipChain->IsCapping() |
3202bf1e |
223 | || aCappingIt.IsDisabled()) |
4269bd1b |
224 | { |
225 | continue; |
226 | } |
227 | |
25c35042 |
228 | Standard_Integer aSubPlaneIndex = 1; |
229 | for (const Graphic3d_ClipPlane* aSubPlaneIter = aClipChain.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get(), ++aSubPlaneIndex) |
4269bd1b |
230 | { |
25c35042 |
231 | // get resource for the plane |
232 | const TCollection_AsciiString& aResId = aSubPlaneIter->GetId(); |
233 | Handle(OpenGl_CappingPlaneResource) aPlaneRes; |
234 | if (!aContext->GetResource (aResId, aPlaneRes)) |
235 | { |
236 | // share and register for release once the resource is no longer used |
237 | aPlaneRes = new OpenGl_CappingPlaneResource (aSubPlaneIter); |
238 | aContext->ShareResource (aResId, aPlaneRes); |
239 | } |
4269bd1b |
240 | |
1b661a81 |
241 | renderCappingForStructure (aStencilSentry, theWorkspace, theStructure, aClipChain, aSubPlaneIndex, aPlaneRes); |
4269bd1b |
242 | |
25c35042 |
243 | // set delayed resource release |
244 | aPlaneRes.Nullify(); |
245 | aContext->ReleaseResource (aResId, Standard_True); |
246 | } |
4269bd1b |
247 | } |
248 | |
4269bd1b |
249 | // restore rendering aspects |
bf5f0ca2 |
250 | theWorkspace->SetAspects (aFaceAsp); |
1b661a81 |
251 | theWorkspace->SetRenderFilter (aPrevFilter); |
4269bd1b |
252 | } |