// commercial license or contractual agreement.
#include <OpenGl_CappingAlgo.hxx>
+
+#include <OpenGl_ClippingIterator.hxx>
#include <OpenGl_Workspace.hxx>
#include <OpenGl_Context.hxx>
#include <OpenGl_PrimitiveArray.hxx>
#include <OpenGl_CappingPlaneResource.hxx>
#include <OpenGl_Vec.hxx>
#include <OpenGl_Structure.hxx>
-#include <Graphic3d_GraphicDriver.hxx>
-
-IMPLEMENT_STANDARD_RTTIEXT(OpenGl_CappingAlgoFilter,OpenGl_RenderFilter)
+#include <OpenGl_ShaderManager.hxx>
namespace
{
-#if !defined(GL_ES_VERSION_2_0)
- static const GLint THE_FILLPRIM_FROM = GL_TRIANGLES;
- static const GLint THE_FILLPRIM_TO = GL_POLYGON;
-#else
- static const GLint THE_FILLPRIM_FROM = GL_TRIANGLES;
- static const GLint THE_FILLPRIM_TO = GL_TRIANGLE_FAN;
-#endif
-}
+ //! Auxiliary sentry object managing stencil test.
+ struct StencilTestSentry
+ {
+ StencilTestSentry() : myDepthFuncPrev (0) {}
-// =======================================================================
-// function : RenderCapping
-// purpose :
-// =======================================================================
-void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorkspace,
- const OpenGl_Structure& theStructure)
-{
- const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
+ //! Restore previous application state.
+ ~StencilTestSentry()
+ {
+ if (myDepthFuncPrev != 0)
+ {
+ glClear (GL_STENCIL_BUFFER_BIT);
+ glDepthFunc (myDepthFuncPrev);
+ glStencilFunc (GL_ALWAYS, 0, 0xFF);
+ glDisable (GL_STENCIL_TEST);
+ }
+ }
- // check whether algorithm need to be performed
- Standard_Boolean isCapping = Standard_False;
- const Graphic3d_SequenceOfHClipPlane& aContextPlanes = aContext->Clipping().Planes();
- Graphic3d_SequenceOfHClipPlane::Iterator aCappingIt (aContextPlanes);
- for (; aCappingIt.More(); aCappingIt.Next())
- {
- const Handle(Graphic3d_ClipPlane)& aPlane = aCappingIt.Value();
- if (aPlane->IsCapping())
+ //! Prepare for rendering the clip planes.
+ void Init()
{
- isCapping = Standard_True;
- break;
+ if (myDepthFuncPrev == 0)
+ {
+ glEnable (GL_STENCIL_TEST);
+ glGetIntegerv (GL_DEPTH_FUNC, &myDepthFuncPrev);
+ glDepthFunc (GL_LESS);
+ }
}
- }
- // do not perform algorithm is there is nothing to render
- if (!isCapping)
+ private:
+ GLint myDepthFuncPrev;
+ };
+
+ //! Render infinite capping plane.
+ //! @param theWorkspace [in] the GL workspace, context state.
+ //! @param thePlane [in] the graphical plane, for which the capping surface is rendered.
+ static void renderPlane (const Handle(OpenGl_Workspace)& theWorkspace,
+ const Handle(OpenGl_CappingPlaneResource)& thePlane)
{
- return;
- }
+ const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
+ const bool wasCullAllowed = theWorkspace->SetAllowFaceCulling (true);
- // remember current aspect face defined in workspace
- const OpenGl_AspectFace* aFaceAsp = theWorkspace->AspectFace (Standard_False);
+ // set identity model matrix
+ aContext->ModelWorldState.Push();
+ aContext->ModelWorldState.SetCurrent (OpenGl_Mat4::Map (*thePlane->Orientation()->mat));
+ aContext->ApplyModelViewMatrix();
- // replace primitive groups rendering filter
- Handle(OpenGl_RenderFilter) aRenderFilter = theWorkspace->GetRenderFilter();
- theWorkspace->SetRenderFilter (theWorkspace->DefaultCappingAlgoFilter());
+ thePlane->Primitives().Render (theWorkspace);
- // prepare for rendering the clip planes
- glEnable (GL_STENCIL_TEST);
+ aContext->ModelWorldState.Pop();
+ aContext->ApplyModelViewMatrix();
- // remember current state of depth
- // function and change its value
- GLint aDepthFuncPrev;
- glGetIntegerv (GL_DEPTH_FUNC, &aDepthFuncPrev);
- glDepthFunc (GL_LESS);
+ theWorkspace->SetAllowFaceCulling (wasCullAllowed);
+ }
- // generate capping for every clip plane
- for (aCappingIt.Init (aContextPlanes); aCappingIt.More(); aCappingIt.Next())
+ //! Render capping for specific structure.
+ static void renderCappingForStructure (StencilTestSentry& theStencilSentry,
+ const Handle(OpenGl_Workspace)& theWorkspace,
+ const OpenGl_Structure& theStructure,
+ const Handle(Graphic3d_ClipPlane)& theClipChain,
+ const Standard_Integer theSubPlaneIndex,
+ const Handle(OpenGl_CappingPlaneResource)& thePlane)
{
- // get plane being rendered
- const Handle(Graphic3d_ClipPlane)& aRenderPlane = aCappingIt.Value();
- if (!aRenderPlane->IsCapping())
- {
- continue;
- }
+ const Standard_Integer aPrevFilter = theWorkspace->RenderFilter();
+ const Standard_Integer anAnyFilter = aPrevFilter & ~(Standard_Integer )(OpenGl_RenderFilter_OpaqueOnly | OpenGl_RenderFilter_TransparentOnly);
- // enable only the rendering plane to generate stencil mask
- Graphic3d_SequenceOfHClipPlane::Iterator aPlaneIt (aContextPlanes);
- for (; aPlaneIt.More(); aPlaneIt.Next())
+ const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
+ const Handle(Graphic3d_ClipPlane)& aRenderPlane = thePlane->Plane();
+ for (OpenGl_Structure::GroupIterator aGroupIter (theStructure.Groups()); aGroupIter.More(); aGroupIter.Next())
{
- const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
- const Standard_Boolean isOn = (aPlane == aRenderPlane);
- aContext->ChangeClipping().SetEnabled (aContext, aPlane, isOn);
+ if (!aGroupIter.Value()->IsClosed())
+ {
+ continue;
+ }
+
+ // clear stencil only if something has been actually drawn
+ theStencilSentry.Init();
+
+ // check if capping plane should be rendered within current pass (only opaque / only transparent)
+ const OpenGl_Aspects* anObjAspectFace = aRenderPlane->ToUseObjectProperties() ? aGroupIter.Value()->GlAspects() : NULL;
+ thePlane->Update (aContext, anObjAspectFace != NULL ? anObjAspectFace->Aspect() : Handle(Graphic3d_Aspects)());
+ theWorkspace->SetAspects (thePlane->AspectFace());
+ theWorkspace->SetRenderFilter (aPrevFilter);
+ if (!theWorkspace->ShouldRender (&thePlane->Primitives()))
+ {
+ continue;
+ }
+
+ // suppress only opaque/transparent filter since for filling stencil the whole geometry should be drawn
+ theWorkspace->SetRenderFilter (anAnyFilter);
+
+ // enable only the rendering plane to generate stencil mask
+ aContext->ChangeClipping().DisableAllExcept (theClipChain, theSubPlaneIndex);
+ aContext->ShaderManager()->UpdateClippingState();
+
+ glClear (GL_STENCIL_BUFFER_BIT);
+ const bool aColorMaskBack = aContext->SetColorMask (false);
+
+ // override aspects, disable culling
+ theWorkspace->SetAspects (&theWorkspace->NoneCulling());
+ theWorkspace->ApplyAspects();
+
+ // evaluate number of pair faces
+ if (theWorkspace->UseZBuffer())
+ {
+ glDisable (GL_DEPTH_TEST);
+ }
+ if (theWorkspace->UseDepthWrite())
+ {
+ glDepthMask (GL_FALSE);
+ }
+ glStencilFunc (GL_ALWAYS, 1, 0x01);
+ glStencilOp (GL_KEEP, GL_INVERT, GL_INVERT);
+
+ // render closed primitives
+ if (aRenderPlane->ToUseObjectProperties())
+ {
+ aGroupIter.Value()->Render (theWorkspace);
+ }
+ else
+ {
+ for (; aGroupIter.More(); aGroupIter.Next())
+ {
+ if (aGroupIter.Value()->IsClosed())
+ {
+ aGroupIter.Value()->Render (theWorkspace);
+ }
+ }
+ }
+
+ // override material, cull back faces
+ theWorkspace->SetAspects (&theWorkspace->FrontCulling());
+ theWorkspace->ApplyAspects();
+
+ // enable all clip plane except the rendered one
+ aContext->ChangeClipping().EnableAllExcept (theClipChain, theSubPlaneIndex);
+ aContext->ShaderManager()->UpdateClippingState();
+
+ // render capping plane using the generated stencil mask
+ aContext->SetColorMask (aColorMaskBack);
+ if (theWorkspace->UseDepthWrite())
+ {
+ glDepthMask (GL_TRUE);
+ }
+ glStencilFunc (GL_EQUAL, 1, 0x01);
+ glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
+ if (theWorkspace->UseZBuffer())
+ {
+ glEnable (GL_DEPTH_TEST);
+ }
+
+ theWorkspace->SetAspects (thePlane->AspectFace());
+ renderPlane (theWorkspace, thePlane);
+
+ // turn on the current plane to restore initial state
+ aContext->ChangeClipping().ResetCappingFilter();
+ aContext->ShaderManager()->RevertClippingState();
+ aContext->ShaderManager()->RevertClippingState();
}
- glClear (GL_STENCIL_BUFFER_BIT);
- glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
-
- // override aspects, disable culling
- theWorkspace->SetAspectFace (&theWorkspace->NoneCulling());
- theWorkspace->AspectFace (Standard_True);
-
- // evaluate number of pair faces
- glDisable (GL_DEPTH_TEST);
- glDepthMask (GL_FALSE);
- glStencilFunc (GL_ALWAYS, 1, 0x01);
- glStencilOp (GL_KEEP, GL_INVERT, GL_INVERT);
-
- // render closed primitives
- theStructure.renderClosedGeometry (theWorkspace);
-
- // override material, cull back faces
- theWorkspace->SetAspectFace (&theWorkspace->FrontCulling());
- theWorkspace->AspectFace (Standard_True);
-
- // enable all clip plane except the rendered one
- for (aPlaneIt.Init (aContextPlanes); aPlaneIt.More(); aPlaneIt.Next())
+ if (theStructure.InstancedStructure() != NULL)
{
- const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIt.Value();
- const Standard_Boolean isOn = (aPlane != aRenderPlane);
- aContext->ChangeClipping().SetEnabled (aContext, aPlane, isOn);
+ renderCappingForStructure (theStencilSentry, theWorkspace, *theStructure.InstancedStructure(), theClipChain, theSubPlaneIndex, thePlane);
}
-
- // render capping plane using the generated stencil mask
- glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glDepthMask (GL_TRUE);
- glStencilFunc (GL_EQUAL, 1, 0x01);
- glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
- glEnable (GL_DEPTH_TEST);
-
- RenderPlane (theWorkspace, aRenderPlane);
}
-
- // restore previous application state
- glClear (GL_STENCIL_BUFFER_BIT);
- glDepthFunc (aDepthFuncPrev);
- glStencilFunc (GL_ALWAYS, 0, 0xFF);
- glDisable (GL_STENCIL_TEST);
-
- // enable clipping
- for (aCappingIt.Init (aContextPlanes); aCappingIt.More(); aCappingIt.Next())
- {
- aContext->ChangeClipping().SetEnabled (aContext, aCappingIt.Value(), Standard_True);
- }
-
- // restore rendering aspects
- theWorkspace->SetAspectFace (aFaceAsp);
- theWorkspace->SetRenderFilter (aRenderFilter);
}
// =======================================================================
-// function : RenderPlane
+// function : RenderCapping
// purpose :
// =======================================================================
-void OpenGl_CappingAlgo::RenderPlane (const Handle(OpenGl_Workspace)& theWorkspace,
- const Handle(Graphic3d_ClipPlane)& thePlane)
+void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorkspace,
+ const OpenGl_Structure& theStructure)
{
const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
-
- // get resource for the plane
- TCollection_AsciiString aResId = thePlane->GetId();
-
- Handle(OpenGl_CappingPlaneResource) aPlaneRes;
- if (!aContext->GetResource (aResId, aPlaneRes))
- {
- // share and register for release once the resource is no longer used
- aPlaneRes = new OpenGl_CappingPlaneResource (thePlane);
- aContext->ShareResource (aResId, aPlaneRes);
- }
-
- aPlaneRes->Update (aContext);
-
- const OpenGl_AspectFace* aFaceAspect = theWorkspace->AspectFace (Standard_False);
- const OpenGl_AspectFace* aPlaneAspect = aPlaneRes->AspectFace();
- if (aPlaneAspect != NULL)
+ if (!aContext->Clipping().IsCappingOn())
{
- theWorkspace->SetAspectFace (aPlaneAspect);
+ // do not perform algorithm if there is nothing to render
+ return;
}
- // set identity model matrix
- aContext->ModelWorldState.Push();
- aContext->ModelWorldState.SetCurrent (OpenGl_Mat4::Map (*aPlaneRes->Orientation()->mat));
- aContext->ApplyModelViewMatrix();
-
- aPlaneRes->Primitives().Render (theWorkspace);
+ // remember current aspect face defined in workspace
+ const OpenGl_Aspects* aFaceAsp = theWorkspace->Aspects();
- aContext->ModelWorldState.Pop();
- aContext->ApplyModelViewMatrix();
+ // only filled primitives should be rendered
+ const Standard_Integer aPrevFilter = theWorkspace->RenderFilter();
+ theWorkspace->SetRenderFilter (aPrevFilter | OpenGl_RenderFilter_FillModeOnly);
+ StencilTestSentry aStencilSentry;
- theWorkspace->SetAspectFace (aFaceAspect);
+ // generate capping for every clip plane
+ for (OpenGl_ClippingIterator aCappingIt (aContext->Clipping()); aCappingIt.More(); aCappingIt.Next())
+ {
+ // get plane being rendered
+ const Handle(Graphic3d_ClipPlane)& aClipChain = aCappingIt.Value();
+ if (!aClipChain->IsCapping()
+ || aCappingIt.IsDisabled())
+ {
+ continue;
+ }
- // set delayed resource release
- aPlaneRes.Nullify();
- aContext->ReleaseResource (aResId, Standard_True);
-}
+ Standard_Integer aSubPlaneIndex = 1;
+ for (const Graphic3d_ClipPlane* aSubPlaneIter = aClipChain.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get(), ++aSubPlaneIndex)
+ {
+ // get resource for the plane
+ const TCollection_AsciiString& aResId = aSubPlaneIter->GetId();
+ Handle(OpenGl_CappingPlaneResource) aPlaneRes;
+ if (!aContext->GetResource (aResId, aPlaneRes))
+ {
+ // share and register for release once the resource is no longer used
+ aPlaneRes = new OpenGl_CappingPlaneResource (aSubPlaneIter);
+ aContext->ShareResource (aResId, aPlaneRes);
+ }
+
+ renderCappingForStructure (aStencilSentry, theWorkspace, theStructure, aClipChain, aSubPlaneIndex, aPlaneRes);
+
+ // set delayed resource release
+ aPlaneRes.Nullify();
+ aContext->ReleaseResource (aResId, Standard_True);
+ }
+ }
-// =======================================================================
-// function : CanRender
-// purpose :
-// =======================================================================
-Standard_Boolean OpenGl_CappingAlgoFilter::CanRender (const OpenGl_Element* theElement)
-{
- const OpenGl_PrimitiveArray* aPArray = dynamic_cast<const OpenGl_PrimitiveArray*> (theElement);
- return aPArray != NULL
- && aPArray->DrawMode() >= THE_FILLPRIM_FROM
- && aPArray->DrawMode() <= THE_FILLPRIM_TO;
+ // restore rendering aspects
+ theWorkspace->SetAspects (aFaceAsp);
+ theWorkspace->SetRenderFilter (aPrevFilter);
}