0032289: Visualization - add NCollection_Mat3 for 3x3 matrix similar to NCollection_Mat4
[occt.git] / src / OpenGl / OpenGl_CappingAlgo.cxx
CommitLineData
4269bd1b 1// Created on: 2013-09-05
2// Created by: Anton POLETAEV
d5f74e42 3// Copyright (c) 2013-2014 OPEN CASCADE SAS
4269bd1b 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
4269bd1b 6//
d5f74e42 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
973c2be1 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.
4269bd1b 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
4269bd1b 15
16#include <OpenGl_CappingAlgo.hxx>
deb02f86 17
25c35042 18#include <OpenGl_ClippingIterator.hxx>
4269bd1b 19#include <OpenGl_Workspace.hxx>
20#include <OpenGl_Context.hxx>
21#include <OpenGl_PrimitiveArray.hxx>
22#include <OpenGl_CappingPlaneResource.hxx>
23#include <OpenGl_Vec.hxx>
b64d84be 24#include <OpenGl_Structure.hxx>
deb02f86 25#include <OpenGl_ShaderManager.hxx>
4269bd1b 26
4269bd1b 27namespace
28{
1b661a81 29 //! Auxiliary sentry object managing stencil test.
30 struct StencilTestSentry
31 {
32 StencilTestSentry() : myDepthFuncPrev (0) {}
33
34 //! Restore previous application state.
35 ~StencilTestSentry()
36 {
37 if (myDepthFuncPrev != 0)
38 {
39 glClear (GL_STENCIL_BUFFER_BIT);
40 glDepthFunc (myDepthFuncPrev);
41 glStencilFunc (GL_ALWAYS, 0, 0xFF);
42 glDisable (GL_STENCIL_TEST);
43 }
44 }
45
46 //! Prepare for rendering the clip planes.
47 void Init()
48 {
49 if (myDepthFuncPrev == 0)
50 {
51 glEnable (GL_STENCIL_TEST);
52 glGetIntegerv (GL_DEPTH_FUNC, &myDepthFuncPrev);
53 glDepthFunc (GL_LESS);
54 }
55 }
56
57 private:
58 GLint myDepthFuncPrev;
59 };
60
3e05329c 61 //! Render infinite capping plane.
62 //! @param theWorkspace [in] the GL workspace, context state.
63 //! @param thePlane [in] the graphical plane, for which the capping surface is rendered.
64 static void renderPlane (const Handle(OpenGl_Workspace)& theWorkspace,
1b661a81 65 const Handle(OpenGl_CappingPlaneResource)& thePlane)
3e05329c 66 {
67 const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
1b661a81 68 const bool wasCullAllowed = theWorkspace->SetAllowFaceCulling (true);
3e05329c 69
70 // set identity model matrix
71 aContext->ModelWorldState.Push();
a2af24d1 72 aContext->ModelWorldState.SetCurrent (thePlane->Orientation());
3e05329c 73 aContext->ApplyModelViewMatrix();
74
75 thePlane->Primitives().Render (theWorkspace);
76
77 aContext->ModelWorldState.Pop();
78 aContext->ApplyModelViewMatrix();
79
25c35042 80 theWorkspace->SetAllowFaceCulling (wasCullAllowed);
3e05329c 81 }
82
83 //! Render capping for specific structure.
1b661a81 84 static void renderCappingForStructure (StencilTestSentry& theStencilSentry,
85 const Handle(OpenGl_Workspace)& theWorkspace,
3e05329c 86 const OpenGl_Structure& theStructure,
25c35042 87 const Handle(Graphic3d_ClipPlane)& theClipChain,
88 const Standard_Integer theSubPlaneIndex,
3e05329c 89 const Handle(OpenGl_CappingPlaneResource)& thePlane)
90 {
1b661a81 91 const Standard_Integer aPrevFilter = theWorkspace->RenderFilter();
92 const Standard_Integer anAnyFilter = aPrevFilter & ~(Standard_Integer )(OpenGl_RenderFilter_OpaqueOnly | OpenGl_RenderFilter_TransparentOnly);
93
3202bf1e 94 const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
95 const Handle(Graphic3d_ClipPlane)& aRenderPlane = thePlane->Plane();
3e05329c 96 for (OpenGl_Structure::GroupIterator aGroupIter (theStructure.Groups()); aGroupIter.More(); aGroupIter.Next())
97 {
98 if (!aGroupIter.Value()->IsClosed())
99 {
100 continue;
101 }
102
1b661a81 103 // clear stencil only if something has been actually drawn
104 theStencilSentry.Init();
105
106 // check if capping plane should be rendered within current pass (only opaque / only transparent)
bf5f0ca2 107 const OpenGl_Aspects* anObjAspectFace = aRenderPlane->ToUseObjectProperties() ? aGroupIter.Value()->GlAspects() : NULL;
108 thePlane->Update (aContext, anObjAspectFace != NULL ? anObjAspectFace->Aspect() : Handle(Graphic3d_Aspects)());
109 theWorkspace->SetAspects (thePlane->AspectFace());
1b661a81 110 theWorkspace->SetRenderFilter (aPrevFilter);
4552cb85 111 if (!theWorkspace->ShouldRender (&thePlane->Primitives(), aGroupIter.Value()))
1b661a81 112 {
113 continue;
114 }
115
116 // suppress only opaque/transparent filter since for filling stencil the whole geometry should be drawn
117 theWorkspace->SetRenderFilter (anAnyFilter);
118
3e05329c 119 // enable only the rendering plane to generate stencil mask
25c35042 120 aContext->ChangeClipping().DisableAllExcept (theClipChain, theSubPlaneIndex);
3e05329c 121 aContext->ShaderManager()->UpdateClippingState();
122
123 glClear (GL_STENCIL_BUFFER_BIT);
f88457e6 124 const bool aColorMaskBack = aContext->SetColorMask (false);
3e05329c 125
126 // override aspects, disable culling
bf5f0ca2 127 theWorkspace->SetAspects (&theWorkspace->NoneCulling());
128 theWorkspace->ApplyAspects();
3e05329c 129
130 // evaluate number of pair faces
a1073ae2 131 if (theWorkspace->UseZBuffer())
132 {
133 glDisable (GL_DEPTH_TEST);
134 }
135 if (theWorkspace->UseDepthWrite())
136 {
137 glDepthMask (GL_FALSE);
138 }
3e05329c 139 glStencilFunc (GL_ALWAYS, 1, 0x01);
140 glStencilOp (GL_KEEP, GL_INVERT, GL_INVERT);
141
142 // render closed primitives
143 if (aRenderPlane->ToUseObjectProperties())
144 {
145 aGroupIter.Value()->Render (theWorkspace);
146 }
147 else
148 {
149 for (; aGroupIter.More(); aGroupIter.Next())
150 {
151 if (aGroupIter.Value()->IsClosed())
152 {
153 aGroupIter.Value()->Render (theWorkspace);
154 }
155 }
156 }
157
158 // override material, cull back faces
bf5f0ca2 159 theWorkspace->SetAspects (&theWorkspace->FrontCulling());
160 theWorkspace->ApplyAspects();
3e05329c 161
162 // enable all clip plane except the rendered one
25c35042 163 aContext->ChangeClipping().EnableAllExcept (theClipChain, theSubPlaneIndex);
3e05329c 164 aContext->ShaderManager()->UpdateClippingState();
165
166 // render capping plane using the generated stencil mask
f88457e6 167 aContext->SetColorMask (aColorMaskBack);
a1073ae2 168 if (theWorkspace->UseDepthWrite())
169 {
170 glDepthMask (GL_TRUE);
171 }
3e05329c 172 glStencilFunc (GL_EQUAL, 1, 0x01);
173 glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
a1073ae2 174 if (theWorkspace->UseZBuffer())
175 {
176 glEnable (GL_DEPTH_TEST);
177 }
3e05329c 178
bf5f0ca2 179 theWorkspace->SetAspects (thePlane->AspectFace());
1b661a81 180 renderPlane (theWorkspace, thePlane);
3e05329c 181
3202bf1e 182 // turn on the current plane to restore initial state
25c35042 183 aContext->ChangeClipping().ResetCappingFilter();
3e05329c 184 aContext->ShaderManager()->RevertClippingState();
185 aContext->ShaderManager()->RevertClippingState();
186 }
187
188 if (theStructure.InstancedStructure() != NULL)
189 {
1b661a81 190 renderCappingForStructure (theStencilSentry, theWorkspace, *theStructure.InstancedStructure(), theClipChain, theSubPlaneIndex, thePlane);
3e05329c 191 }
192 }
ca3c13d1 193}
4269bd1b 194
195// =======================================================================
196// function : RenderCapping
197// purpose :
198// =======================================================================
cc6852f3 199void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorkspace,
200 const OpenGl_Structure& theStructure)
4269bd1b 201{
4269bd1b 202 const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
3202bf1e 203 if (!aContext->Clipping().IsCappingOn())
b859a34d 204 {
3202bf1e 205 // do not perform algorithm if there is nothing to render
4269bd1b 206 return;
b859a34d 207 }
4269bd1b 208
4269bd1b 209 // remember current aspect face defined in workspace
bf5f0ca2 210 const OpenGl_Aspects* aFaceAsp = theWorkspace->Aspects();
4269bd1b 211
1b661a81 212 // only filled primitives should be rendered
213 const Standard_Integer aPrevFilter = theWorkspace->RenderFilter();
214 theWorkspace->SetRenderFilter (aPrevFilter | OpenGl_RenderFilter_FillModeOnly);
215 StencilTestSentry aStencilSentry;
347423b2 216
4269bd1b 217 // generate capping for every clip plane
3202bf1e 218 for (OpenGl_ClippingIterator aCappingIt (aContext->Clipping()); aCappingIt.More(); aCappingIt.Next())
4269bd1b 219 {
220 // get plane being rendered
25c35042 221 const Handle(Graphic3d_ClipPlane)& aClipChain = aCappingIt.Value();
222 if (!aClipChain->IsCapping()
3202bf1e 223 || aCappingIt.IsDisabled())
4269bd1b 224 {
225 continue;
226 }
227
25c35042 228 Standard_Integer aSubPlaneIndex = 1;
229 for (const Graphic3d_ClipPlane* aSubPlaneIter = aClipChain.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get(), ++aSubPlaneIndex)
4269bd1b 230 {
25c35042 231 // get resource for the plane
232 const TCollection_AsciiString& aResId = aSubPlaneIter->GetId();
233 Handle(OpenGl_CappingPlaneResource) aPlaneRes;
234 if (!aContext->GetResource (aResId, aPlaneRes))
235 {
236 // share and register for release once the resource is no longer used
237 aPlaneRes = new OpenGl_CappingPlaneResource (aSubPlaneIter);
238 aContext->ShareResource (aResId, aPlaneRes);
239 }
4269bd1b 240
1b661a81 241 renderCappingForStructure (aStencilSentry, theWorkspace, theStructure, aClipChain, aSubPlaneIndex, aPlaneRes);
4269bd1b 242
25c35042 243 // set delayed resource release
244 aPlaneRes.Nullify();
245 aContext->ReleaseResource (aResId, Standard_True);
246 }
4269bd1b 247 }
248
4269bd1b 249 // restore rendering aspects
bf5f0ca2 250 theWorkspace->SetAspects (aFaceAsp);
1b661a81 251 theWorkspace->SetRenderFilter (aPrevFilter);
4269bd1b 252}