0029729: Visualization, Graphic3d_ClipPlane - add support of clipping plane chains
[occt.git] / src / OpenGl / OpenGl_CappingAlgo.cxx
1 // Created on: 2013-09-05
2 // Created by: Anton POLETAEV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
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.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <OpenGl_CappingAlgo.hxx>
17
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>
26
27 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_CappingAlgoFilter,OpenGl_RenderFilter)
28
29 namespace
30 {
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
41     bool wasCullAllowed = theWorkspace->SetAllowFaceCulling (true);
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
55     theWorkspace->SetAllowFaceCulling (wasCullAllowed);
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,
62                                          const Handle(Graphic3d_ClipPlane)& theClipChain,
63                                          const Standard_Integer          theSubPlaneIndex,
64                                          const Handle(OpenGl_CappingPlaneResource)& thePlane)
65   {
66     const Handle(OpenGl_Context)&      aContext     = theWorkspace->GetGlContext();
67     const Handle(Graphic3d_ClipPlane)& aRenderPlane = thePlane->Plane();
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
76       aContext->ChangeClipping().DisableAllExcept (theClipChain, theSubPlaneIndex);
77       aContext->ShaderManager()->UpdateClippingState();
78
79       glClear (GL_STENCIL_BUFFER_BIT);
80       const bool aColorMaskBack = aContext->SetColorMask (false);
81
82       // override aspects, disable culling
83       theWorkspace->SetAspectFace (&theWorkspace->NoneCulling());
84       theWorkspace->ApplyAspectFace();
85
86       // evaluate number of pair faces
87       if (theWorkspace->UseZBuffer())
88       {
89         glDisable (GL_DEPTH_TEST);
90       }
91       if (theWorkspace->UseDepthWrite())
92       {
93         glDepthMask (GL_FALSE);
94       }
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
119       aContext->ChangeClipping().EnableAllExcept (theClipChain, theSubPlaneIndex);
120       aContext->ShaderManager()->UpdateClippingState();
121
122       // render capping plane using the generated stencil mask
123       aContext->SetColorMask (aColorMaskBack);
124       if (theWorkspace->UseDepthWrite())
125       {
126         glDepthMask (GL_TRUE);
127       }
128       glStencilFunc (GL_EQUAL, 1, 0x01);
129       glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
130       if (theWorkspace->UseZBuffer())
131       {
132         glEnable (GL_DEPTH_TEST);
133       }
134
135       renderPlane (theWorkspace, thePlane,
136                    aRenderPlane->ToUseObjectProperties() ? aGroupIter.Value()->AspectFace() : NULL);
137
138       // turn on the current plane to restore initial state
139       aContext->ChangeClipping().ResetCappingFilter();
140       aContext->ShaderManager()->RevertClippingState();
141       aContext->ShaderManager()->RevertClippingState();
142     }
143
144     if (theStructure.InstancedStructure() != NULL)
145     {
146       renderCappingForStructure (theWorkspace, *theStructure.InstancedStructure(), theClipChain, theSubPlaneIndex, thePlane);
147     }
148   }
149 }
150
151 // =======================================================================
152 // function : RenderCapping
153 // purpose  :
154 // =======================================================================
155 void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorkspace,
156                                         const OpenGl_Structure&         theStructure)
157 {
158   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
159   if (!aContext->Clipping().IsCappingOn())
160   {
161     // do not perform algorithm if there is nothing to render
162     return;
163   }
164
165   // remember current aspect face defined in workspace
166   const OpenGl_AspectFace* aFaceAsp = theWorkspace->AspectFace();
167
168   // replace primitive groups rendering filter
169   Handle(OpenGl_RenderFilter) aRenderFilter = theWorkspace->GetRenderFilter();
170   Handle(OpenGl_CappingAlgoFilter) aCappingFilter = theWorkspace->DefaultCappingAlgoFilter();
171   aCappingFilter->SetPreviousFilter (aRenderFilter);
172   theWorkspace->SetRenderFilter (aCappingFilter);
173
174   // prepare for rendering the clip planes
175   glEnable (GL_STENCIL_TEST);
176
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
183   // generate capping for every clip plane
184   for (OpenGl_ClippingIterator aCappingIt (aContext->Clipping()); aCappingIt.More(); aCappingIt.Next())
185   {
186     // get plane being rendered
187     const Handle(Graphic3d_ClipPlane)& aClipChain = aCappingIt.Value();
188     if (!aClipChain->IsCapping()
189       || aCappingIt.IsDisabled())
190     {
191       continue;
192     }
193
194     Standard_Integer aSubPlaneIndex = 1;
195     for (const Graphic3d_ClipPlane* aSubPlaneIter = aClipChain.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get(), ++aSubPlaneIndex)
196     {
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       }
206
207       renderCappingForStructure (theWorkspace, theStructure, aClipChain, aSubPlaneIndex, aPlaneRes);
208
209       // set delayed resource release
210       aPlaneRes.Nullify();
211       aContext->ReleaseResource (aResId, Standard_True);
212     }
213   }
214
215   // restore previous application state
216   glClear (GL_STENCIL_BUFFER_BIT);
217   glDepthFunc (aDepthFuncPrev);
218   glStencilFunc (GL_ALWAYS, 0, 0xFF);
219   glDisable (GL_STENCIL_TEST);
220
221   // restore rendering aspects
222   theWorkspace->SetAspectFace (aFaceAsp);
223   theWorkspace->SetRenderFilter (aRenderFilter);
224 }
225
226 // =======================================================================
227 // function : CanRender
228 // purpose  :
229 // =======================================================================
230 Standard_Boolean OpenGl_CappingAlgoFilter::ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace,
231                                                          const OpenGl_Element* theGlElement)
232 {
233   if (!myFilter.IsNull() && !myFilter->ShouldRender (theWorkspace, theGlElement))
234   {
235     return Standard_False;
236   }
237
238   return theGlElement->IsFillDrawMode();
239 }