0026940: Visualization, TKOpenGl - capping plane should be applied to connected struc...
[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 OpenGl_Structure&         theStructure)
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 (aContext, 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     // render closed primitives
114     theStructure.renderClosedGeometry (theWorkspace);
115
116     // override material, cull back faces
117     theWorkspace->SetAspectFace (&theWorkspace->FrontCulling());
118     theWorkspace->AspectFace (Standard_True);
119
120     // enable all clip plane except the rendered one
121     for (aPlaneIt.Init (aContextPlanes); aPlaneIt.More(); aPlaneIt.Next())
122     {
123       const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
124       const Standard_Boolean isOn = (aPlane != aRenderPlane);
125       aContext->ChangeClipping().SetEnabled (aContext, aPlane, isOn);
126     }
127
128     // render capping plane using the generated stencil mask
129     glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
130     glDepthMask (GL_TRUE);
131     glStencilFunc (GL_EQUAL, 1, 0x01);
132     glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
133     glEnable (GL_DEPTH_TEST);
134
135     RenderPlane (theWorkspace, aRenderPlane);
136   }
137
138   // restore previous application state
139   glClear (GL_STENCIL_BUFFER_BIT);
140   glDepthFunc (aDepthFuncPrev);
141   glStencilFunc (GL_ALWAYS, 0, 0xFF);
142   glDisable (GL_STENCIL_TEST);
143
144   // enable clipping
145   for (aCappingIt.Init (aContextPlanes); aCappingIt.More(); aCappingIt.Next())
146   {
147     aContext->ChangeClipping().SetEnabled (aContext, aCappingIt.Value(), Standard_True);
148   }
149
150   // restore rendering aspects
151   theWorkspace->SetAspectFace (aFaceAsp);
152   theWorkspace->SetRenderFilter (aRenderFilter);
153 }
154
155 // =======================================================================
156 // function : RenderPlane
157 // purpose  :
158 // =======================================================================
159 void OpenGl_CappingAlgo::RenderPlane (const Handle(OpenGl_Workspace)& theWorkspace,
160                                       const Handle(Graphic3d_ClipPlane)& thePlane)
161 {
162   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
163
164   // get resource for the plane
165   TCollection_AsciiString aResId = thePlane->GetId();
166
167   Handle(OpenGl_CappingPlaneResource) aPlaneRes;
168   if (!aContext->GetResource (aResId, aPlaneRes))
169   {
170     // share and register for release once the resource is no longer used
171     aPlaneRes = new OpenGl_CappingPlaneResource (thePlane);
172     aContext->ShareResource (aResId, aPlaneRes);
173   }
174
175   aPlaneRes->Update (aContext);
176
177   const OpenGl_AspectFace* aFaceAspect = theWorkspace->AspectFace (Standard_False);
178   const OpenGl_AspectFace* aPlaneAspect = aPlaneRes->AspectFace();
179   if (aPlaneAspect != NULL)
180   {
181     theWorkspace->SetAspectFace (aPlaneAspect);
182   }
183
184   // set identity model matrix
185   aContext->ModelWorldState.Push();
186   aContext->ModelWorldState.SetCurrent (OpenGl_Mat4::Map (*aPlaneRes->Orientation()->mat));
187   aContext->ApplyModelViewMatrix();
188
189   aPlaneRes->Primitives().Render (theWorkspace);
190
191   aContext->ModelWorldState.Pop();
192   aContext->ApplyModelViewMatrix();
193
194   theWorkspace->SetAspectFace (aFaceAspect);
195
196   // set delayed resource release
197   aPlaneRes.Nullify();
198   aContext->ReleaseResource (aResId, Standard_True);
199 }
200
201 // =======================================================================
202 // function : CanRender
203 // purpose  :
204 // =======================================================================
205 Standard_Boolean OpenGl_CappingAlgoFilter::CanRender (const OpenGl_Element* theElement)
206 {
207   const OpenGl_PrimitiveArray* aPArray = dynamic_cast<const OpenGl_PrimitiveArray*> (theElement);
208   return aPArray != NULL
209       && aPArray->DrawMode() >= THE_FILLPRIM_FROM
210       && aPArray->DrawMode() <= THE_FILLPRIM_TO;
211 }