482e26743632930f0d64968586c90080173877d4
[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   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
74
75   // check whether algorithm need to be performed
76   Standard_Boolean isCapping = Standard_False;
77   const Graphic3d_SetOfHClipPlane& aContextPlanes = aContext->Clipping().Planes();
78   Graphic3d_SetOfHClipPlane::Iterator aCappingIt (aContextPlanes);
79   for (; aCappingIt.More(); aCappingIt.Next())
80   {
81     const Handle(Graphic3d_ClipPlane)& aPlane = aCappingIt.Value();
82     if (aPlane->IsCapping())
83     {
84       isCapping = Standard_True;
85       break;
86     }
87   }
88
89   // do not perform algorithm is there is nothing to render
90   if (!isCapping)
91   {
92     return;
93   }
94
95   // init internal data
96   Init();
97
98   // remember current aspect face defined in workspace
99   const OpenGl_AspectFace* aFaceAsp = theWorkspace->AspectFace (Standard_False);
100
101   // replace primitive groups rendering filter
102   static Handle(OpenGl_CappingAlgoFilter) aCappingFilter = new OpenGl_CappingAlgoFilter();
103   Handle(OpenGl_RenderFilter) aRenderFilter = theWorkspace->GetRenderFilter();
104   theWorkspace->SetRenderFilter (aCappingFilter);
105
106   // prepare for rendering the clip planes
107   glEnable (GL_STENCIL_TEST);
108
109   // generate capping for every clip plane
110   for (aCappingIt.Init (aContextPlanes); aCappingIt.More(); aCappingIt.Next())
111   {
112     // get plane being rendered
113     const Handle(Graphic3d_ClipPlane)& aRenderPlane = aCappingIt.Value();
114     if (!aRenderPlane->IsCapping())
115     {
116       continue;
117     }
118
119     // enable only the rendering plane to generate stencil mask
120     Graphic3d_SetOfHClipPlane::Iterator aPlaneIt (aContextPlanes);
121     for (; aPlaneIt.More(); aPlaneIt.Next())
122     {
123       const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
124       const Standard_Boolean isOn = (aPlane == aRenderPlane);
125       aContext->ChangeClipping().SetEnabled (aPlane, isOn);
126     }
127
128     glClear (GL_STENCIL_BUFFER_BIT);
129     glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
130
131     // override aspects, disable culling
132     theWorkspace->SetAspectFace (NoneCulling());
133     theWorkspace->AspectFace (Standard_True);
134
135     // evaluate number of pair faces
136     glDisable (GL_DEPTH_TEST);
137     glDepthMask (GL_FALSE);
138     glStencilFunc (GL_ALWAYS, 1, 0x01);
139     glStencilOp (GL_KEEP, GL_INVERT, GL_INVERT);
140
141     OpenGl_ListOfGroup::Iterator aGroupIt (theGroups);
142     for (; aGroupIt.More(); aGroupIt.Next())
143     {
144       aGroupIt.Value()->Render (theWorkspace);
145     }
146
147     // override material, cull back faces
148     theWorkspace->SetAspectFace (FrontCulling());
149     theWorkspace->AspectFace (Standard_True);
150
151     // enable all clip plane except the rendered one
152     for (aPlaneIt.Init (aContextPlanes); aPlaneIt.More(); aPlaneIt.Next())
153     {
154       const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
155       const Standard_Boolean isOn = (aPlane != aRenderPlane);
156       aContext->ChangeClipping().SetEnabled (aPlane, isOn);
157     }
158
159     // render capping plane using the generated stencil mask
160     glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
161     glDepthMask (GL_TRUE);
162     glDepthFunc (GL_LESS);
163     glStencilFunc (GL_EQUAL, 1, 0x01);
164     glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
165     glEnable (GL_DEPTH_TEST);
166
167     RenderPlane (theWorkspace, aRenderPlane);
168   }
169
170   // restore previous application state
171   glClear (GL_STENCIL_BUFFER_BIT);
172   glStencilFunc (GL_ALWAYS, 0, 0xFF);
173   glDisable (GL_STENCIL_TEST);
174
175   // enable clipping
176   for (aCappingIt.Init (aContextPlanes); aCappingIt.More(); aCappingIt.Next())
177   {
178     aContext->ChangeClipping().SetEnabled (aCappingIt.Value(), Standard_True);
179   }
180
181   // restore rendering aspects
182   theWorkspace->SetAspectFace (aFaceAsp);
183   theWorkspace->SetRenderFilter (aRenderFilter);
184 }
185
186 // =======================================================================
187 // function : RenderPlane
188 // purpose  :
189 // =======================================================================
190 void OpenGl_CappingAlgo::RenderPlane (const Handle(OpenGl_Workspace)& theWorkspace,
191                                       const Handle(Graphic3d_ClipPlane)& thePlane)
192 {
193   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
194
195   // get resource for the plane
196   TCollection_AsciiString aResId = thePlane->GetId();
197
198   Handle(OpenGl_CappingPlaneResource) aPlaneRes;
199   if (!aContext->GetResource (aResId, aPlaneRes))
200   {
201     // share and register for release once the resource is no longer used
202     aPlaneRes = new OpenGl_CappingPlaneResource (thePlane);
203     aContext->ShareResource (aResId, aPlaneRes);
204   }
205
206   aPlaneRes->Update (aContext);
207
208   const OpenGl_AspectFace* aFaceAspect = theWorkspace->AspectFace (Standard_False);
209   const OpenGl_AspectFace* aPlaneAspect = aPlaneRes->AspectFace();
210   if (aPlaneAspect != NULL)
211   {
212     theWorkspace->SetAspectFace (aPlaneAspect);
213   }
214
215   // apply aspect for rendering
216   theWorkspace->AspectFace (Standard_True);
217
218   // set identity model matrix
219   const OpenGl_Matrix* aModelMatrix = theWorkspace->SetStructureMatrix (&OpenGl_IdentityMatrix);
220
221   glMultMatrixf ((const GLfloat*)aPlaneRes->Orientation());
222   glNormal3f (0.0f, 1.0f, 0.0f);
223   glEnableClientState (GL_VERTEX_ARRAY);
224   glVertexPointer (4, GL_FLOAT, 0, (GLfloat* )&THE_CAPPING_PLN_VERTS);
225   glEnableClientState (GL_TEXTURE_COORD_ARRAY);
226   glTexCoordPointer (4, GL_FLOAT, 0, (GLfloat*)&THE_CAPPING_PLN_TCOORD);
227   glDrawArrays (GL_TRIANGLES, 0, 12);
228   glDisableClientState (GL_VERTEX_ARRAY);
229   glDisableClientState (GL_TEXTURE_COORD_ARRAY);
230
231   theWorkspace->SetStructureMatrix (aModelMatrix);
232   theWorkspace->SetAspectFace (aFaceAspect);
233
234   // set delayed resource release
235   aPlaneRes.Nullify();
236   aContext->ReleaseResource (aResId, Standard_True);
237 }
238
239 // =======================================================================
240 // function : Init
241 // purpose  :
242 // =======================================================================
243 void OpenGl_CappingAlgo::Init()
244 {
245   if (myIsInit)
246     return;
247
248   myRenderFilter = new OpenGl_CappingAlgoFilter();
249   myNoneCulling.CullingMode = TelCullNone;
250   myNoneCulling.Edge = 0;
251
252   myFrontCulling.CullingMode = TelCullBack;
253   myFrontCulling.Edge = 0;
254
255   myIsInit = Standard_True;
256 }
257
258 // =======================================================================
259 // function : CanRender
260 // purpose  :
261 // =======================================================================
262 Standard_Boolean OpenGl_CappingAlgoFilter::CanRender (const OpenGl_Element* theElement)
263 {
264   const OpenGl_PrimitiveArray* aPArray =
265     dynamic_cast<const OpenGl_PrimitiveArray*> (theElement);
266   if (!aPArray)
267     return Standard_False;
268
269   switch (aPArray->PArray()->type)
270   {
271     case TelPolygonsArrayType :
272     case TelTrianglesArrayType :
273     case TelQuadranglesArrayType :
274     case TelTriangleStripsArrayType :
275     case TelQuadrangleStripsArrayType :
276     case TelTriangleFansArrayType :
277       return Standard_True;
278
279     default:
280       return Standard_False;
281   }
282 }