4b2a3e93523d2a169febcb88540717469a71ac5b
[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_Workspace.hxx>
19 #include <OpenGl_Context.hxx>
20 #include <OpenGl_PrimitiveArray.hxx>
21 #include <OpenGl_CappingPlaneResource.hxx>
22 #include <OpenGl_Vec.hxx>
23 #include <OpenGl_Structure.hxx>
24 #include <OpenGl_ShaderManager.hxx>
25
26 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_CappingAlgoFilter,OpenGl_RenderFilter)
27
28 namespace
29 {
30   //! Render infinite capping plane.
31   //! @param theWorkspace [in] the GL workspace, context state.
32   //! @param thePlane [in] the graphical plane, for which the capping surface is rendered.
33   static void renderPlane (const Handle(OpenGl_Workspace)& theWorkspace,
34                            const Handle(OpenGl_CappingPlaneResource)& thePlane,
35                            const OpenGl_AspectFace* theAspectFace)
36   {
37     const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
38     thePlane->Update (aContext, theAspectFace != NULL ? theAspectFace->Aspect() : Handle(Graphic3d_AspectFillArea3d)());
39
40     const OpenGl_AspectFace* aFaceAspect = theWorkspace->AspectFace();
41     theWorkspace->SetAspectFace (thePlane->AspectFace());
42
43     // set identity model matrix
44     aContext->ModelWorldState.Push();
45     aContext->ModelWorldState.SetCurrent (OpenGl_Mat4::Map (*thePlane->Orientation()->mat));
46     aContext->ApplyModelViewMatrix();
47
48     thePlane->Primitives().Render (theWorkspace);
49
50     aContext->ModelWorldState.Pop();
51     aContext->ApplyModelViewMatrix();
52
53     theWorkspace->SetAspectFace (aFaceAspect);
54   }
55
56   //! Render capping for specific structure.
57   static void renderCappingForStructure (const Handle(OpenGl_Workspace)& theWorkspace,
58                                          const OpenGl_Structure&         theStructure,
59                                          const OpenGl_ClippingIterator&  thePlaneIter,
60                                          const Handle(OpenGl_CappingPlaneResource)& thePlane)
61   {
62     const Handle(OpenGl_Context)&      aContext     = theWorkspace->GetGlContext();
63     const Handle(Graphic3d_ClipPlane)& aRenderPlane = thePlane->Plane();
64     for (OpenGl_Structure::GroupIterator aGroupIter (theStructure.Groups()); aGroupIter.More(); aGroupIter.Next())
65     {
66       if (!aGroupIter.Value()->IsClosed())
67       {
68         continue;
69       }
70
71       // enable only the rendering plane to generate stencil mask
72       aContext->ChangeClipping().DisableAllExcept (aContext, thePlaneIter);
73       aContext->ShaderManager()->UpdateClippingState();
74
75       glClear (GL_STENCIL_BUFFER_BIT);
76       glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
77
78       // override aspects, disable culling
79       theWorkspace->SetAspectFace (&theWorkspace->NoneCulling());
80       theWorkspace->ApplyAspectFace();
81
82       // evaluate number of pair faces
83       if (theWorkspace->UseZBuffer())
84       {
85         glDisable (GL_DEPTH_TEST);
86       }
87       if (theWorkspace->UseDepthWrite())
88       {
89         glDepthMask (GL_FALSE);
90       }
91       glStencilFunc (GL_ALWAYS, 1, 0x01);
92       glStencilOp (GL_KEEP, GL_INVERT, GL_INVERT);
93
94       // render closed primitives
95       if (aRenderPlane->ToUseObjectProperties())
96       {
97         aGroupIter.Value()->Render (theWorkspace);
98       }
99       else
100       {
101         for (; aGroupIter.More(); aGroupIter.Next())
102         {
103           if (aGroupIter.Value()->IsClosed())
104           {
105             aGroupIter.Value()->Render (theWorkspace);
106           }
107         }
108       }
109
110       // override material, cull back faces
111       theWorkspace->SetAspectFace (&theWorkspace->FrontCulling());
112       theWorkspace->ApplyAspectFace();
113
114       // enable all clip plane except the rendered one
115       aContext->ChangeClipping().EnableAllExcept (aContext, thePlaneIter);
116       aContext->ShaderManager()->UpdateClippingState();
117
118       // render capping plane using the generated stencil mask
119       glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
120       if (theWorkspace->UseDepthWrite())
121       {
122         glDepthMask (GL_TRUE);
123       }
124       glStencilFunc (GL_EQUAL, 1, 0x01);
125       glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
126       if (theWorkspace->UseZBuffer())
127       {
128         glEnable (GL_DEPTH_TEST);
129       }
130
131       renderPlane (theWorkspace, thePlane, aRenderPlane->ToUseObjectProperties()
132                                          ? aGroupIter.Value()->AspectFace()
133                                          : NULL);
134
135       // turn on the current plane to restore initial state
136       aContext->ChangeClipping().SetEnabled (aContext, thePlaneIter, Standard_True);
137       aContext->ShaderManager()->RevertClippingState();
138       aContext->ShaderManager()->RevertClippingState();
139     }
140
141     if (theStructure.InstancedStructure() != NULL)
142     {
143       renderCappingForStructure (theWorkspace, *theStructure.InstancedStructure(), thePlaneIter, thePlane);
144     }
145   }
146 }
147
148 // =======================================================================
149 // function : RenderCapping
150 // purpose  :
151 // =======================================================================
152 void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorkspace,
153                                         const OpenGl_Structure&         theStructure)
154 {
155   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
156   if (!aContext->Clipping().IsCappingOn())
157   {
158     // do not perform algorithm if there is nothing to render
159     return;
160   }
161
162   // remember current aspect face defined in workspace
163   const OpenGl_AspectFace* aFaceAsp = theWorkspace->AspectFace();
164
165   // replace primitive groups rendering filter
166   Handle(OpenGl_RenderFilter) aRenderFilter = theWorkspace->GetRenderFilter();
167   Handle(OpenGl_CappingAlgoFilter) aCappingFilter = theWorkspace->DefaultCappingAlgoFilter();
168   aCappingFilter->SetPreviousFilter (aRenderFilter);
169   theWorkspace->SetRenderFilter (aCappingFilter);
170
171   // prepare for rendering the clip planes
172   glEnable (GL_STENCIL_TEST);
173
174   // remember current state of depth
175   // function and change its value
176   GLint aDepthFuncPrev;
177   glGetIntegerv (GL_DEPTH_FUNC, &aDepthFuncPrev);
178   glDepthFunc (GL_LESS);
179
180   // generate capping for every clip plane
181   for (OpenGl_ClippingIterator aCappingIt (aContext->Clipping()); aCappingIt.More(); aCappingIt.Next())
182   {
183     // get plane being rendered
184     const Handle(Graphic3d_ClipPlane)& aRenderPlane = aCappingIt.Value();
185     if (!aRenderPlane->IsCapping()
186       || aCappingIt.IsDisabled())
187     {
188       continue;
189     }
190
191     // get resource for the plane
192     const TCollection_AsciiString& aResId = aRenderPlane->GetId();
193     Handle(OpenGl_CappingPlaneResource) aPlaneRes;
194     if (!aContext->GetResource (aResId, aPlaneRes))
195     {
196       // share and register for release once the resource is no longer used
197       aPlaneRes = new OpenGl_CappingPlaneResource (aRenderPlane);
198       aContext->ShareResource (aResId, aPlaneRes);
199     }
200
201     renderCappingForStructure (theWorkspace, theStructure, aCappingIt, aPlaneRes);
202
203     // set delayed resource release
204     aPlaneRes.Nullify();
205     aContext->ReleaseResource (aResId, Standard_True);
206   }
207
208   // restore previous application state
209   glClear (GL_STENCIL_BUFFER_BIT);
210   glDepthFunc (aDepthFuncPrev);
211   glStencilFunc (GL_ALWAYS, 0, 0xFF);
212   glDisable (GL_STENCIL_TEST);
213
214   // restore rendering aspects
215   theWorkspace->SetAspectFace (aFaceAsp);
216   theWorkspace->SetRenderFilter (aRenderFilter);
217 }
218
219 // =======================================================================
220 // function : CanRender
221 // purpose  :
222 // =======================================================================
223 Standard_Boolean OpenGl_CappingAlgoFilter::ShouldRender (const Handle(OpenGl_Workspace)& theWorkspace,
224                                                          const OpenGl_Element* theGlElement)
225 {
226   if (!myFilter.IsNull() && !myFilter->ShouldRender (theWorkspace, theGlElement))
227   {
228     return Standard_False;
229   }
230
231   const OpenGl_PrimitiveArray* aPArray = dynamic_cast<const OpenGl_PrimitiveArray*> (theGlElement);
232   return aPArray != NULL
233       && aPArray->IsFillDrawMode();
234 }