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