0024023: Revamp the OCCT Handle -- general
[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 #include <Graphic3d_GraphicDriver.hxx>
24
25 namespace
26 {
27 #if !defined(GL_ES_VERSION_2_0)
28   static const GLint THE_FILLPRIM_FROM = GL_TRIANGLES;
29   static const GLint THE_FILLPRIM_TO   = GL_POLYGON;
30 #else
31   static const GLint THE_FILLPRIM_FROM = GL_TRIANGLES;
32   static const GLint THE_FILLPRIM_TO   = GL_TRIANGLE_FAN;
33 #endif
34 }
35
36 // =======================================================================
37 // function : RenderCapping
38 // purpose  :
39 // =======================================================================
40 void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)&  theWorkspace,
41                                         const Graphic3d_SequenceOfGroup& theGroups)
42 {
43   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
44
45   // check whether algorithm need to be performed
46   Standard_Boolean isCapping = Standard_False;
47   const Graphic3d_SequenceOfHClipPlane& aContextPlanes = aContext->Clipping().Planes();
48   Graphic3d_SequenceOfHClipPlane::Iterator aCappingIt (aContextPlanes);
49   for (; aCappingIt.More(); aCappingIt.Next())
50   {
51     const Handle(Graphic3d_ClipPlane)& aPlane = aCappingIt.Value();
52     if (aPlane->IsCapping())
53     {
54       isCapping = Standard_True;
55       break;
56     }
57   }
58
59   // do not perform algorithm is there is nothing to render
60   if (!isCapping)
61   {
62     return;
63   }
64
65   // remember current aspect face defined in workspace
66   const OpenGl_AspectFace* aFaceAsp = theWorkspace->AspectFace (Standard_False);
67
68   // replace primitive groups rendering filter
69   Handle(OpenGl_RenderFilter) aRenderFilter = theWorkspace->GetRenderFilter();
70   theWorkspace->SetRenderFilter (theWorkspace->DefaultCappingAlgoFilter());
71
72   // prepare for rendering the clip planes
73   glEnable (GL_STENCIL_TEST);
74
75   // remember current state of depth
76   // function and change its value
77   GLint aDepthFuncPrev;
78   glGetIntegerv (GL_DEPTH_FUNC, &aDepthFuncPrev);
79   glDepthFunc (GL_LESS);
80
81   // generate capping for every clip plane
82   for (aCappingIt.Init (aContextPlanes); aCappingIt.More(); aCappingIt.Next())
83   {
84     // get plane being rendered
85     const Handle(Graphic3d_ClipPlane)& aRenderPlane = aCappingIt.Value();
86     if (!aRenderPlane->IsCapping())
87     {
88       continue;
89     }
90
91     // enable only the rendering plane to generate stencil mask
92     Graphic3d_SequenceOfHClipPlane::Iterator aPlaneIt (aContextPlanes);
93     for (; aPlaneIt.More(); aPlaneIt.Next())
94     {
95       const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
96       const Standard_Boolean isOn = (aPlane == aRenderPlane);
97       aContext->ChangeClipping().SetEnabled (aPlane, isOn);
98     }
99
100     glClear (GL_STENCIL_BUFFER_BIT);
101     glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
102
103     // override aspects, disable culling
104     theWorkspace->SetAspectFace (&theWorkspace->NoneCulling());
105     theWorkspace->AspectFace (Standard_True);
106
107     // evaluate number of pair faces
108     glDisable (GL_DEPTH_TEST);
109     glDepthMask (GL_FALSE);
110     glStencilFunc (GL_ALWAYS, 1, 0x01);
111     glStencilOp (GL_KEEP, GL_INVERT, GL_INVERT);
112
113     for (OpenGl_Structure::GroupIterator aGroupIt (theGroups); aGroupIt.More(); aGroupIt.Next())
114     {
115       if (aGroupIt.Value()->IsClosed())
116       {
117         aGroupIt.Value()->Render (theWorkspace);
118       }
119     }
120
121     // override material, cull back faces
122     theWorkspace->SetAspectFace (&theWorkspace->FrontCulling());
123     theWorkspace->AspectFace (Standard_True);
124
125     // enable all clip plane except the rendered one
126     for (aPlaneIt.Init (aContextPlanes); aPlaneIt.More(); aPlaneIt.Next())
127     {
128       const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
129       const Standard_Boolean isOn = (aPlane != aRenderPlane);
130       aContext->ChangeClipping().SetEnabled (aPlane, isOn);
131     }
132
133     // render capping plane using the generated stencil mask
134     glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
135     glDepthMask (GL_TRUE);
136     glStencilFunc (GL_EQUAL, 1, 0x01);
137     glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
138     glEnable (GL_DEPTH_TEST);
139
140     RenderPlane (theWorkspace, aRenderPlane);
141   }
142
143   // restore previous application state
144   glClear (GL_STENCIL_BUFFER_BIT);
145   glDepthFunc (aDepthFuncPrev);
146   glStencilFunc (GL_ALWAYS, 0, 0xFF);
147   glDisable (GL_STENCIL_TEST);
148
149   // enable clipping
150   for (aCappingIt.Init (aContextPlanes); aCappingIt.More(); aCappingIt.Next())
151   {
152     aContext->ChangeClipping().SetEnabled (aCappingIt.Value(), Standard_True);
153   }
154
155   // restore rendering aspects
156   theWorkspace->SetAspectFace (aFaceAsp);
157   theWorkspace->SetRenderFilter (aRenderFilter);
158 }
159
160 // =======================================================================
161 // function : RenderPlane
162 // purpose  :
163 // =======================================================================
164 void OpenGl_CappingAlgo::RenderPlane (const Handle(OpenGl_Workspace)& theWorkspace,
165                                       const Handle(Graphic3d_ClipPlane)& thePlane)
166 {
167   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
168
169   // get resource for the plane
170   TCollection_AsciiString aResId = thePlane->GetId();
171
172   Handle(OpenGl_CappingPlaneResource) aPlaneRes;
173   if (!aContext->GetResource (aResId, aPlaneRes))
174   {
175     // share and register for release once the resource is no longer used
176     aPlaneRes = new OpenGl_CappingPlaneResource (thePlane);
177     aContext->ShareResource (aResId, aPlaneRes);
178   }
179
180   aPlaneRes->Update (aContext);
181
182   const OpenGl_AspectFace* aFaceAspect = theWorkspace->AspectFace (Standard_False);
183   const OpenGl_AspectFace* aPlaneAspect = aPlaneRes->AspectFace();
184   if (aPlaneAspect != NULL)
185   {
186     theWorkspace->SetAspectFace (aPlaneAspect);
187   }
188
189   // set identity model matrix
190   aContext->ModelWorldState.Push();
191   aContext->ModelWorldState.SetCurrent (OpenGl_Mat4::Map (*aPlaneRes->Orientation()->mat));
192   aContext->ApplyModelViewMatrix();
193
194   aPlaneRes->Primitives().Render (theWorkspace);
195
196   aContext->ModelWorldState.Pop();
197   aContext->ApplyModelViewMatrix();
198
199   theWorkspace->SetAspectFace (aFaceAspect);
200
201   // set delayed resource release
202   aPlaneRes.Nullify();
203   aContext->ReleaseResource (aResId, Standard_True);
204 }
205
206 // =======================================================================
207 // function : CanRender
208 // purpose  :
209 // =======================================================================
210 Standard_Boolean OpenGl_CappingAlgoFilter::CanRender (const OpenGl_Element* theElement)
211 {
212   const OpenGl_PrimitiveArray* aPArray = dynamic_cast<const OpenGl_PrimitiveArray*> (theElement);
213   return aPArray != NULL
214       && aPArray->DrawMode() >= THE_FILLPRIM_FROM
215       && aPArray->DrawMode() <= THE_FILLPRIM_TO;
216 }