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