0024070: OpenGL capped object-level clipping planes
[occt.git] / src / OpenGl / OpenGl_CappingAlgo.cxx
1 // Created on: 2013-09-05
2 // Created by: Anton POLETAEV
3 // Copyright (c) 2013 OPEN CASCADE SAS
4 //
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
9 //
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12 //
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
19
20 #include <OpenGl_CappingAlgo.hxx>
21 #include <OpenGl_Workspace.hxx>
22 #include <OpenGl_Context.hxx>
23 #include <OpenGl_PrimitiveArray.hxx>
24 #include <OpenGl_CappingPlaneResource.hxx>
25 #include <OpenGl_Vec.hxx>
26
27 IMPLEMENT_STANDARD_HANDLE(OpenGl_CappingAlgoFilter, OpenGl_RenderFilter)
28 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_CappingAlgoFilter, OpenGl_RenderFilter)
29
30 Handle(OpenGl_RenderFilter) OpenGl_CappingAlgo::myRenderFilter;
31 OpenGl_AspectFace OpenGl_CappingAlgo::myFrontCulling;
32 OpenGl_AspectFace OpenGl_CappingAlgo::myNoneCulling;
33 Standard_Boolean OpenGl_CappingAlgo::myIsInit = Standard_False;
34
35 namespace
36 {
37   static const OpenGl_Vec4 THE_CAPPING_PLN_VERTS[12] =
38     { OpenGl_Vec4 ( 0.0f, 0.0f, 0.0f, 1.0f),
39       OpenGl_Vec4 ( 1.0f, 0.0f, 0.0f, 0.0f),
40       OpenGl_Vec4 ( 0.0f, 0.0f, 1.0f, 0.0f),
41       OpenGl_Vec4 ( 0.0f, 0.0f, 0.0f, 1.0f),
42       OpenGl_Vec4 ( 0.0f, 0.0f, 1.0f, 0.0f),
43       OpenGl_Vec4 (-1.0f, 0.0f, 0.0f, 0.0f),
44       OpenGl_Vec4 ( 0.0f, 0.0f, 0.0f, 1.0f),
45       OpenGl_Vec4 (-1.0f, 0.0f, 0.0f, 0.0f),
46       OpenGl_Vec4 ( 0.0f, 0.0f,-1.0f, 0.0f),
47       OpenGl_Vec4 ( 0.0f, 0.0f, 0.0f, 1.0f),
48       OpenGl_Vec4 ( 0.0f, 0.0f,-1.0f, 0.0f),
49       OpenGl_Vec4 ( 1.0f, 0.0f, 0.0f, 0.0f) };
50
51   static const OpenGl_Vec4 THE_CAPPING_PLN_TCOORD[12] = 
52     { OpenGl_Vec4 ( 0.0f, 0.0f, 0.0f, 1.0f),
53       OpenGl_Vec4 ( 1.0f, 0.0f, 0.0f, 0.0f),
54       OpenGl_Vec4 ( 0.0f, 1.0f, 0.0f, 0.0f),
55       OpenGl_Vec4 ( 0.0f, 0.0f, 0.0f, 1.0f),
56       OpenGl_Vec4 ( 0.0f, 1.0f, 0.0f, 0.0f),
57       OpenGl_Vec4 (-1.0f, 0.0f, 0.0f, 0.0f),
58       OpenGl_Vec4 ( 0.0f, 0.0f, 0.0f, 1.0f),
59       OpenGl_Vec4 (-1.0f, 0.0f, 0.0f, 0.0f),
60       OpenGl_Vec4 ( 0.0f,-1.0f, 0.0f, 0.0f),
61       OpenGl_Vec4 ( 0.0f, 0.0f, 0.0f, 1.0f),
62       OpenGl_Vec4 ( 0.0f,-1.0f, 0.0f, 0.0f),
63       OpenGl_Vec4 ( 1.0f, 0.0f, 0.0f, 0.0f) };
64 };
65
66 // =======================================================================
67 // function : RenderCapping
68 // purpose  :
69 // =======================================================================
70 void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorkspace,
71                                         const OpenGl_ListOfGroup& theGroups)
72 {
73   // do not draw capping surface for second transparency pass
74   if (theWorkspace->NamedStatus & OPENGL_NS_2NDPASSDO)
75     return;
76
77   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
78
79   // check whether algorithm need to be runned
80   Standard_Boolean isCapping = Standard_False;
81   Graphic3d_SetOfHClipPlane aContextPlanes = aContext->Clipping().Planes();
82   Graphic3d_SetOfHClipPlane::Iterator aCappingIt (aContextPlanes);
83   for (; aCappingIt.More(); aCappingIt.Next())
84   {
85     const Handle(Graphic3d_ClipPlane)& aPlane = aCappingIt.Value();
86     if (aPlane->IsCapping())
87     {
88       isCapping = Standard_True;
89       break;
90     }
91   }
92
93   // do not perform algorithm is there is nothing to render
94   if (!isCapping)
95     return;
96
97   // init internal data
98   Init();
99
100   // remember current aspect face defined in workspace
101   const OpenGl_AspectFace* aFaceAsp = theWorkspace->AspectFace (Standard_False);
102
103   // replace primitive groups rendering filter
104   static Handle(OpenGl_CappingAlgoFilter) aCappingFilter = new OpenGl_CappingAlgoFilter();
105   Handle(OpenGl_RenderFilter) aRenderFilter = theWorkspace->GetRenderFilter();
106   theWorkspace->SetRenderFilter (aCappingFilter);
107
108   // prepare for rendering the clip planes
109   glEnable (GL_STENCIL_TEST);
110
111   // generate capping for every clip plane
112   for (aCappingIt.Init (aContextPlanes); aCappingIt.More(); aCappingIt.Next())
113   {
114     // get plane being rendered
115     const Handle(Graphic3d_ClipPlane)& aRenderPlane = aCappingIt.Value();
116     if (!aRenderPlane->IsCapping())
117     {
118       continue;
119     }
120
121     // enable only the rendering plane to generate stencil mask
122     Graphic3d_SetOfHClipPlane::Iterator aPlaneIt (aContextPlanes);
123     for (; aPlaneIt.More(); aPlaneIt.Next())
124     {
125       const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
126       const Standard_Boolean isOn = (aPlane == aRenderPlane);
127       aContext->ChangeClipping().SetEnabled (aPlane, isOn);
128     }
129
130     glClear (GL_STENCIL_BUFFER_BIT);
131     glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
132
133     // override aspects, disable culling
134     theWorkspace->SetAspectFace (NoneCulling());
135     theWorkspace->AspectFace (Standard_True);
136
137     // evaluate number of pair faces
138     glDisable (GL_DEPTH_TEST);
139     glDepthMask (GL_FALSE);
140     glStencilFunc (GL_ALWAYS, 1, 0x01);
141     glStencilOp (GL_KEEP, GL_INVERT, GL_INVERT);
142
143     OpenGl_ListOfGroup::Iterator aGroupIt (theGroups);
144     for (; aGroupIt.More(); aGroupIt.Next())
145     {
146       aGroupIt.Value()->Render (theWorkspace);
147     }
148
149     // override material, cull backfaces
150     theWorkspace->SetAspectFace (FrontCulling());
151     theWorkspace->AspectFace (Standard_True);
152
153     // enable all clip plane except the rendered one
154     for (aPlaneIt.Init (aContextPlanes); aPlaneIt.More(); aPlaneIt.Next())
155     {
156       const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
157       const Standard_Boolean isOn = (aPlane != aRenderPlane);
158       aContext->ChangeClipping().SetEnabled (aPlane, isOn);
159     }
160
161     // render capping plane using the generated stencil mask
162     glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
163     glDepthMask (GL_TRUE);
164     glDepthFunc (GL_LESS);
165     glStencilFunc (GL_EQUAL, 1, 0x01);
166     glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
167     glEnable (GL_DEPTH_TEST);
168
169     RenderPlane (theWorkspace, aRenderPlane);
170   }
171
172   // restore previous application state
173   glClear (GL_STENCIL_BUFFER_BIT);
174   glStencilFunc (GL_ALWAYS, 0, 0xFF);
175   glDisable (GL_STENCIL_TEST);
176
177   // enable clipping
178   for (aCappingIt.Init (aContextPlanes); aCappingIt.More(); aCappingIt.Next())
179   {
180     aContext->ChangeClipping().SetEnabled (aCappingIt.Value(), Standard_True);
181   }
182
183   // restore rendering aspects
184   theWorkspace->SetAspectFace (aFaceAsp);
185   theWorkspace->SetRenderFilter (aRenderFilter);
186 }
187
188 // =======================================================================
189 // function : RenderPlane
190 // purpose  :
191 // =======================================================================
192 void OpenGl_CappingAlgo::RenderPlane (const Handle(OpenGl_Workspace)& theWorkspace,
193                                       const Handle(Graphic3d_ClipPlane)& thePlane)
194 {
195   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
196
197   // get resource for the plane
198   TCollection_AsciiString aResId = thePlane->GetId();
199
200   Handle(OpenGl_CappingPlaneResource) aPlaneRes;
201   if (!aContext->GetResource (aResId, aPlaneRes))
202   {
203     // share and register for release once the resource is no longer used
204     aPlaneRes = new OpenGl_CappingPlaneResource (thePlane);
205     aContext->ShareResource (aResId, aPlaneRes);
206   }
207
208   aPlaneRes->Update (aContext);
209
210   const OpenGl_AspectFace* aFaceAspect = theWorkspace->AspectFace (Standard_False);
211   const OpenGl_AspectFace* aPlaneAspect = aPlaneRes->AspectFace();
212   if (aPlaneAspect != NULL)
213   {
214     theWorkspace->SetAspectFace (aPlaneAspect);
215   }
216
217   // apply aspect for rendering
218   theWorkspace->AspectFace (Standard_True);
219
220   // set identity model matrix
221   const OpenGl_Matrix* aModelMatrix = theWorkspace->SetStructureMatrix (&OpenGl_IdentityMatrix);
222
223   glMultMatrixf ((const GLfloat*)aPlaneRes->Orientation());
224   glNormal3f (0.0f, 1.0f, 0.0f);
225   glEnableClientState (GL_VERTEX_ARRAY);
226   glVertexPointer (4, GL_FLOAT, 0, (GLfloat* )&THE_CAPPING_PLN_VERTS);
227   glEnableClientState (GL_TEXTURE_COORD_ARRAY);
228   glTexCoordPointer (4, GL_FLOAT, 0, (GLfloat*)&THE_CAPPING_PLN_TCOORD);
229   glDrawArrays (GL_TRIANGLES, 0, 12);
230   glDisableClientState (GL_VERTEX_ARRAY);
231   glDisableClientState (GL_TEXTURE_COORD_ARRAY);
232
233   theWorkspace->SetStructureMatrix (aModelMatrix);
234   theWorkspace->SetAspectFace (aFaceAspect);
235
236   // set delayed resource release
237   aPlaneRes.Nullify();
238   aContext->ReleaseResource (aResId, Standard_True);
239 }
240
241 // =======================================================================
242 // function : Init
243 // purpose  :
244 // =======================================================================
245 void OpenGl_CappingAlgo::Init()
246 {
247   if (myIsInit)
248     return;
249
250   myRenderFilter = new OpenGl_CappingAlgoFilter();
251   myNoneCulling.CullingMode = TelCullNone;
252   myNoneCulling.Edge = 0;
253
254   myFrontCulling.CullingMode = TelCullBack;
255   myFrontCulling.Edge = 0;
256
257   myIsInit = Standard_True;
258 }
259
260 // =======================================================================
261 // function : CanRender
262 // purpose  :
263 // =======================================================================
264 Standard_Boolean OpenGl_CappingAlgoFilter::CanRender (const OpenGl_Element* theElement)
265 {
266   const OpenGl_PrimitiveArray* aPArray =
267     dynamic_cast<const OpenGl_PrimitiveArray*> (theElement);
268   if (!aPArray)
269     return Standard_False;
270
271   switch (aPArray->PArray()->type)
272   {
273     case TelPolygonsArrayType :
274     case TelTrianglesArrayType :
275     case TelQuadranglesArrayType :
276     case TelTriangleStripsArrayType :
277     case TelQuadrangleStripsArrayType :
278     case TelTriangleFansArrayType :
279       return Standard_True;
280
281     default:
282       return Standard_False;
283   }
284 }