From 25c35042b6db0ee8f85df4097f448a721c2461e0 Mon Sep 17 00:00:00 2001 From: kgv Date: Fri, 25 May 2018 10:13:38 +0300 Subject: [PATCH] 0029729: Visualization, Graphic3d_ClipPlane - add support of clipping plane chains Graphic3d_ClipPlane now can define a Chain of Planes (logical AND). OpenGl_ShaderManager - added new GLSL sub-programs for clipping plane chains. Bnd_Range::TrimFrom(), ::TrimTo() - added auxiliary methods for trimming the range. SelectMgr_ViewClipRange now handles non-continuous clipping range. Graphic3d_SequenceOfHClipPlane now aggregates NCollection_Sequence instead of inheritance. OpenGl_CappingPlaneResource - triangulation has been adjusted to make front face following CCW order. --- src/Bnd/Bnd_Range.hxx | 20 ++ src/Graphic3d/FILES | 1 + src/Graphic3d/Graphic3d_ClipPlane.cxx | 60 ++++- src/Graphic3d/Graphic3d_ClipPlane.hxx | 206 ++++++++++++++++-- .../Graphic3d_SequenceOfHClipPlane.cxx | 60 +++++ .../Graphic3d_SequenceOfHClipPlane.hxx | 74 ++++++- src/OpenGl/FILES | 1 + src/OpenGl/OpenGl_CappingAlgo.cxx | 53 +++-- src/OpenGl/OpenGl_CappingPlaneResource.cxx | 24 +- src/OpenGl/OpenGl_Clipping.cxx | 138 +++++------- src/OpenGl/OpenGl_Clipping.hxx | 147 ++++++------- src/OpenGl/OpenGl_ClippingIterator.hxx | 77 +++++++ src/OpenGl/OpenGl_Context.cxx | 2 +- src/OpenGl/OpenGl_Group.cxx | 3 +- src/OpenGl/OpenGl_SetOfShaderPrograms.hxx | 8 +- src/OpenGl/OpenGl_ShaderManager.cxx | 134 +++++++++--- src/OpenGl/OpenGl_ShaderManager.hxx | 29 +++ src/OpenGl/OpenGl_ShaderProgram.cxx | 1 + src/OpenGl/OpenGl_ShaderProgram.hxx | 3 +- src/OpenGl/OpenGl_Structure.cxx | 36 +-- src/OpenGl/OpenGl_View_Redraw.cxx | 4 +- src/OpenGl/OpenGl_Workspace.cxx | 12 +- src/OpenGl/OpenGl_Workspace.hxx | 9 +- .../Select3D_SensitivePrimitiveArray.hxx | 1 + .../SelectMgr_RectangularFrustum.cxx | 114 +++++----- .../SelectMgr_RectangularFrustum.hxx | 3 +- src/SelectMgr/SelectMgr_ViewClipRange.hxx | 58 +++-- src/SelectMgr/SelectMgr_ViewerSelector.cxx | 5 +- src/Shaders/Declarations.glsl | 1 + src/Shaders/Shaders_Declarations_glsl.pxx | 1 + src/ViewerTest/ViewerTest.cxx | 9 +- src/ViewerTest/ViewerTest_ViewerCommands.cxx | 79 ++++++- tests/bugs/vis/bug25052 | 6 +- tests/v3d/glsl/clipping1 | 91 ++++++++ 34 files changed, 1063 insertions(+), 407 deletions(-) create mode 100644 src/Graphic3d/Graphic3d_SequenceOfHClipPlane.cxx create mode 100644 src/OpenGl/OpenGl_ClippingIterator.hxx create mode 100644 tests/v3d/glsl/clipping1 diff --git a/src/Bnd/Bnd_Range.hxx b/src/Bnd/Bnd_Range.hxx index 53fcee6c96..88738245cb 100644 --- a/src/Bnd/Bnd_Range.hxx +++ b/src/Bnd/Bnd_Range.hxx @@ -193,6 +193,26 @@ public: } } + //! Trims the First value in range by the given lower limit. + //! Marks range as Void if the given Lower value is greater than range Max. + void TrimFrom (const Standard_Real theValLower) + { + if (!IsVoid()) + { + myFirst = Max (myFirst, theValLower); + } + } + + //! Trim the Last value in range by the given Upper limit. + //! Marks range as Void if the given Upper value is smaller than range Max. + void TrimTo (const Standard_Real theValUpper) + { + if (!IsVoid()) + { + myLast = Min (myLast, theValUpper); + } + } + //! Returns True if the value is out of this range. Standard_Boolean IsOut (Standard_Real theValue) const { diff --git a/src/Graphic3d/FILES b/src/Graphic3d/FILES index 6432321f82..2c15a0d70f 100755 --- a/src/Graphic3d/FILES +++ b/src/Graphic3d/FILES @@ -83,6 +83,7 @@ Graphic3d_RenderingMode.hxx Graphic3d_RenderingParams.hxx Graphic3d_RenderTransparentMethod.hxx Graphic3d_SequenceOfGroup.hxx +Graphic3d_SequenceOfHClipPlane.cxx Graphic3d_SequenceOfHClipPlane.hxx Graphic3d_SequenceOfStructure.hxx Graphic3d_ShaderAttribute.cxx diff --git a/src/Graphic3d/Graphic3d_ClipPlane.cxx b/src/Graphic3d/Graphic3d_ClipPlane.cxx index 1524c946fa..22ac56c4b6 100755 --- a/src/Graphic3d/Graphic3d_ClipPlane.cxx +++ b/src/Graphic3d/Graphic3d_ClipPlane.cxx @@ -45,8 +45,11 @@ namespace // ======================================================================= Graphic3d_ClipPlane::Graphic3d_ClipPlane() : myAspect (defaultAspect()), + myPrevInChain(NULL), myPlane (0.0, 0.0, 1.0, 0.0), myEquation (0.0, 0.0, 1.0, 0.0), + myEquationRev(0.0, 0.0,-1.0, 0.0), + myChainLenFwd(1), myFlags (Graphic3d_CappingFlags_None), myEquationMod(0), myAspectMod (0), @@ -60,10 +63,13 @@ Graphic3d_ClipPlane::Graphic3d_ClipPlane() // function : Graphic3d_ClipPlane // purpose : // ======================================================================= -Graphic3d_ClipPlane::Graphic3d_ClipPlane(const Equation& theEquation) +Graphic3d_ClipPlane::Graphic3d_ClipPlane (const Graphic3d_Vec4d& theEquation) : myAspect (defaultAspect()), + myPrevInChain(NULL), myPlane (theEquation.x(), theEquation.y(), theEquation.z(), theEquation.w()), myEquation (theEquation), + myEquationRev(0.0, 0.0,-1.0, 0.0), + myChainLenFwd(1), myFlags (Graphic3d_CappingFlags_None), myEquationMod(0), myAspectMod (0), @@ -71,6 +77,7 @@ Graphic3d_ClipPlane::Graphic3d_ClipPlane(const Equation& theEquation) myIsCapping (Standard_False) { makeId(); + updateInversedPlane(); } // ======================================================================= @@ -80,8 +87,11 @@ Graphic3d_ClipPlane::Graphic3d_ClipPlane(const Equation& theEquation) Graphic3d_ClipPlane::Graphic3d_ClipPlane(const Graphic3d_ClipPlane& theOther) : Standard_Transient(theOther), myAspect (defaultAspect()), + myPrevInChain(NULL), myPlane (theOther.myPlane), myEquation (theOther.myEquation), + myEquationRev(theOther.myEquationRev), + myChainLenFwd(1), myFlags (theOther.myFlags), myEquationMod(0), myAspectMod (0), @@ -98,7 +108,9 @@ Graphic3d_ClipPlane::Graphic3d_ClipPlane(const Graphic3d_ClipPlane& theOther) // ======================================================================= Graphic3d_ClipPlane::Graphic3d_ClipPlane(const gp_Pln& thePlane) : myAspect (defaultAspect()), + myPrevInChain(NULL), myPlane (thePlane), + myChainLenFwd(1), myFlags (Graphic3d_CappingFlags_None), myEquationMod(0), myAspectMod (0), @@ -106,6 +118,7 @@ Graphic3d_ClipPlane::Graphic3d_ClipPlane(const gp_Pln& thePlane) myIsCapping (Standard_False) { thePlane.Coefficients (myEquation[0], myEquation[1], myEquation[2], myEquation[3]); + updateInversedPlane(); makeId(); } @@ -113,10 +126,11 @@ Graphic3d_ClipPlane::Graphic3d_ClipPlane(const gp_Pln& thePlane) // function : SetEquation // purpose : // ======================================================================= -void Graphic3d_ClipPlane::SetEquation (const Equation& theEquation) +void Graphic3d_ClipPlane::SetEquation (const Graphic3d_Vec4d& theEquation) { myPlane = gp_Pln (theEquation.x(), theEquation.y(), theEquation.z(), theEquation.w()); myEquation = theEquation; + updateInversedPlane(); myEquationMod++; } @@ -127,10 +141,8 @@ void Graphic3d_ClipPlane::SetEquation (const Equation& theEquation) void Graphic3d_ClipPlane::SetEquation (const gp_Pln& thePlane) { myPlane = thePlane; - thePlane.Coefficients (myEquation[0], - myEquation[1], - myEquation[2], - myEquation[3]); + thePlane.Coefficients (myEquation[0], myEquation[1], myEquation[2], myEquation[3]); + updateInversedPlane(); myEquationMod++; } @@ -140,6 +152,10 @@ void Graphic3d_ClipPlane::SetEquation (const gp_Pln& thePlane) // ======================================================================= void Graphic3d_ClipPlane::SetOn (const Standard_Boolean theIsOn) { + if (myPrevInChain != NULL) + { + throw Standard_ProgramError ("Graphic3d_ClipPlane::SetOn() - undefined operation for a plane in Union"); + } myIsOn = theIsOn; } @@ -276,3 +292,35 @@ void Graphic3d_ClipPlane::makeId() myId = TCollection_AsciiString ("Graphic3d_ClipPlane_") //DynamicType()->Name() + TCollection_AsciiString (Standard_Atomic_Increment (&THE_CLIP_PLANE_COUNTER)); } + +// ======================================================================= +// function : updateChainLen +// purpose : +// ======================================================================= +void Graphic3d_ClipPlane::updateChainLen() +{ + myChainLenFwd = !myNextInChain.IsNull() ? (myNextInChain->myChainLenFwd + 1) : 1; + if (myPrevInChain != NULL) + { + myPrevInChain->updateChainLen(); + } +} + +// ======================================================================= +// function : SetChainNextPlane +// purpose : +// ======================================================================= +void Graphic3d_ClipPlane::SetChainNextPlane (const Handle(Graphic3d_ClipPlane)& thePlane) +{ + ++myEquationMod; + if (!myNextInChain.IsNull()) + { + myNextInChain->myPrevInChain = NULL; + } + myNextInChain = thePlane; + if (!myNextInChain.IsNull()) + { + myNextInChain->myPrevInChain = this; + } + updateChainLen(); +} diff --git a/src/Graphic3d/Graphic3d_ClipPlane.hxx b/src/Graphic3d/Graphic3d_ClipPlane.hxx index 11058e3599..388ae39b4d 100755 --- a/src/Graphic3d/Graphic3d_ClipPlane.hxx +++ b/src/Graphic3d/Graphic3d_ClipPlane.hxx @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -26,24 +27,26 @@ #include #include -//! Container for properties describing graphic driver clipping planes. -//! It is up to application to create instances of this class and specify its -//! properties. The instances are passed into graphic driver or other facilities -//! that implement clipping features (e.g. selection). -//! Depending on usage context the class can be used to specify: -//! - Global clipping applied over the whole scene. -//! - Object-level clipping applied for each particular object. +//! Clipping state. +enum Graphic3d_ClipState +{ + Graphic3d_ClipState_Out, //!< fully outside (clipped) - should be discarded + Graphic3d_ClipState_In, //!< fully inside (NOT clipped) - should NOT be discarded + Graphic3d_ClipState_On, //!< on (not clipped / partially clipped) - should NOT be discarded +}; + +//! Container for properties describing either a Clipping halfspace (single Clipping Plane), +//! or a chain of Clipping Planes defining logical AND (conjunction) operation. //! The plane equation is specified in "world" coordinate system. -//! Please note that the set of planes can define convex clipping volume. -//! Be aware that number of clip planes supported by OpenGl is implementation -//! dependent: at least 6 planes are available. Thus, take into account -//! number of clipping planes passed for rendering: the object planes plus -//! the view defined ones. class Graphic3d_ClipPlane : public Standard_Transient { + DEFINE_STANDARD_RTTIEXT(Graphic3d_ClipPlane,Standard_Transient) public: - typedef NCollection_Vec4 Equation; + //! Type defining XYZW (ABCD) plane equation - left for compatibility with old code using Graphic3d_ClipPlane::Equation type. + typedef Graphic3d_Vec4d Equation; + +public: //! Default constructor. //! Initializes clip plane container with the following properties: @@ -63,7 +66,7 @@ public: //! Construct clip plane for the passed equation. //! By default the plane is on, capping is turned off. //! @param theEquation [in] the plane equation. - Standard_EXPORT Graphic3d_ClipPlane (const Equation& theEquation); + Standard_EXPORT Graphic3d_ClipPlane (const Graphic3d_Vec4d& theEquation); //! Construct clip plane from the passed geometrical definition. //! By default the plane is on, capping is turned off. @@ -78,14 +81,15 @@ public: //! Set 4-component equation vector for clipping plane. //! The equation is specified in "world" coordinate system. //! @param theEquation [in] the XYZW (or "ABCD") equation vector. - Standard_EXPORT void SetEquation (const Equation& theEquation); + Standard_EXPORT void SetEquation (const Graphic3d_Vec4d& theEquation); //! Get 4-component equation vector for clipping plane. //! @return clipping plane equation vector. - const Equation& GetEquation() const - { - return myEquation; - } + const Graphic3d_Vec4d& GetEquation() const { return myEquation; } + + //! Get 4-component equation vector for clipping plane. + //! @return clipping plane equation vector. + const Graphic3d_Vec4d& ReversedEquation() const { return myEquationRev; } //! Check that the clipping plane is turned on. //! @return boolean flag indicating whether the plane is in on or off state. @@ -123,6 +127,43 @@ public: //! @return new instance of clipping plane with same properties and attributes. Standard_EXPORT virtual Handle(Graphic3d_ClipPlane) Clone() const; +public: + + //! Return TRUE if this item defines a conjunction (logical AND) between a set of Planes. + //! Graphic3d_ClipPlane item defines either a Clipping halfspace (single Clipping Plane) + //! or a Clipping volume defined by a logical AND (conjunction) operation between a set of Planes defined as a Chain + //! (so that the volume cuts a space only in case if check fails for ALL Planes in the Chain). + //! + //! Note that Graphic3d_ClipPlane item cannot: + //! - Define a Chain with logical OR (disjunction) operation; + //! this should be done through Graphic3d_SequenceOfHClipPlane. + //! - Define nested Chains. + //! - Disable Chain items; only entire Chain can be disabled (by disabled a head of Chain). + //! + //! The head of a Chain defines all visual properties of the Chain, + //! so that Graphic3d_ClipPlane of next items in a Chain merely defines only geometrical definition of the plane. + Standard_Boolean IsChain() const { return !myNextInChain.IsNull(); } + + //! Return the previous plane in a Chain of Planes defining logical AND operation, + //! or NULL if there is no Chain or it is a first element in Chain. + //! When clipping is defined by a Chain of Planes, + //! it cuts a space only in case if check fails for all Planes in Chain. + Handle(Graphic3d_ClipPlane) ChainPreviousPlane() const { return myPrevInChain; } + + //! Return the next plane in a Chain of Planes defining logical AND operation, + //! or NULL if there is no chain or it is a last element in chain. + + const Handle(Graphic3d_ClipPlane)& ChainNextPlane() const { return myNextInChain; } + + //! Return the number of chains in forward direction (including this item, so it is always >= 1). + //! For a head of Chain - returns the length of entire Chain. + Standard_Integer NbChainNextPlanes() const { return myChainLenFwd; } + + //! Set the next plane in a Chain of Planes. + //! This operation also updates relationship between chains (Previous/Next items), + //! so that the previously set Next plane is cut off. + Standard_EXPORT void SetChainNextPlane (const Handle(Graphic3d_ClipPlane)& thePlane); + public: // @name user-defined graphical attributes //! Set material for rendering capping surface. @@ -209,6 +250,113 @@ public: //! Return true if some fill area aspect properties should be taken from object. bool ToUseObjectProperties() const { return myFlags != Graphic3d_CappingFlags_None; } +public: + + //! Check if the given point is outside / inside / on section. + Graphic3d_ClipState ProbePoint (const Graphic3d_Vec4d& thePoint) const + { + for (const Graphic3d_ClipPlane* aPlaneIter = this; aPlaneIter != NULL; aPlaneIter = aPlaneIter->myNextInChain.get()) + { + Graphic3d_ClipState aPlnState = aPlaneIter->ProbePointHalfspace (thePoint); + if (aPlnState == Graphic3d_ClipState_On) + { + return Graphic3d_ClipState_On; + } + else if (aPlnState == Graphic3d_ClipState_Out + && aPlaneIter->myNextInChain.IsNull()) + { + return Graphic3d_ClipState_Out; + } + } + return Graphic3d_ClipState_In; + } + + //! Check if the given bounding box is fully outside / fully inside. + Graphic3d_ClipState ProbeBox (const Graphic3d_BndBox3d& theBox) const + { + Graphic3d_ClipState aPrevState = Graphic3d_ClipState_On; + for (const Graphic3d_ClipPlane* aPlaneIter = this; aPlaneIter != NULL; aPlaneIter = aPlaneIter->myNextInChain.get()) + { + if (aPlaneIter->IsBoxFullOutHalfspace (theBox)) + { + if (aPlaneIter->myNextInChain.IsNull()) + { + return Graphic3d_ClipState_Out; + } + else if (aPrevState == Graphic3d_ClipState_In) + { + return Graphic3d_ClipState_On; + } + aPrevState = Graphic3d_ClipState_Out; + } + else if (aPlaneIter->IsBoxFullInHalfspace (theBox)) + { + if (aPlaneIter->myNextInChain.IsNull()) + { + return Graphic3d_ClipState_In; + } + else if (aPrevState == Graphic3d_ClipState_Out) + { + return Graphic3d_ClipState_On; + } + aPrevState = Graphic3d_ClipState_In; + } + else + { + return Graphic3d_ClipState_On; + } + } + return Graphic3d_ClipState_On; + } + +public: + + //! Check if the given point is outside of the half-space (e.g. should be discarded by clipping plane). + Graphic3d_ClipState ProbePointHalfspace (const Graphic3d_Vec4d& thePoint) const + { + const Standard_Real aVal = myEquation.Dot (thePoint); + return aVal < 0.0 + ? Graphic3d_ClipState_Out + : (aVal == 0.0 + ? Graphic3d_ClipState_On + : Graphic3d_ClipState_In); + } + + //! Check if the given bounding box is fully outside / fully inside the half-space. + Graphic3d_ClipState ProbeBoxHalfspace (const Graphic3d_BndBox3d& theBox) const + { + if (IsBoxFullOutHalfspace (theBox)) + { + return Graphic3d_ClipState_Out; + } + return IsBoxFullInHalfspace (theBox) + ? Graphic3d_ClipState_In + : Graphic3d_ClipState_On; + } + + //! Check if the given point is outside of the half-space (e.g. should be discarded by clipping plane). + bool IsPointOutHalfspace (const Graphic3d_Vec4d& thePoint) const { return ProbePointHalfspace (thePoint) == Graphic3d_ClipState_Out; } + + //! Check if the given bounding box is fully outside of the half-space (e.g. should be discarded by clipping plane). + bool IsBoxFullOutHalfspace (const Graphic3d_BndBox3d& theBox) const + { + const Graphic3d_Vec4d aMaxPnt (myEquation.x() > 0.0 ? theBox.CornerMax().x() : theBox.CornerMin().x(), + myEquation.y() > 0.0 ? theBox.CornerMax().y() : theBox.CornerMin().y(), + myEquation.z() > 0.0 ? theBox.CornerMax().z() : theBox.CornerMin().z(), + 1.0); + return IsPointOutHalfspace (aMaxPnt); + } + + //! Check if the given bounding box is fully inside (or touches from inside) the half-space (e.g. NOT discarded by clipping plane). + bool IsBoxFullInHalfspace (const Graphic3d_BndBox3d& theBox) const + { + const Graphic3d_Vec4d aMinPnt (myEquation.x() > 0.0 ? theBox.CornerMin().x() : theBox.CornerMax().x(), + myEquation.y() > 0.0 ? theBox.CornerMin().y() : theBox.CornerMax().y(), + myEquation.z() > 0.0 ? theBox.CornerMin().z() : theBox.CornerMax().z(), + 1.0); + return !IsPointOutHalfspace (aMinPnt); + } + public: // @name modification counters //! @return modification counter for equation. @@ -231,21 +379,33 @@ private: //! Set capping flag. Standard_EXPORT void setCappingFlag (bool theToUse, int theFlag); + //! Update chain length in backward direction. + void updateChainLen(); + + //! Update inversed plane definition from main plane. + void updateInversedPlane() + { + gp_Pln aPlane = myPlane; + aPlane.SetAxis (aPlane.Axis().Reversed()); + aPlane.Coefficients (myEquationRev[0], myEquationRev[1], myEquationRev[2], myEquationRev[3]); + } + private: Handle(Graphic3d_AspectFillArea3d) myAspect; //!< fill area aspect + Handle(Graphic3d_ClipPlane) myNextInChain; //!< next plane in a chain of planes defining logical AND operation + Graphic3d_ClipPlane* myPrevInChain; //!< previous plane in a chain of planes defining logical AND operation TCollection_AsciiString myId; //!< resource id gp_Pln myPlane; //!< plane definition - Equation myEquation; //!< plane equation vector + Graphic3d_Vec4d myEquation; //!< plane equation vector + Graphic3d_Vec4d myEquationRev; //!< reversed plane equation + Standard_Integer myChainLenFwd; //!< chain length in forward direction (including this item) unsigned int myFlags; //!< capping flags unsigned int myEquationMod; //!< modification counter for equation unsigned int myAspectMod; //!< modification counter of aspect Standard_Boolean myIsOn; //!< state of the clipping plane Standard_Boolean myIsCapping; //!< state of graphic driver capping -public: - - DEFINE_STANDARD_RTTIEXT(Graphic3d_ClipPlane,Standard_Transient) }; DEFINE_STANDARD_HANDLE (Graphic3d_ClipPlane, Standard_Transient) diff --git a/src/Graphic3d/Graphic3d_SequenceOfHClipPlane.cxx b/src/Graphic3d/Graphic3d_SequenceOfHClipPlane.cxx new file mode 100644 index 0000000000..e8cb10c32d --- /dev/null +++ b/src/Graphic3d/Graphic3d_SequenceOfHClipPlane.cxx @@ -0,0 +1,60 @@ +// Copyright (c) 2018 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_SequenceOfHClipPlane, Standard_Transient) + +// ======================================================================= +// function : Graphic3d_SequenceOfHClipPlane +// purpose : +// ======================================================================= +Graphic3d_SequenceOfHClipPlane::Graphic3d_SequenceOfHClipPlane() +: myToOverrideGlobal (Standard_False) +{ + // +} + +// ======================================================================= +// function : Append +// purpose : +// ======================================================================= +bool Graphic3d_SequenceOfHClipPlane::Append (const Handle(Graphic3d_ClipPlane)& theItem) +{ + for (NCollection_Sequence::Iterator anItemIter (myItems); anItemIter.More(); anItemIter.Next()) + { + if (anItemIter.Value() == theItem) + { + return false; + } + } + myItems.Append (theItem); + return true; +} + +// ======================================================================= +// function : Remove +// purpose : +// ======================================================================= +bool Graphic3d_SequenceOfHClipPlane::Remove (const Handle(Graphic3d_ClipPlane)& theItem) +{ + for (NCollection_Sequence::Iterator anItemIter (myItems); anItemIter.More(); anItemIter.Next()) + { + if (anItemIter.Value() == theItem) + { + myItems.Remove (anItemIter); + return true; + } + } + return false; +} diff --git a/src/Graphic3d/Graphic3d_SequenceOfHClipPlane.hxx b/src/Graphic3d/Graphic3d_SequenceOfHClipPlane.hxx index 457e799609..014aaebc71 100755 --- a/src/Graphic3d/Graphic3d_SequenceOfHClipPlane.hxx +++ b/src/Graphic3d/Graphic3d_SequenceOfHClipPlane.hxx @@ -17,19 +17,50 @@ #define _Graphic3d_SequenceOfHClipPlane_HeaderFile #include -#include #include -//! Class defining the sequence of clipping planes. -class Graphic3d_SequenceOfHClipPlane : public Standard_Transient, public NCollection_Sequence +//! Class defines a Clipping Volume as a logical OR (disjunction) operation between Graphic3d_ClipPlane in sequence. +//! Each Graphic3d_ClipPlane represents either a single Plane clipping a halfspace (direction is specified by normal), +//! or a sub-chain of planes defining a logical AND (conjunction) operation. +//! Therefore, this collection allows defining a Clipping Volume through the limited set of Boolean operations between clipping Planes. +//! +//! The Clipping Volume can be assigned either to entire View or to a specific Object; +//! in the latter case property ToOverrideGlobal() will specify if Object planes should override (suppress) globally defined ones +//! or extend their definition through logical OR (disjunction) operation. +//! +//! Note that defining (many) planes will lead to performance degradation, and Graphics Driver may limit +//! the overall number of simultaneously active clipping planes - but at least 6 planes should be supported on all configurations. +class Graphic3d_SequenceOfHClipPlane : public Standard_Transient { -DEFINE_STANDARD_RTTI_INLINE(Graphic3d_SequenceOfHClipPlane,Standard_Transient) + DEFINE_STANDARD_RTTIEXT(Graphic3d_SequenceOfHClipPlane, Standard_Transient) +public: + + //! Iterator through clipping planes. + class Iterator : public NCollection_Sequence::Iterator + { + public: + Iterator() {} + Iterator (const Graphic3d_SequenceOfHClipPlane& thePlanes) : NCollection_Sequence::Iterator (thePlanes.myItems) {} + Iterator (const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes) { Init (thePlanes); } + + void Init (const Graphic3d_SequenceOfHClipPlane& thePlanes) { NCollection_Sequence::Iterator::Init (thePlanes.myItems); } + void Init (const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes) + { + if (!thePlanes.IsNull()) + { + NCollection_Sequence::Iterator::Init (thePlanes->myItems); + } + else + { + *this = Iterator(); + } + } + }; + public: - DEFINE_STANDARD_ALLOC - DEFINE_NCOLLECTION_ALLOC //! Empty constructor. - Graphic3d_SequenceOfHClipPlane() : myToOverrideGlobal (Standard_False) {} + Standard_EXPORT Graphic3d_SequenceOfHClipPlane(); //! Return true if local properties should override global properties. Standard_Boolean ToOverrideGlobal() const { return myToOverrideGlobal; } @@ -37,8 +68,35 @@ public: //! Setup flag defining if local properties should override global properties. void SetOverrideGlobal (const Standard_Boolean theToOverride) { myToOverrideGlobal = theToOverride; } -private: + //! Return TRUE if sequence is empty. + bool IsEmpty() const { return myItems.IsEmpty(); } + //! Return the number of items in sequence. + Standard_Integer Size() const { return myItems.Size(); } + + //! Append a plane. + //! @return TRUE if new item has been added (FALSE if item already existed) + Standard_EXPORT bool Append (const Handle(Graphic3d_ClipPlane)& theItem); + + //! Remove a plane. + //! @return TRUE if item has been found and removed + Standard_EXPORT bool Remove (const Handle(Graphic3d_ClipPlane)& theItem); + + //! Remove a plane. + void Remove (Iterator& theItem) { myItems.Remove (theItem); } + + //! Clear the items out. + void Clear() + { + myItems.Clear(); + } + + //! Return the first item in sequence. + const Handle(Graphic3d_ClipPlane)& First() const { return myItems.First(); } + +protected: + + NCollection_Sequence myItems; Standard_Boolean myToOverrideGlobal; }; diff --git a/src/OpenGl/FILES b/src/OpenGl/FILES index 80a9aa0fd6..c9e4fa99b1 100755 --- a/src/OpenGl/FILES +++ b/src/OpenGl/FILES @@ -77,6 +77,7 @@ OpenGl_Caps.cxx OpenGl_Caps.hxx OpenGl_Clipping.cxx OpenGl_Clipping.hxx +OpenGl_ClippingIterator.hxx OpenGl_Context.cxx OpenGl_Context.hxx OpenGl_Context_1.mm diff --git a/src/OpenGl/OpenGl_CappingAlgo.cxx b/src/OpenGl/OpenGl_CappingAlgo.cxx index a729da3620..0a438fbc35 100755 --- a/src/OpenGl/OpenGl_CappingAlgo.cxx +++ b/src/OpenGl/OpenGl_CappingAlgo.cxx @@ -15,6 +15,7 @@ #include +#include #include #include #include @@ -37,6 +38,7 @@ namespace const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext(); thePlane->Update (aContext, theAspectFace != NULL ? theAspectFace->Aspect() : Handle(Graphic3d_AspectFillArea3d)()); + bool wasCullAllowed = theWorkspace->SetAllowFaceCulling (true); const OpenGl_AspectFace* aFaceAspect = theWorkspace->AspectFace(); theWorkspace->SetAspectFace (thePlane->AspectFace()); @@ -50,13 +52,15 @@ namespace aContext->ModelWorldState.Pop(); aContext->ApplyModelViewMatrix(); + theWorkspace->SetAllowFaceCulling (wasCullAllowed); theWorkspace->SetAspectFace (aFaceAspect); } //! Render capping for specific structure. static void renderCappingForStructure (const Handle(OpenGl_Workspace)& theWorkspace, const OpenGl_Structure& theStructure, - const OpenGl_ClippingIterator& thePlaneIter, + const Handle(Graphic3d_ClipPlane)& theClipChain, + const Standard_Integer theSubPlaneIndex, const Handle(OpenGl_CappingPlaneResource)& thePlane) { const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext(); @@ -69,7 +73,7 @@ namespace } // enable only the rendering plane to generate stencil mask - aContext->ChangeClipping().DisableAllExcept (aContext, thePlaneIter); + aContext->ChangeClipping().DisableAllExcept (theClipChain, theSubPlaneIndex); aContext->ShaderManager()->UpdateClippingState(); glClear (GL_STENCIL_BUFFER_BIT); @@ -112,7 +116,7 @@ namespace theWorkspace->ApplyAspectFace(); // enable all clip plane except the rendered one - aContext->ChangeClipping().EnableAllExcept (aContext, thePlaneIter); + aContext->ChangeClipping().EnableAllExcept (theClipChain, theSubPlaneIndex); aContext->ShaderManager()->UpdateClippingState(); // render capping plane using the generated stencil mask @@ -128,19 +132,18 @@ namespace glEnable (GL_DEPTH_TEST); } - renderPlane (theWorkspace, thePlane, aRenderPlane->ToUseObjectProperties() - ? aGroupIter.Value()->AspectFace() - : NULL); + renderPlane (theWorkspace, thePlane, + aRenderPlane->ToUseObjectProperties() ? aGroupIter.Value()->AspectFace() : NULL); // turn on the current plane to restore initial state - aContext->ChangeClipping().SetEnabled (aContext, thePlaneIter, Standard_True); + aContext->ChangeClipping().ResetCappingFilter(); aContext->ShaderManager()->RevertClippingState(); aContext->ShaderManager()->RevertClippingState(); } if (theStructure.InstancedStructure() != NULL) { - renderCappingForStructure (theWorkspace, *theStructure.InstancedStructure(), thePlaneIter, thePlane); + renderCappingForStructure (theWorkspace, *theStructure.InstancedStructure(), theClipChain, theSubPlaneIndex, thePlane); } } } @@ -181,28 +184,32 @@ void OpenGl_CappingAlgo::RenderCapping (const Handle(OpenGl_Workspace)& theWorks for (OpenGl_ClippingIterator aCappingIt (aContext->Clipping()); aCappingIt.More(); aCappingIt.Next()) { // get plane being rendered - const Handle(Graphic3d_ClipPlane)& aRenderPlane = aCappingIt.Value(); - if (!aRenderPlane->IsCapping() + const Handle(Graphic3d_ClipPlane)& aClipChain = aCappingIt.Value(); + if (!aClipChain->IsCapping() || aCappingIt.IsDisabled()) { continue; } - // get resource for the plane - const TCollection_AsciiString& aResId = aRenderPlane->GetId(); - Handle(OpenGl_CappingPlaneResource) aPlaneRes; - if (!aContext->GetResource (aResId, aPlaneRes)) + Standard_Integer aSubPlaneIndex = 1; + for (const Graphic3d_ClipPlane* aSubPlaneIter = aClipChain.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get(), ++aSubPlaneIndex) { - // share and register for release once the resource is no longer used - aPlaneRes = new OpenGl_CappingPlaneResource (aRenderPlane); - aContext->ShareResource (aResId, aPlaneRes); + // 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 (theWorkspace, theStructure, aClipChain, aSubPlaneIndex, aPlaneRes); + + // set delayed resource release + aPlaneRes.Nullify(); + aContext->ReleaseResource (aResId, Standard_True); } - - renderCappingForStructure (theWorkspace, theStructure, aCappingIt, aPlaneRes); - - // set delayed resource release - aPlaneRes.Nullify(); - aContext->ReleaseResource (aResId, Standard_True); } // restore previous application state diff --git a/src/OpenGl/OpenGl_CappingPlaneResource.cxx b/src/OpenGl/OpenGl_CappingPlaneResource.cxx index a4b77939d1..d551231791 100755 --- a/src/OpenGl/OpenGl_CappingPlaneResource.cxx +++ b/src/OpenGl/OpenGl_CappingPlaneResource.cxx @@ -29,21 +29,21 @@ namespace //! - 4 floats, UV texture coordinates static const GLfloat THE_CAPPING_PLN_VERTS[12 * (4 + 4 + 4)] = { - 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, - 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,-1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,-1.0f, 0.0f, 0.0f, 0.0f,-1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,-1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,-1.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, + -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,-1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,-1.0f, 0.0f, 0.0f, 0.0f,-1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, - -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f,-1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f,-1.0f, 0.0f, 0.0f,-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,-1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f,-1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f + 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,-1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f,-1.0f, 0.0f, 0.0f,-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f }; static const OpenGl_Matrix OpenGl_IdentityMatrix = diff --git a/src/OpenGl/OpenGl_Clipping.cxx b/src/OpenGl/OpenGl_Clipping.cxx index edc9b71b1e..a572df8a11 100755 --- a/src/OpenGl/OpenGl_Clipping.cxx +++ b/src/OpenGl/OpenGl_Clipping.cxx @@ -15,35 +15,17 @@ #include -#include -#include -#include +#include // ======================================================================= -// function : OpenGl_ClippingIterator +// function : OpenGl_Clipping // purpose : // ======================================================================= -OpenGl_ClippingIterator::OpenGl_ClippingIterator (const OpenGl_Clipping& theClipping) -: myDisabled (&theClipping.myDisabledPlanes), - myCurrIndex (1) -{ - if (!theClipping.myPlanesGlobal.IsNull()) - { - myIter1.Init (*theClipping.myPlanesGlobal); - } - if (!theClipping.myPlanesLocal.IsNull()) - { - myIter2.Init (*theClipping.myPlanesLocal); - } -} - -// ======================================================================= -// function : OpenGl_ClippingState -// purpose : -// ======================================================================= -OpenGl_Clipping::OpenGl_Clipping () -: myNbClipping (0), +OpenGl_Clipping::OpenGl_Clipping() +: myCappedSubPlane (0), + myNbClipping (0), myNbCapping (0), + myNbChains (0), myNbDisabled (0) {} @@ -51,32 +33,36 @@ OpenGl_Clipping::OpenGl_Clipping () // function : Init // purpose : // ======================================================================= -void OpenGl_Clipping::Init (const Standard_Integer ) +void OpenGl_Clipping::Init() { myPlanesGlobal.Nullify(); myPlanesLocal.Nullify(); myNbClipping = 0; myNbCapping = 0; + myNbChains = 0; myNbDisabled = 0; + myCappedSubPlane = 0; + myCappedChain.Nullify(); } // ======================================================================= // function : Reset // purpose : // ======================================================================= -void OpenGl_Clipping::Reset (const Handle(OpenGl_Context)& theGlCtx, - const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes) +void OpenGl_Clipping::Reset (const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes) { const Standard_Integer aStartIndex = myPlanesGlobal.IsNull() ? 1 : myPlanesGlobal->Size() + 1; - remove (theGlCtx, myPlanesLocal, aStartIndex); - remove (theGlCtx, myPlanesGlobal, 1); + remove (myPlanesLocal, aStartIndex); + remove (myPlanesGlobal, 1); myPlanesGlobal = thePlanes; myPlanesLocal.Nullify(); - add (theGlCtx, thePlanes, 1); + add (thePlanes, 1); myNbDisabled = 0; + myCappedSubPlane = 0; + myCappedChain.Nullify(); // Method ::add() implicitly extends myDisabledPlanes (NCollection_Vector::SetValue()), // however we do not reset myDisabledPlanes and mySkipFilter beforehand to avoid redundant memory re-allocations. @@ -88,23 +74,21 @@ void OpenGl_Clipping::Reset (const Handle(OpenGl_Context)& theGlCtx, // function : SetLocalPlanes // purpose : // ======================================================================= -void OpenGl_Clipping::SetLocalPlanes (const Handle(OpenGl_Context)& theGlCtx, - const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes) +void OpenGl_Clipping::SetLocalPlanes (const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes) { const Standard_Integer aStartIndex = myPlanesGlobal.IsNull() ? 1 : myPlanesGlobal->Size() + 1; - remove (theGlCtx, myPlanesLocal, aStartIndex); + remove (myPlanesLocal, aStartIndex); myPlanesLocal = thePlanes; - add (theGlCtx, thePlanes, aStartIndex); + add (thePlanes, aStartIndex); } // ======================================================================= // function : add // purpose : // ======================================================================= -void OpenGl_Clipping::add (const Handle(OpenGl_Context)& , - const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes, +void OpenGl_Clipping::add (const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes, const Standard_Integer theStartIndex) { if (thePlanes.IsNull()) @@ -122,13 +106,15 @@ void OpenGl_Clipping::add (const Handle(OpenGl_Context)& , continue; } + const Standard_Integer aNbSubPlanes = aPlane->NbChainNextPlanes(); + myNbChains += 1; if (aPlane->IsCapping()) { - ++myNbCapping; + myNbCapping += aNbSubPlanes; } else { - ++myNbClipping; + myNbClipping += aNbSubPlanes; } } } @@ -137,8 +123,7 @@ void OpenGl_Clipping::add (const Handle(OpenGl_Context)& , // function : remove // purpose : // ======================================================================= -void OpenGl_Clipping::remove (const Handle(OpenGl_Context)& , - const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes, +void OpenGl_Clipping::remove (const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes, const Standard_Integer theStartIndex) { if (thePlanes.IsNull()) @@ -156,13 +141,15 @@ void OpenGl_Clipping::remove (const Handle(OpenGl_Context)& , continue; } + const Standard_Integer aNbSubPlanes = aPlane->NbChainNextPlanes(); + myNbChains -= 1; if (aPlane->IsCapping()) { - --myNbCapping; + myNbCapping -= aNbSubPlanes; } else { - --myNbClipping; + myNbClipping -= aNbSubPlanes; } } } @@ -171,8 +158,7 @@ void OpenGl_Clipping::remove (const Handle(OpenGl_Context)& , // function : SetEnabled // purpose : // ======================================================================= -Standard_Boolean OpenGl_Clipping::SetEnabled (const Handle(OpenGl_Context)& , - const OpenGl_ClippingIterator& thePlane, +Standard_Boolean OpenGl_Clipping::SetEnabled (const OpenGl_ClippingIterator& thePlane, const Standard_Boolean theIsEnabled) { const Standard_Integer aPlaneIndex = thePlane.PlaneIndex(); @@ -183,15 +169,17 @@ Standard_Boolean OpenGl_Clipping::SetEnabled (const Handle(OpenGl_Context)& , } isDisabled = !theIsEnabled; + const Standard_Integer aNbSubPlanes = thePlane.Value()->NbChainNextPlanes(); if (thePlane.Value()->IsCapping()) { - myNbCapping += (theIsEnabled ? 1 : -1); + myNbCapping += (theIsEnabled ? aNbSubPlanes : -aNbSubPlanes); } else { - myNbClipping += (theIsEnabled ? 1 : -1); + myNbClipping += (theIsEnabled ? aNbSubPlanes : -aNbSubPlanes); } - myNbDisabled -= (theIsEnabled ? 1 : -1); + myNbChains += (theIsEnabled ? 1 : -1); + myNbDisabled += (theIsEnabled ? -aNbSubPlanes : aNbSubPlanes); return Standard_True; } @@ -199,7 +187,7 @@ Standard_Boolean OpenGl_Clipping::SetEnabled (const Handle(OpenGl_Context)& , // function : RestoreDisabled // purpose : // ======================================================================= -void OpenGl_Clipping::RestoreDisabled (const Handle(OpenGl_Context)& ) +void OpenGl_Clipping::RestoreDisabled() { if (myNbDisabled == 0) { @@ -217,13 +205,15 @@ void OpenGl_Clipping::RestoreDisabled (const Handle(OpenGl_Context)& ) isDisabled = Standard_False; const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIter.Value(); + const Standard_Integer aNbSubPlanes = aPlane->NbChainNextPlanes(); + myNbChains += 1; if (aPlane->IsCapping()) { - ++myNbCapping; + myNbCapping += aNbSubPlanes; } else { - ++myNbClipping; + myNbClipping += aNbSubPlanes; } } } @@ -232,7 +222,7 @@ void OpenGl_Clipping::RestoreDisabled (const Handle(OpenGl_Context)& ) // function : DisableGlobal // purpose : // ======================================================================= -void OpenGl_Clipping::DisableGlobal (const Handle(OpenGl_Context)& theGlCtx) +void OpenGl_Clipping::DisableGlobal() { for (OpenGl_ClippingIterator aPlaneIter (*this); aPlaneIter.More(); aPlaneIter.Next()) { @@ -242,7 +232,7 @@ void OpenGl_Clipping::DisableGlobal (const Handle(OpenGl_Context)& theGlCtx) return; } - SetEnabled (theGlCtx, aPlaneIter, Standard_False); + SetEnabled (aPlaneIter, Standard_False); } } @@ -250,38 +240,30 @@ void OpenGl_Clipping::DisableGlobal (const Handle(OpenGl_Context)& theGlCtx) // function : DisableAllExcept // purpose : // ======================================================================= -void OpenGl_Clipping::DisableAllExcept (const Handle(OpenGl_Context)& theGlCtx, - const OpenGl_ClippingIterator& thePlane) +void OpenGl_Clipping::DisableAllExcept (const Handle(Graphic3d_ClipPlane)& theChain, + const Standard_Integer theSubPlaneIndex) { - for (OpenGl_ClippingIterator aPlaneIter (*this); aPlaneIter.More(); aPlaneIter.Next()) - { - if (aPlaneIter.IsDisabled()) - { - mySkipFilter.SetValue (aPlaneIter.PlaneIndex(), Standard_True); - continue; - } - - const Standard_Boolean isOn = (aPlaneIter.PlaneIndex() == thePlane.PlaneIndex()); - SetEnabled (theGlCtx, aPlaneIter, isOn); - mySkipFilter.SetValue (aPlaneIter.PlaneIndex(), Standard_False); - } + myCappedChain = theChain; + myCappedSubPlane = theSubPlaneIndex; } // ======================================================================= // function : EnableAllExcept // purpose : // ======================================================================= -void OpenGl_Clipping::EnableAllExcept (const Handle(OpenGl_Context)& theGlCtx, - const OpenGl_ClippingIterator& thePlane) +void OpenGl_Clipping::EnableAllExcept (const Handle(Graphic3d_ClipPlane)& theChain, + const Standard_Integer theSubPlaneIndex) { - for (OpenGl_ClippingIterator aPlaneIter (*this); aPlaneIter.More(); aPlaneIter.Next()) - { - if (mySkipFilter.Value (aPlaneIter.PlaneIndex())) - { - continue; - } - - const Standard_Boolean isOn = (aPlaneIter.PlaneIndex() != thePlane.PlaneIndex()); - SetEnabled (theGlCtx, aPlaneIter, isOn); - } + myCappedChain = theChain; + myCappedSubPlane = -theSubPlaneIndex; +} + +// ======================================================================= +// function : ResetCappingFilter +// purpose : +// ======================================================================= +void OpenGl_Clipping::ResetCappingFilter() +{ + myCappedChain.Nullify(); + myCappedSubPlane = 0; } diff --git a/src/OpenGl/OpenGl_Clipping.hxx b/src/OpenGl/OpenGl_Clipping.hxx index 6e1c5d312b..b2fe1f31a4 100755 --- a/src/OpenGl/OpenGl_Clipping.hxx +++ b/src/OpenGl/OpenGl_Clipping.hxx @@ -20,7 +20,6 @@ #include #include -class OpenGl_Context; class OpenGl_ClippingIterator; //! This class contains logics related to tracking and modification of clipping plane @@ -30,35 +29,51 @@ class OpenGl_ClippingIterator; //! class. class OpenGl_Clipping { + friend class OpenGl_ClippingIterator; public: //! @name general methods //! Default constructor. Standard_EXPORT OpenGl_Clipping(); //! Initialize. - //! @param theMaxPlanes [in] number of clipping planes supported by OpenGl context. - Standard_EXPORT void Init (const Standard_Integer theMaxPlanes); + Standard_EXPORT void Init(); //! Setup list of global (for entire view) clipping planes //! and clears local plane list if it was not released before. - Standard_EXPORT void Reset (const Handle(OpenGl_Context)& theGlCtx, - const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes); + Standard_EXPORT void Reset (const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes); //! Setup list of local (for current object) clipping planes. - Standard_EXPORT void SetLocalPlanes (const Handle(OpenGl_Context)& theGlCtx, - const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes); - - //! @return true if there are enabled clipping planes (NOT capping) - Standard_Boolean IsClippingOn() const { return myNbClipping > 0; } + Standard_EXPORT void SetLocalPlanes (const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes); //! @return true if there are enabled capping planes Standard_Boolean IsCappingOn() const { return myNbCapping > 0; } //! @return true if there are enabled clipping or capping planes - Standard_Boolean IsClippingOrCappingOn() const { return (myNbClipping + myNbCapping) > 0; } + Standard_Boolean IsClippingOrCappingOn() const { return NbClippingOrCappingOn() > 0; } //! @return number of enabled clipping + capping planes - Standard_Integer NbClippingOrCappingOn() const { return myNbClipping + myNbCapping; } + Standard_Integer NbClippingOrCappingOn() const + { + if (IsCappingDisableAllExcept()) + { + return 1; // all Chains are disabled - only single (sub) plane is active + } + return myNbClipping + myNbCapping + + (IsCappingEnableAllExcept() ? -1 : 0); // exclude 1 plane with Capping filter turned ON + } + + //! Return TRUE if there are clipping chains in the list (defining more than 1 sub-plane) + Standard_Boolean HasClippingChains() const + { + if (IsCappingDisableAllExcept() // all chains are disabled - only single (sub) plane is active; + || myNbChains == (myNbClipping + myNbCapping)) // no sub-planes + { + return Standard_False; + } + return !IsCappingEnableAllExcept() + || myCappedChain->NbChainNextPlanes() == 1 + || myNbChains > 1; // if capping filter ON - chains counter should be decremented + } public: //! @name advanced method for disabling defined planes @@ -66,26 +81,46 @@ public: //! @name advanced method for disabling defined planes Standard_Boolean HasDisabled() const { return myNbDisabled > 0; } //! Disable plane temporarily. - Standard_EXPORT Standard_Boolean SetEnabled (const Handle(OpenGl_Context)& theGlCtx, - const OpenGl_ClippingIterator& thePlane, + Standard_EXPORT Standard_Boolean SetEnabled (const OpenGl_ClippingIterator& thePlane, const Standard_Boolean theIsEnabled); //! Temporarily disable all planes from the global (view) list, keep only local (object) list. - Standard_EXPORT void DisableGlobal (const Handle(OpenGl_Context)& theGlCtx); + Standard_EXPORT void DisableGlobal(); //! Restore all temporarily disabled planes. //! Does NOT affect constantly disabled planes Graphic3d_ClipPlane::IsOn(). - Standard_EXPORT void RestoreDisabled (const Handle(OpenGl_Context)& theGlCtx); + Standard_EXPORT void RestoreDisabled(); - //! Temporarily disable all planes except specified one. +//! @name capping algorithm filter +public: + + //! Chain which is either temporary disabled or the only one enabled for Capping algorithm. + const Handle(Graphic3d_ClipPlane)& CappedChain() const { return myCappedChain; } + + //! Sub-plane index within filtered Chain; positive number for DisableAllExcept and negative for EnableAllExcept. + Standard_Integer CappedSubPlane() const { return myCappedSubPlane; } + + //! Return TRUE if capping algorithm is in state, when all clipping planes are temporarily disabled except currently processed one. + bool IsCappingFilterOn() const { return !myCappedChain.IsNull(); } + + //! Return TRUE if capping algorithm is in state, when all clipping planes are temporarily disabled except currently processed one. + bool IsCappingDisableAllExcept() const { return myCappedSubPlane > 0; } + + //! Return TRUE if capping algorithm is in state, when all clipping planes are enabled except currently rendered one. + bool IsCappingEnableAllExcept() const { return myCappedSubPlane < 0; } + + //! Temporarily disable all planes except specified one for Capping algorithm. //! Does not affect already disabled planes. - Standard_EXPORT void DisableAllExcept (const Handle(OpenGl_Context)& theGlCtx, - const OpenGl_ClippingIterator& thePlane); + Standard_EXPORT void DisableAllExcept (const Handle(Graphic3d_ClipPlane)& theChain, + const Standard_Integer theSubPlaneIndex); - //! Enable back planes disabled by ::DisableAllExcept(). + //! Enable back planes disabled by ::DisableAllExcept() for Capping algorithm. //! Keeps only specified plane enabled. - Standard_EXPORT void EnableAllExcept (const Handle(OpenGl_Context)& theGlCtx, - const OpenGl_ClippingIterator& thePlane); + Standard_EXPORT void EnableAllExcept (const Handle(Graphic3d_ClipPlane)& theChain, + const Standard_Integer theSubPlaneIndex); + + //! Resets chain filter for Capping algorithm. + Standard_EXPORT void ResetCappingFilter(); protected: //! @name clipping state modification commands @@ -98,18 +133,15 @@ protected: //! @name clipping state modification commands //! Within FFP, method also temporarily resets ModelView matrix before calling glClipPlane(). //! Otherwise the method just redirects to addLazy(). //! - //! @param theGlCtx [in] context to access the matrices //! @param thePlanes [in/out] the list of planes to be added //! The list then provides information on which planes were really added to clipping state. //! This list then can be used to fall back to previous state. - Standard_EXPORT void add (const Handle(OpenGl_Context)& theGlCtx, - const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes, + Standard_EXPORT void add (const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes, const Standard_Integer theStartIndex); //! Remove the passed set of clipping planes from the context state. //! @param thePlanes [in] the planes to remove from list. - Standard_EXPORT void remove (const Handle(OpenGl_Context)& theGlCtx, - const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes, + Standard_EXPORT void remove (const Handle(Graphic3d_SequenceOfHClipPlane)& thePlanes, const Standard_Integer theStartIndex); private: @@ -117,70 +149,19 @@ private: Handle(Graphic3d_SequenceOfHClipPlane) myPlanesGlobal; //!< global clipping planes Handle(Graphic3d_SequenceOfHClipPlane) myPlanesLocal; //!< object clipping planes NCollection_Vector myDisabledPlanes; //!< ids of disabled planes - NCollection_Vector mySkipFilter; //!< ids of planes that were disabled before calling ::DisableAllExcept() + + Handle(Graphic3d_ClipPlane) myCappedChain; //!< chain which is either temporary disabled or the only one enabled for Capping algorithm + Standard_Integer myCappedSubPlane; //!< sub-plane index within filtered chain; positive number for DisableAllExcept and negative for EnableAllExcept + Standard_Integer myNbClipping; //!< number of enabled clipping-only planes (NOT capping) Standard_Integer myNbCapping; //!< number of enabled capping planes + Standard_Integer myNbChains; //!< number of enabled chains Standard_Integer myNbDisabled; //!< number of defined but disabled planes private: - //! Copying allowed only within Handles OpenGl_Clipping (const OpenGl_Clipping& ); OpenGl_Clipping& operator= (const OpenGl_Clipping& ); - - friend class OpenGl_ClippingIterator; -}; - -//! The iterator through clipping planes. -class OpenGl_ClippingIterator -{ -public: - - //! Main constructor. - Standard_EXPORT OpenGl_ClippingIterator(const OpenGl_Clipping& theClipping); - - //! Return true if iterator points to the valid clipping plane. - bool More() const { return myIter1.More() || myIter2.More(); } - - //! Go to the next clipping plane. - void Next() - { - ++myCurrIndex; - if (myIter1.More()) - { - myIter1.Next(); - } - else - { - myIter2.Next(); - } - } - - //! Return true if plane has been temporarily disabled - //! either by Graphic3d_ClipPlane->IsOn() property or by temporary filter. - bool IsDisabled() const { return myDisabled->Value (myCurrIndex) || !Value()->IsOn(); } - - //! Return the plane at current iterator position. - const Handle(Graphic3d_ClipPlane)& Value() const - { - return myIter1.More() - ? myIter1.Value() - : myIter2.Value(); - } - - //! Return true if plane from the global (view) list. - bool IsGlobal() const { return myIter1.More(); } - - //! Return the plane index. - Standard_Integer PlaneIndex() const { return myCurrIndex; } - -private: - - Graphic3d_SequenceOfHClipPlane::Iterator myIter1; - Graphic3d_SequenceOfHClipPlane::Iterator myIter2; - const NCollection_Vector* myDisabled; - Standard_Integer myCurrIndex; - }; #endif diff --git a/src/OpenGl/OpenGl_ClippingIterator.hxx b/src/OpenGl/OpenGl_ClippingIterator.hxx new file mode 100644 index 0000000000..3cae9bd5fa --- /dev/null +++ b/src/OpenGl/OpenGl_ClippingIterator.hxx @@ -0,0 +1,77 @@ +// Copyright (c) 2013-2014 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef OpenGl_ClippingIterator_Header +#define OpenGl_ClippingIterator_Header + +#include + +//! The iterator through clipping planes. +class OpenGl_ClippingIterator +{ +public: + + //! Main constructor. + OpenGl_ClippingIterator(const OpenGl_Clipping& theClipping) + : myDisabled (&theClipping.myDisabledPlanes), + myCurrIndex (1) + { + myIter1.Init (theClipping.myPlanesGlobal); + myIter2.Init (theClipping.myPlanesLocal); + } + + //! Return true if iterator points to the valid clipping plane. + bool More() const { return myIter1.More() || myIter2.More(); } + + //! Go to the next clipping plane. + void Next() + { + ++myCurrIndex; + if (myIter1.More()) + { + myIter1.Next(); + } + else + { + myIter2.Next(); + } + } + + //! Return true if plane has been temporarily disabled either by Graphic3d_ClipPlane->IsOn() property or by temporary filter. + //! Beware that this method does NOT handle a Chain filter for Capping algorithm OpenGl_Clipping::CappedChain()! + bool IsDisabled() const { return myDisabled->Value (myCurrIndex) || !Value()->IsOn(); } + + //! Return the plane at current iterator position. + const Handle(Graphic3d_ClipPlane)& Value() const + { + return myIter1.More() + ? myIter1.Value() + : myIter2.Value(); + } + + //! Return true if plane from the global (view) list. + bool IsGlobal() const { return myIter1.More(); } + + //! Return the plane index. + Standard_Integer PlaneIndex() const { return myCurrIndex; } + +private: + + Graphic3d_SequenceOfHClipPlane::Iterator myIter1; + Graphic3d_SequenceOfHClipPlane::Iterator myIter2; + const NCollection_Vector* myDisabled; + Standard_Integer myCurrIndex; + +}; + +#endif // OpenGl_ClippingIterator_Header diff --git a/src/OpenGl/OpenGl_Context.cxx b/src/OpenGl/OpenGl_Context.cxx index 39a494c093..487e4e0349 100644 --- a/src/OpenGl/OpenGl_Context.cxx +++ b/src/OpenGl/OpenGl_Context.cxx @@ -1465,7 +1465,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile) glGetIntegerv (GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &myAnisoMax); } - myClippingState.Init (myMaxClipPlanes); + myClippingState.Init(); #if !defined(GL_ES_VERSION_2_0) diff --git a/src/OpenGl/OpenGl_Group.cxx b/src/OpenGl/OpenGl_Group.cxx index f539a6867e..1d44dd97f5 100644 --- a/src/OpenGl/OpenGl_Group.cxx +++ b/src/OpenGl/OpenGl_Group.cxx @@ -396,7 +396,8 @@ void OpenGl_Group::Render (const Handle(OpenGl_Workspace)& theWorkspace) const const Handle(OpenGl_RenderFilter)& aFilter = theWorkspace->GetRenderFilter(); // Setup aspects - theWorkspace->SetAllowFaceCulling (myIsClosed); + theWorkspace->SetAllowFaceCulling (myIsClosed + && !theWorkspace->GetGlContext()->Clipping().IsClippingOrCappingOn()); const OpenGl_AspectLine* aBackAspectLine = theWorkspace->AspectLine(); const OpenGl_AspectFace* aBackAspectFace = theWorkspace->AspectFace(); const OpenGl_AspectMarker* aBackAspectMarker = theWorkspace->AspectMarker(); diff --git a/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx b/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx index f04c5471ff..9c44813edd 100644 --- a/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx +++ b/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx @@ -31,10 +31,12 @@ enum OpenGl_ProgramOptions OpenGl_PO_StippleLine = 0x020, //!< stipple line OpenGl_PO_ClipPlanes1 = 0x040, //!< handle 1 clipping plane OpenGl_PO_ClipPlanes2 = 0x080, //!< handle 2 clipping planes + //OpenGl_PO_ClipPlanes3 = OpenGl_PO_ClipPlanes1|OpenGl_PO_ClipPlanes2, //!< handle 3 clipping planes - not implemented OpenGl_PO_ClipPlanesN = 0x100, //!< handle N clipping planes - OpenGl_PO_AlphaTest = 0x200, //!< discard fragment by alpha test (defined by cutoff value) - OpenGl_PO_WriteOit = 0x400, //!< write coverage buffer for Blended Order-Independent Transparency - OpenGl_PO_NB = 0x800 //!< overall number of combinations + OpenGl_PO_ClipChains = 0x200, //!< handle chains of clipping planes + OpenGl_PO_AlphaTest = 0x400, //!< discard fragment by alpha test (defined by cutoff value) + OpenGl_PO_WriteOit = 0x800, //!< write coverage buffer for Blended Order-Independent Transparency + OpenGl_PO_NB = 0x1000 //!< overall number of combinations }; //! Alias to programs array of predefined length diff --git a/src/OpenGl/OpenGl_ShaderManager.cxx b/src/OpenGl/OpenGl_ShaderManager.cxx index a83169c8b1..a939255ea7 100644 --- a/src/OpenGl/OpenGl_ShaderManager.cxx +++ b/src/OpenGl/OpenGl_ShaderManager.cxx @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include @@ -238,6 +238,25 @@ const char THE_FRAG_CLIP_PLANES_N[] = EOL" }" EOL" }"; +//! Process chains of clipping planes in Fragment Shader. +const char THE_FRAG_CLIP_CHAINS_N[] = +EOL" for (int aPlaneIter = 0; aPlaneIter < occClipPlaneCount;)" +EOL" {" +EOL" vec4 aClipEquation = occClipPlaneEquations[aPlaneIter];" +EOL" if (dot (aClipEquation.xyz, PositionWorld.xyz / PositionWorld.w) + aClipEquation.w < 0.0)" +EOL" {" +EOL" if (occClipPlaneChains[aPlaneIter] == 1)" +EOL" {" +EOL" discard;" +EOL" }" +EOL" aPlaneIter += 1;" +EOL" }" +EOL" else" +EOL" {" +EOL" aPlaneIter += occClipPlaneChains[aPlaneIter];" +EOL" }" +EOL" }"; + //! Process 1 clipping plane in Fragment Shader. const char THE_FRAG_CLIP_PLANES_1[] = EOL" vec4 aClipEquation0 = occClipPlaneEquations[0];" @@ -256,6 +275,16 @@ const char THE_FRAG_CLIP_PLANES_2[] = EOL" discard;" EOL" }"; +//! Process a chain of 2 clipping planes in Fragment Shader (3/4 section). +const char THE_FRAG_CLIP_CHAINS_2[] = +EOL" vec4 aClipEquation0 = occClipPlaneEquations[0];" +EOL" vec4 aClipEquation1 = occClipPlaneEquations[1];" +EOL" if (dot (aClipEquation0.xyz, PositionWorld.xyz / PositionWorld.w) + aClipEquation0.w < 0.0" +EOL" && dot (aClipEquation1.xyz, PositionWorld.xyz / PositionWorld.w) + aClipEquation1.w < 0.0)" +EOL" {" +EOL" discard;" +EOL" }"; + #if !defined(GL_ES_VERSION_2_0) static const GLfloat THE_DEFAULT_AMBIENT[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; @@ -930,10 +959,14 @@ void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram) Standard_Integer aPlaneId = 0; Standard_Boolean toRestoreModelView = Standard_False; + const Handle(Graphic3d_ClipPlane)& aCappedChain = myContext->Clipping().CappedChain(); for (OpenGl_ClippingIterator aPlaneIter (myContext->Clipping()); aPlaneIter.More(); aPlaneIter.Next()) { const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIter.Value(); - if (aPlaneIter.IsDisabled()) + if (aPlaneIter.IsDisabled() + || aPlane->IsChain() + || (aPlane == aCappedChain + && myContext->Clipping().IsCappingEnableAllExcept())) { continue; } @@ -995,21 +1028,21 @@ void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram) } const Standard_Integer aNbClipPlanesMax = theProgram->NbClipPlanesMax(); - const GLint aNbPlanes = Min (myContext->Clipping().NbClippingOrCappingOn(), aNbClipPlanesMax); - theProgram->SetUniform (myContext, - theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_COUNT), - aNbPlanes); + const Standard_Integer aNbPlanes = Min (myContext->Clipping().NbClippingOrCappingOn(), aNbClipPlanesMax); if (aNbPlanes < 1) { + theProgram->SetUniform (myContext, theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_COUNT), 0); return; } if (myClipPlaneArray.Size() < aNbClipPlanesMax) { myClipPlaneArray.Resize (0, aNbClipPlanesMax - 1, false); + myClipChainArray.Resize (0, aNbClipPlanesMax - 1, false); } Standard_Integer aPlaneId = 0; + const Handle(Graphic3d_ClipPlane)& aCappedChain = myContext->Clipping().CappedChain(); for (OpenGl_ClippingIterator aPlaneIter (myContext->Clipping()); aPlaneIter.More(); aPlaneIter.Next()) { const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIter.Value(); @@ -1017,29 +1050,64 @@ void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram) { continue; } - else if (aPlaneId >= aNbClipPlanesMax) + + if (myContext->Clipping().IsCappingDisableAllExcept()) { - myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM, - TCollection_AsciiString("Warning: clipping planes limit (") + aNbClipPlanesMax + ") has been exceeded."); + // enable only specific (sub) plane + if (aPlane != aCappedChain) + { + continue; + } + + Standard_Integer aSubPlaneIndex = 1; + for (const Graphic3d_ClipPlane* aSubPlaneIter = aCappedChain.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get(), ++aSubPlaneIndex) + { + if (aSubPlaneIndex == myContext->Clipping().CappedSubPlane()) + { + addClippingPlane (aPlaneId, *aSubPlaneIter, aSubPlaneIter->GetEquation(), 1); + break; + } + } break; } - - const Graphic3d_ClipPlane::Equation& anEquation = aPlane->GetEquation(); - OpenGl_Vec4& aPlaneEq = myClipPlaneArray.ChangeValue (aPlaneId); - aPlaneEq.x() = float(anEquation.x()); - aPlaneEq.y() = float(anEquation.y()); - aPlaneEq.z() = float(anEquation.z()); - aPlaneEq.w() = float(anEquation.w()); - if (myHasLocalOrigin) + else if (aPlane == aCappedChain) // && myContext->Clipping().IsCappingEnableAllExcept() { - const gp_XYZ aPos = aPlane->ToPlane().Position().Location().XYZ() - myLocalOrigin; - const Standard_Real aD = -(anEquation.x() * aPos.X() + anEquation.y() * aPos.Y() + anEquation.z() * aPos.Z()); - aPlaneEq.w() = float(aD); + // enable sub-planes within processed Chain as reversed and ORed, excluding filtered plane + if (aPlaneId + aPlane->NbChainNextPlanes() - 1 > aNbClipPlanesMax) + { + myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, + TCollection_AsciiString("Error: clipping planes limit (") + aNbClipPlanesMax + ") has been exceeded."); + break; + } + + Standard_Integer aSubPlaneIndex = 1; + for (const Graphic3d_ClipPlane* aSubPlaneIter = aPlane.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get(), ++aSubPlaneIndex) + { + if (aSubPlaneIndex != -myContext->Clipping().CappedSubPlane()) + { + addClippingPlane (aPlaneId, *aSubPlaneIter, aSubPlaneIter->ReversedEquation(), 1); + } + } + } + else + { + // normal case + if (aPlaneId + aPlane->NbChainNextPlanes() > aNbClipPlanesMax) + { + myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, + TCollection_AsciiString("Error: clipping planes limit (") + aNbClipPlanesMax + ") has been exceeded."); + break; + } + for (const Graphic3d_ClipPlane* aSubPlaneIter = aPlane.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get()) + { + addClippingPlane (aPlaneId, *aSubPlaneIter, aSubPlaneIter->GetEquation(), aSubPlaneIter->NbChainNextPlanes()); + } } - ++aPlaneId; } + theProgram->SetUniform (myContext, theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_COUNT), aPlaneId); theProgram->SetUniform (myContext, aLocEquations, aNbClipPlanesMax, &myClipPlaneArray.First()); + theProgram->SetUniform (myContext, theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_CHAINS), aNbClipPlanesMax, &myClipChainArray.First()); } // ======================================================================= @@ -1532,12 +1600,16 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha else if ((theBits & OpenGl_PO_ClipPlanes2) != 0) { aNbClipPlanes = 2; - aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2; + aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0 + ? THE_FRAG_CLIP_CHAINS_2 + : THE_FRAG_CLIP_PLANES_2; } else { aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT; - aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N; + aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0 + ? THE_FRAG_CLIP_CHAINS_N + : THE_FRAG_CLIP_PLANES_N; } } if ((theBits & OpenGl_PO_WriteOit) != 0) @@ -1895,12 +1967,16 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S else if ((theBits & OpenGl_PO_ClipPlanes2) != 0) { aNbClipPlanes = 2; - aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2; + aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0 + ? THE_FRAG_CLIP_CHAINS_2 + : THE_FRAG_CLIP_PLANES_2; } else { aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT; - aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N; + aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0 + ? THE_FRAG_CLIP_CHAINS_N + : THE_FRAG_CLIP_PLANES_N; } } if ((theBits & OpenGl_PO_WriteOit) != 0) @@ -2054,12 +2130,16 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha else if ((theBits & OpenGl_PO_ClipPlanes2) != 0) { aNbClipPlanes = 2; - aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2; + aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0 + ? THE_FRAG_CLIP_CHAINS_2 + : THE_FRAG_CLIP_PLANES_2; } else { aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT; - aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N; + aSrcFragExtraMain += (theBits & OpenGl_PO_ClipChains) != 0 + ? THE_FRAG_CLIP_CHAINS_N + : THE_FRAG_CLIP_PLANES_N; } } if ((theBits & OpenGl_PO_WriteOit) != 0) diff --git a/src/OpenGl/OpenGl_ShaderManager.hxx b/src/OpenGl/OpenGl_ShaderManager.hxx index 7c423e0066..4cc836428f 100644 --- a/src/OpenGl/OpenGl_ShaderManager.hxx +++ b/src/OpenGl/OpenGl_ShaderManager.hxx @@ -414,6 +414,11 @@ protected: if (aNbPlanes > 0) { aBits |= OpenGl_PO_ClipPlanesN; + if (myContext->Clipping().HasClippingChains()) + { + aBits |= OpenGl_PO_ClipChains; + } + if (aNbPlanes == 1) { aBits |= OpenGl_PO_ClipPlanes1; @@ -568,6 +573,29 @@ protected: OpenGl_ShaderProgramFFP() {} }; +protected: + + //! Append clipping plane definition to temporary buffers. + void addClippingPlane (Standard_Integer& thePlaneId, + const Graphic3d_ClipPlane& thePlane, + const Graphic3d_Vec4d& theEq, + const Standard_Integer theChainFwd) const + { + myClipChainArray.SetValue (thePlaneId, theChainFwd); + OpenGl_Vec4& aPlaneEq = myClipPlaneArray.ChangeValue (thePlaneId); + aPlaneEq.x() = float(theEq.x()); + aPlaneEq.y() = float(theEq.y()); + aPlaneEq.z() = float(theEq.z()); + aPlaneEq.w() = float(theEq.w()); + if (myHasLocalOrigin) + { + const gp_XYZ aPos = thePlane.ToPlane().Position().Location().XYZ() - myLocalOrigin; + const Standard_Real aD = -(theEq.x() * aPos.X() + theEq.y() * aPos.Y() + theEq.z() * aPos.Z()); + aPlaneEq.w() = float(aD); + } + ++thePlaneId; + } + protected: Handle(OpenGl_ShaderProgramFFP) myFfpProgram; @@ -602,6 +630,7 @@ protected: mutable NCollection_Array1 myLightParamsArray; mutable NCollection_Array1 myClipPlaneArray; mutable NCollection_Array1 myClipPlaneArrayFfp; + mutable NCollection_Array1 myClipChainArray; private: diff --git a/src/OpenGl/OpenGl_ShaderProgram.cxx b/src/OpenGl/OpenGl_ShaderProgram.cxx index 784dc528ab..3b2bb563c2 100755 --- a/src/OpenGl/OpenGl_ShaderProgram.cxx +++ b/src/OpenGl/OpenGl_ShaderProgram.cxx @@ -56,6 +56,7 @@ Standard_CString OpenGl_ShaderProgram::PredefinedKeywords[] = "occProjectionMatrixInverseTranspose", // OpenGl_OCC_PROJECTION_MATRIX_INVERSE_TRANSPOSE "occClipPlaneEquations", // OpenGl_OCC_CLIP_PLANE_EQUATIONS + "occClipPlaneChains", // OpenGl_OCC_CLIP_PLANE_CHAINS "occClipPlaneCount", // OpenGl_OCC_CLIP_PLANE_COUNT "occLightSourcesCount", // OpenGl_OCC_LIGHT_SOURCE_COUNT diff --git a/src/OpenGl/OpenGl_ShaderProgram.hxx b/src/OpenGl/OpenGl_ShaderProgram.hxx index 87941ff0b3..1f15f0133d 100755 --- a/src/OpenGl/OpenGl_ShaderProgram.hxx +++ b/src/OpenGl/OpenGl_ShaderProgram.hxx @@ -50,6 +50,7 @@ enum OpenGl_StateVariable // OpenGL clip planes state OpenGl_OCC_CLIP_PLANE_EQUATIONS, + OpenGl_OCC_CLIP_PLANE_CHAINS, OpenGl_OCC_CLIP_PLANE_COUNT, // OpenGL light state @@ -224,7 +225,7 @@ public: Standard_Integer NbLightsMax() const { return myNbLightsMax; } //! Return the length of array of clipping planes (THE_MAX_CLIP_PLANES), - //! to be used for initialization occClipPlaneEquations (OpenGl_OCC_CLIP_PLANE_EQUATIONS). + //! to be used for initialization occClipPlaneEquations (OpenGl_OCC_CLIP_PLANE_EQUATIONS) and occClipPlaneChains (OpenGl_OCC_CLIP_PLANE_CHAINS). Standard_Integer NbClipPlanesMax() const { return myNbClipPlanesMax; } //! Return the length of array of Fragment Shader outputs (THE_NB_FRAG_OUTPUTS), diff --git a/src/OpenGl/OpenGl_Structure.cxx b/src/OpenGl/OpenGl_Structure.cxx index 60b5aec151..34870a57c4 100644 --- a/src/OpenGl/OpenGl_Structure.cxx +++ b/src/OpenGl/OpenGl_Structure.cxx @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -24,9 +25,6 @@ #include #include -#include - - IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Structure,Graphic3d_CStructure) //! Auxiliary class for bounding box presentation @@ -551,7 +549,7 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con } // Collect clipping planes of structure scope - aCtx->ChangeClipping().SetLocalPlanes (aCtx, myClipPlanes); + aCtx->ChangeClipping().SetLocalPlanes (myClipPlanes); // True if structure is fully clipped bool isClipped = false; @@ -562,7 +560,7 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con if (!myClipPlanes.IsNull() && myClipPlanes->ToOverrideGlobal()) { - aCtx->ChangeClipping().DisableGlobal (aCtx); + aCtx->ChangeClipping().DisableGlobal(); hasDisabled = aCtx->Clipping().HasDisabled(); } else if (!myTrsfPers.IsNull()) @@ -583,9 +581,8 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con } // check for clipping - const Graphic3d_Vec4d& aPlaneEquation = aPlane->GetEquation(); const Graphic3d_Vec4d aCheckPnt (anAnchor.X(), anAnchor.Y(), anAnchor.Z(), 1.0); - if (aPlaneEquation.Dot (aCheckPnt) < 0.0) // vertex is outside the half-space + if (aPlane->ProbePoint (aCheckPnt) == Graphic3d_ClipState_Out) { isClipped = true; break; @@ -593,7 +590,7 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con } } - aCtx->ChangeClipping().DisableGlobal (aCtx); + aCtx->ChangeClipping().DisableGlobal(); hasDisabled = aCtx->Clipping().HasDisabled(); } @@ -610,26 +607,15 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con continue; } - // check for clipping - const Graphic3d_Vec4d& aPlaneEquation = aPlane->GetEquation(); - const Graphic3d_Vec4d aMaxPnt (aPlaneEquation.x() > 0.0 ? aBBox.CornerMax().x() : aBBox.CornerMin().x(), - aPlaneEquation.y() > 0.0 ? aBBox.CornerMax().y() : aBBox.CornerMin().y(), - aPlaneEquation.z() > 0.0 ? aBBox.CornerMax().z() : aBBox.CornerMin().z(), - 1.0); - if (aPlaneEquation.Dot (aMaxPnt) < 0.0) // max vertex is outside the half-space + const Graphic3d_ClipState aBoxState = aPlane->ProbeBox (aBBox); + if (aBoxState == Graphic3d_ClipState_Out) { isClipped = true; break; } - - // check for no intersection (e.g. object is "entirely not clipped") - const Graphic3d_Vec4d aMinPnt (aPlaneEquation.x() > 0.0 ? aBBox.CornerMin().x() : aBBox.CornerMax().x(), - aPlaneEquation.y() > 0.0 ? aBBox.CornerMin().y() : aBBox.CornerMax().y(), - aPlaneEquation.z() > 0.0 ? aBBox.CornerMin().z() : aBBox.CornerMax().z(), - 1.0); - if (aPlaneEquation.Dot (aMinPnt) > 0.0) // min vertex is inside the half-space + else if (aBoxState == Graphic3d_ClipState_In) { - aCtx->ChangeClipping().SetEnabled (aCtx, aPlaneIt, Standard_False); + aCtx->ChangeClipping().SetEnabled (aPlaneIt, false); hasDisabled = true; } } @@ -667,9 +653,9 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con if (hasDisabled) { // enable planes that were previously disabled - aCtx->ChangeClipping().RestoreDisabled (aCtx); + aCtx->ChangeClipping().RestoreDisabled(); } - aCtx->ChangeClipping().SetLocalPlanes (aCtx, Handle(Graphic3d_SequenceOfHClipPlane)()); + aCtx->ChangeClipping().SetLocalPlanes (Handle(Graphic3d_SequenceOfHClipPlane)()); if ((!myClipPlanes.IsNull() && !myClipPlanes->IsEmpty()) || hasDisabled) { diff --git a/src/OpenGl/OpenGl_View_Redraw.cxx b/src/OpenGl/OpenGl_View_Redraw.cxx index d499839e4d..247e44fac0 100644 --- a/src/OpenGl/OpenGl_View_Redraw.cxx +++ b/src/OpenGl/OpenGl_View_Redraw.cxx @@ -1205,7 +1205,7 @@ void OpenGl_View::renderScene (Graphic3d_Camera::Projection theProjection, const Handle(OpenGl_Context)& aContext = myWorkspace->GetGlContext(); // Specify clipping planes in view transformation space - aContext->ChangeClipping().Reset (aContext, myClipPlanes); + aContext->ChangeClipping().Reset (myClipPlanes); if (!myClipPlanes.IsNull() && !myClipPlanes->IsEmpty()) { @@ -1218,7 +1218,7 @@ void OpenGl_View::renderScene (Graphic3d_Camera::Projection theProjection, // Apply restored view matrix. aContext->ApplyWorldViewMatrix(); - aContext->ChangeClipping().Reset (aContext, Handle(Graphic3d_SequenceOfHClipPlane)()); + aContext->ChangeClipping().Reset (Handle(Graphic3d_SequenceOfHClipPlane)()); if (!myClipPlanes.IsNull() && !myClipPlanes->IsEmpty()) { diff --git a/src/OpenGl/OpenGl_Workspace.cxx b/src/OpenGl/OpenGl_Workspace.cxx index 8c14002d09..37060f3f41 100644 --- a/src/OpenGl/OpenGl_Workspace.cxx +++ b/src/OpenGl/OpenGl_Workspace.cxx @@ -280,20 +280,12 @@ const OpenGl_AspectFace* OpenGl_Workspace::ApplyAspectFace() { if (myView->BackfacingModel() == Graphic3d_TOBM_AUTOMATIC) { - // manage back face culling mode, disable culling when clipping is enabled bool toSuppressBackFaces = myToAllowFaceCulling && myAspectFaceSet->Aspect()->ToSuppressBackFaces(); if (toSuppressBackFaces) { - if (myGlContext->Clipping().IsClippingOrCappingOn() - || myAspectFaceSet->Aspect()->InteriorStyle() == Aspect_IS_HATCH) - { - toSuppressBackFaces = false; - } - } - if (toSuppressBackFaces) - { - if (myAspectFaceSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_Blend + if (myAspectFaceSet->Aspect()->InteriorStyle() == Aspect_IS_HATCH + || myAspectFaceSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_Blend || myAspectFaceSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_Mask || (myAspectFaceSet->Aspect()->AlphaMode() == Graphic3d_AlphaMode_BlendAuto && myAspectFaceSet->Aspect()->FrontMaterial().Transparency() != 0.0f)) diff --git a/src/OpenGl/OpenGl_Workspace.hxx b/src/OpenGl/OpenGl_Workspace.hxx index 4a3e602471..7645942a51 100644 --- a/src/OpenGl/OpenGl_Workspace.hxx +++ b/src/OpenGl/OpenGl_Workspace.hxx @@ -122,7 +122,7 @@ public: //! @return true if depth writing is enabled. Standard_Boolean& UseDepthWrite() { return myUseDepthWrite; } - //! @return true if clipping algorithm enabled + //! @return true if frustum culling algorithm is enabled Standard_EXPORT Standard_Boolean IsCullingEnabled() const; //// RELATED TO STATUS //// @@ -133,7 +133,12 @@ public: //! Allow or disallow face culling. //! This call does NOT affect current state of back face culling; //! ApplyAspectFace() should be called to update state. - void SetAllowFaceCulling (bool theToAllow) { myToAllowFaceCulling = theToAllow; } + bool SetAllowFaceCulling (bool theToAllow) + { + const bool wasAllowed = myToAllowFaceCulling; + myToAllowFaceCulling = theToAllow; + return wasAllowed; + } //! Return true if following structures should apply highlight color. bool ToHighlight() const { return !myHighlightStyle.IsNull(); } diff --git a/src/Select3D/Select3D_SensitivePrimitiveArray.hxx b/src/Select3D/Select3D_SensitivePrimitiveArray.hxx index 653a3f93c4..599ff826ec 100644 --- a/src/Select3D/Select3D_SensitivePrimitiveArray.hxx +++ b/src/Select3D/Select3D_SensitivePrimitiveArray.hxx @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/src/SelectMgr/SelectMgr_RectangularFrustum.cxx b/src/SelectMgr/SelectMgr_RectangularFrustum.cxx index d191a41efc..7bcd65c840 100644 --- a/src/SelectMgr/SelectMgr_RectangularFrustum.cxx +++ b/src/SelectMgr/SelectMgr_RectangularFrustum.cxx @@ -276,7 +276,7 @@ void SelectMgr_RectangularFrustum::Build (const gp_Pnt2d &thePoint) // {i, j, k} vectors and store them to corresponding class fields cacheVertexProjections (this); - myViewClipRange.Clear(); + myViewClipRange.SetVoid(); myScale = 1.0; } @@ -306,7 +306,7 @@ void SelectMgr_RectangularFrustum::Build (const gp_Pnt2d& theMinPnt, // {i, j, k} vectors and store them to corresponding class fields cacheVertexProjections (this); - myViewClipRange.Clear(); + myViewClipRange.SetVoid(); myScale = 1.0; } @@ -645,53 +645,74 @@ gp_Pnt SelectMgr_RectangularFrustum::DetectedPoint (const Standard_Real theDepth // purpose : // ======================================================================= void SelectMgr_RectangularFrustum::computeClippingRange (const Graphic3d_SequenceOfHClipPlane& thePlanes, - Standard_Real& theDepthMin, - Standard_Real& theDepthMax) + SelectMgr_ViewClipRange& theRange) { - theDepthMax = DBL_MAX; - theDepthMin = -DBL_MAX; Standard_Real aPlaneA, aPlaneB, aPlaneC, aPlaneD; for (Graphic3d_SequenceOfHClipPlane::Iterator aPlaneIt (thePlanes); aPlaneIt.More(); aPlaneIt.Next()) { const Handle(Graphic3d_ClipPlane)& aClipPlane = aPlaneIt.Value(); if (!aClipPlane->IsOn()) - continue; - - gp_Pln aGeomPlane = aClipPlane->ToPlane(); - - aGeomPlane.Coefficients (aPlaneA, aPlaneB, aPlaneC, aPlaneD); - - const gp_XYZ& aPlaneDirXYZ = aGeomPlane.Axis().Direction().XYZ(); - - Standard_Real aDotProduct = myViewRayDir.XYZ ().Dot (aPlaneDirXYZ); - Standard_Real aDistance = - myNearPickedPnt.XYZ ().Dot (aPlaneDirXYZ) - - aPlaneD; - - // check whether the pick line is parallel to clip plane - if (Abs (aDotProduct) < Precision::Angular()) { - // line lies below the plane and is not clipped, skip continue; } - // compute distance to point of pick line intersection with the plane - const Standard_Real aParam = aDistance / aDotProduct; - const gp_Pnt anIntersectionPt = myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * aParam; - Standard_Real aDistToPln = anIntersectionPt.Distance (myNearPickedPnt); - if (aParam < 0.0) + Bnd_Range aSubRange (RealFirst(), RealLast()); + for (const Graphic3d_ClipPlane* aSubPlaneIter = aClipPlane.get(); aSubPlaneIter != NULL; aSubPlaneIter = aSubPlaneIter->ChainNextPlane().get()) { - // the plane is "behind" the ray - aDistToPln = -aDistToPln; + const gp_Pln aGeomPlane = aSubPlaneIter->ToPlane(); + aGeomPlane.Coefficients (aPlaneA, aPlaneB, aPlaneC, aPlaneD); + + const gp_XYZ& aPlaneDirXYZ = aGeomPlane.Axis().Direction().XYZ(); + Standard_Real aDotProduct = myViewRayDir.XYZ().Dot (aPlaneDirXYZ); + Standard_Real aDistance = -myNearPickedPnt.XYZ().Dot (aPlaneDirXYZ) - aPlaneD; + + // check whether the pick line is parallel to clip plane + if (Abs (aDotProduct) < Precision::Angular()) + { + // line lies below the plane and is not clipped, skip + continue; + } + + // compute distance to point of pick line intersection with the plane + const Standard_Real aParam = aDistance / aDotProduct; + + const gp_Pnt anIntersectionPnt = myNearPickedPnt.XYZ() + myViewRayDir.XYZ() * aParam; + Standard_Real aDistToPln = anIntersectionPnt.Distance (myNearPickedPnt); + if (aParam < 0.0) + { + // the plane is "behind" the ray + aDistToPln = -aDistToPln; + } + + // change depth limits for case of opposite and directed planes + if (!aClipPlane->IsChain()) + { + if (aDotProduct < 0.0) + { + theRange.ChangeMain().Add (Bnd_Range (aDistToPln, RealLast())); + } + else + { + theRange.ChangeMain().Add (Bnd_Range (RealFirst(), aDistToPln)); + } + } + else + { + if (aDotProduct < 0.0) + { + aSubRange.TrimFrom (aDistToPln); + } + else + { + aSubRange.TrimTo (aDistToPln); + } + } } - // change depth limits for case of opposite and directed planes - if (aDotProduct < 0.0) + if (!aSubRange.IsVoid() + && aClipPlane->IsChain()) { - theDepthMax = Min (aDistToPln, theDepthMax); - } - else if (aDistToPln > theDepthMin) - { - theDepthMin = Max (aDistToPln, theDepthMin); + theRange.AddSubRange (aSubRange); } } } @@ -704,10 +725,9 @@ void SelectMgr_RectangularFrustum::computeClippingRange (const Graphic3d_Sequenc Standard_Boolean SelectMgr_RectangularFrustum::IsClipped (const Graphic3d_SequenceOfHClipPlane& thePlanes, const Standard_Real theDepth) { - Standard_Real aMaxDepth, aMinDepth; - computeClippingRange (thePlanes, aMinDepth, aMaxDepth); - - return (theDepth <= aMinDepth || theDepth >= aMaxDepth); + SelectMgr_ViewClipRange aRange; + computeClippingRange (thePlanes, aRange); + return aRange.IsClipped (theDepth); } // ======================================================================= @@ -719,13 +739,11 @@ void SelectMgr_RectangularFrustum::SetViewClipping (const Handle(Graphic3d_Seque if (thePlanes.IsNull() || thePlanes->IsEmpty()) { - myViewClipRange.Clear(); + myViewClipRange.SetVoid(); return; } - Standard_Real aMaxDepth, aMinDepth; - computeClippingRange (*thePlanes, aMinDepth, aMaxDepth); - myViewClipRange.Set (aMinDepth, aMaxDepth); + computeClippingRange (*thePlanes, myViewClipRange); } // ======================================================================= @@ -734,14 +752,8 @@ void SelectMgr_RectangularFrustum::SetViewClipping (const Handle(Graphic3d_Seque // ======================================================================= Standard_Boolean SelectMgr_RectangularFrustum::isViewClippingOk (const Standard_Real theDepth) const { - if (!myViewClipRange.IsValid() - || !myIsViewClipEnabled) - { - return Standard_True; - } - - return myViewClipRange.MaxDepth() > theDepth - && myViewClipRange.MinDepth() < theDepth; + return !myIsViewClipEnabled + || !myViewClipRange.IsClipped (theDepth); } // ======================================================================= diff --git a/src/SelectMgr/SelectMgr_RectangularFrustum.hxx b/src/SelectMgr/SelectMgr_RectangularFrustum.hxx index 4c9276adb3..5d5713a088 100644 --- a/src/SelectMgr/SelectMgr_RectangularFrustum.hxx +++ b/src/SelectMgr/SelectMgr_RectangularFrustum.hxx @@ -149,8 +149,7 @@ protected: //! Computes valid depth range for the given clipping planes Standard_EXPORT void computeClippingRange (const Graphic3d_SequenceOfHClipPlane& thePlanes, - Standard_Real& theDepthMin, - Standard_Real& theDepthMax); + SelectMgr_ViewClipRange& theRange); //! Returns false if theDepth must be clipped by current view clip range Standard_EXPORT Standard_Boolean isViewClippingOk (const Standard_Real theDepth) const; diff --git a/src/SelectMgr/SelectMgr_ViewClipRange.hxx b/src/SelectMgr/SelectMgr_ViewClipRange.hxx index 7fc0931aae..77abb97129 100644 --- a/src/SelectMgr/SelectMgr_ViewClipRange.hxx +++ b/src/SelectMgr/SelectMgr_ViewClipRange.hxx @@ -16,58 +16,52 @@ #ifndef _SelectMgr_ViewClipRange_HeaderFile #define _SelectMgr_ViewClipRange_HeaderFile +#include #include //! Class for handling depth clipping range. //! It is used to perform checks in case if global (for the whole view) -//! clipping planes are defined inside of SelectMgr_RectangularFrustum -//! class methods. +//! clipping planes are defined inside of SelectMgr_RectangularFrustum class methods. class SelectMgr_ViewClipRange { public: - //! Creates new empty view clip range + //! Creates an empty clip range. SelectMgr_ViewClipRange() { - Clear(); + SetVoid(); } - //! Sets boundaries and validates view clipping range - void Set (const Standard_Real theDepthMin, const Standard_Real theDepthMax) + //! Check if the given depth is not within clipping range(s), + //! e.g. TRUE means depth is clipped. + Standard_Boolean IsClipped (const Standard_Real theDepth) const { - myMin = theDepthMin; - myMax = theDepthMax; - myIsValid = Standard_True; + for (size_t aRangeIter = 0; aRangeIter < myRanges.size(); ++aRangeIter) + { + if (!myRanges[aRangeIter].IsOut (theDepth)) + { + return Standard_True; + } + } + return Standard_False; } - //! Returns true if clip range is set and depth of each matched - //! primitive must be tested for satisfying the defined interval - Standard_Boolean IsValid() const + //! Clears clipping range. + void SetVoid() { - return myIsValid; + myRanges.resize (1); + myRanges[0].SetVoid(); } - //! Returns the upper bound of valid depth range - Standard_Real MaxDepth() const - { - return myMax; - } + //! Returns the main range. + Bnd_Range& ChangeMain() { return myRanges[0]; } - //! Returns the lower bound of valid depth range - Standard_Real MinDepth() const - { - return myMin; - } - - //! Invalidates view clipping range - void Clear() - { - myIsValid = Standard_False; - } + //! Adds a sub-range. + void AddSubRange (const Bnd_Range& theRange) { myRanges.push_back (theRange); } private: - Standard_Real myMin; //!< Lower bound of valid depth range - Standard_Real myMax; //!< Upper bound of valid depth range - Standard_Boolean myIsValid; //!< The flag is set to true when range boundaries are set and depth check must be performed + + std::vector myRanges; + }; #endif // _SelectMgr_ViewClipRange_HeaderFile diff --git a/src/SelectMgr/SelectMgr_ViewerSelector.cxx b/src/SelectMgr/SelectMgr_ViewerSelector.cxx index a555ab7cb2..4bfe074572 100644 --- a/src/SelectMgr/SelectMgr_ViewerSelector.cxx +++ b/src/SelectMgr/SelectMgr_ViewerSelector.cxx @@ -225,9 +225,8 @@ void SelectMgr_ViewerSelector::checkOverlap (const Handle(SelectBasics_Sensitive continue; } - const Graphic3d_Vec4d& aPlaneEquation = aPlane->GetEquation(); - const Graphic3d_Vec4d aCheckPnt (anAnchor.X(), anAnchor.Y(), anAnchor.Z(), 1.0); - if (aPlaneEquation.Dot (aCheckPnt) < 0.0) // vertex is outside the half-space + const Graphic3d_Vec4d aCheckPnt (anAnchor.X(), anAnchor.Y(), anAnchor.Z(), 1.0); + if (aPlane->ProbePoint (aCheckPnt) == Graphic3d_ClipState_Out) { return; } diff --git a/src/Shaders/Declarations.glsl b/src/Shaders/Declarations.glsl index a3b7e12d29..5cd1ef046e 100644 --- a/src/Shaders/Declarations.glsl +++ b/src/Shaders/Declarations.glsl @@ -173,5 +173,6 @@ uniform float occAlphaCutoff; //!< alpha test cutoff value //! Parameters of clipping planes #if defined(THE_MAX_CLIP_PLANES) && (THE_MAX_CLIP_PLANES > 0) uniform vec4 occClipPlaneEquations[THE_MAX_CLIP_PLANES]; +uniform THE_PREC_ENUM int occClipPlaneChains[THE_MAX_CLIP_PLANES]; //! Indicating the number of planes in the Chain uniform THE_PREC_ENUM int occClipPlaneCount; //!< Total number of clip planes #endif diff --git a/src/Shaders/Shaders_Declarations_glsl.pxx b/src/Shaders/Shaders_Declarations_glsl.pxx index ed3045e3b9..74663c4098 100644 --- a/src/Shaders/Shaders_Declarations_glsl.pxx +++ b/src/Shaders/Shaders_Declarations_glsl.pxx @@ -176,5 +176,6 @@ static const char Shaders_Declarations_glsl[] = "//! Parameters of clipping planes\n" "#if defined(THE_MAX_CLIP_PLANES) && (THE_MAX_CLIP_PLANES > 0)\n" "uniform vec4 occClipPlaneEquations[THE_MAX_CLIP_PLANES];\n" + "uniform THE_PREC_ENUM int occClipPlaneChains[THE_MAX_CLIP_PLANES]; //! Indicating the number of planes in the Chain\n" "uniform THE_PREC_ENUM int occClipPlaneCount; //!< Total number of clip planes\n" "#endif\n"; diff --git a/src/ViewerTest/ViewerTest.cxx b/src/ViewerTest/ViewerTest.cxx index 6f53cd3ada..b04a299242 100644 --- a/src/ViewerTest/ViewerTest.cxx +++ b/src/ViewerTest/ViewerTest.cxx @@ -2626,8 +2626,13 @@ static Standard_Integer VAspects (Draw_Interpretor& /*theDI*/, for (ViewTest_PrsIter aPrsIter (aNames); aPrsIter.More(); aPrsIter.Next()) { - const TCollection_AsciiString& aName = aPrsIter.CurrentName(); - Handle(AIS_InteractiveObject) aPrs = aPrsIter.Current(); + const TCollection_AsciiString& aName = aPrsIter.CurrentName(); + Handle(AIS_InteractiveObject) aPrs = aPrsIter.Current(); + if (aPrs.IsNull()) + { + return 1; + } + Handle(Prs3d_Drawer) aDrawer = aPrs->Attributes(); Handle(AIS_ColoredShape) aColoredPrs; Standard_Boolean toDisplay = Standard_False; diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 94a66bfb9f..a4304262d9 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -8375,8 +8375,8 @@ static int VClipPlane (Draw_Interpretor& theDi, Standard_Integer theArgsNb, cons { aClipPlane->SetOn (toEnable); } - else if (aChangeArg == "-equation" - || aChangeArg == "equation") + else if (aChangeArg.StartsWith ("-equation") + || aChangeArg.StartsWith ("equation")) { if (aNbChangeArgs < 5) { @@ -8384,13 +8384,74 @@ static int VClipPlane (Draw_Interpretor& theDi, Standard_Integer theArgsNb, cons return 1; } - Standard_Real aCoeffA = Draw::Atof (aChangeArgs [1]); - Standard_Real aCoeffB = Draw::Atof (aChangeArgs [2]); - Standard_Real aCoeffC = Draw::Atof (aChangeArgs [3]); - Standard_Real aCoeffD = Draw::Atof (aChangeArgs [4]); - aClipPlane->SetEquation (gp_Pln (aCoeffA, aCoeffB, aCoeffC, aCoeffD)); + Standard_Integer aSubIndex = 1; + Standard_Integer aPrefixLen = 8 + (aChangeArg.Value (1) == '-' ? 1 : 0); + if (aPrefixLen < aChangeArg.Length()) + { + TCollection_AsciiString aSubStr = aChangeArg.SubString (aPrefixLen + 1, aChangeArg.Length()); + if (!aSubStr.IsIntegerValue() + || aSubStr.IntegerValue() <= 0) + { + std::cout << "Syntax error: unknown argument '" << aChangeArg << "'.\n"; + return 1; + } + aSubIndex = aSubStr.IntegerValue(); + } + + Standard_Real aCoeffA = Draw::Atof (aChangeArgs[1]); + Standard_Real aCoeffB = Draw::Atof (aChangeArgs[2]); + Standard_Real aCoeffC = Draw::Atof (aChangeArgs[3]); + Standard_Real aCoeffD = Draw::Atof (aChangeArgs[4]); + Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane; + for (Standard_Integer aSubPlaneIter = 1; aSubPlaneIter < aSubIndex; ++aSubPlaneIter) + { + if (aSubPln->ChainNextPlane().IsNull()) + { + aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln)); + } + aSubPln = aSubPln->ChainNextPlane(); + } + aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)()); + aSubPln->SetEquation (gp_Pln (aCoeffA, aCoeffB, aCoeffC, aCoeffD)); anArgIter += 4; } + else if ((aChangeArg == "-boxinterior" + || aChangeArg == "-boxint" + || aChangeArg == "-box") + && aNbChangeArgs >= 7) + { + Graphic3d_BndBox3d aBndBox; + aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[1]), Draw::Atof (aChangeArgs[2]), Draw::Atof (aChangeArgs[3]))); + aBndBox.Add (Graphic3d_Vec3d (Draw::Atof (aChangeArgs[4]), Draw::Atof (aChangeArgs[5]), Draw::Atof (aChangeArgs[6]))); + anArgIter += 6; + + Standard_Integer aNbSubPlanes = 6; + const Graphic3d_Vec3d aDirArray[6] = + { + Graphic3d_Vec3d (-1, 0, 0), + Graphic3d_Vec3d ( 1, 0, 0), + Graphic3d_Vec3d ( 0,-1, 0), + Graphic3d_Vec3d ( 0, 1, 0), + Graphic3d_Vec3d ( 0, 0,-1), + Graphic3d_Vec3d ( 0, 0, 1), + }; + Handle(Graphic3d_ClipPlane) aSubPln = aClipPlane; + for (Standard_Integer aSubPlaneIter = 0; aSubPlaneIter < aNbSubPlanes; ++aSubPlaneIter) + { + const Graphic3d_Vec3d& aDir = aDirArray[aSubPlaneIter]; + const Standard_Real aW = -aDir.Dot ((aSubPlaneIter % 2 == 1) ? aBndBox.CornerMax() : aBndBox.CornerMin()); + aSubPln->SetEquation (gp_Pln (aDir.x(), aDir.y(), aDir.z(), aW)); + if (aSubPlaneIter + 1 == aNbSubPlanes) + { + aSubPln->SetChainNextPlane (Handle(Graphic3d_ClipPlane)()); + } + else + { + aSubPln->SetChainNextPlane (new Graphic3d_ClipPlane (*aSubPln)); + } + aSubPln = aSubPln->ChainNextPlane(); + } + } else if (aChangeArg == "-capping" || aChangeArg == "capping") { @@ -12300,7 +12361,9 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands) __FILE__,VHLRType,group); theCommands.Add("vclipplane", "vclipplane planeName [{0|1}]" - "\n\t\t: [-equation A B C D]" + "\n\t\t: [-equation1 A B C D]" + "\n\t\t: [-equation2 A B C D]" + "\n\t\t: [-boxInterior MinX MinY MinZ MaxX MaxY MaxZ]" "\n\t\t: [-set|-unset|-setOverrideGlobal [objects|views]]" "\n\t\t: [-maxPlanes]" "\n\t\t: [-capping {0|1}]" diff --git a/tests/bugs/vis/bug25052 b/tests/bugs/vis/bug25052 index 966059e72a..cd53b6343f 100644 --- a/tests/bugs/vis/bug25052 +++ b/tests/bugs/vis/bug25052 @@ -1,10 +1,8 @@ +puts "REQUIRED All: Error: clipping planes limit" puts "===========" -puts "OCC25052" +puts "OCC25052: Visualization - activation of all Clipping Planes within driver limit leads to broken planes management" puts "===========" puts "" -########################################################################## -# Visualization - activation of all Clipping Planes within driver limit leads to broken planes management -########################################################################## set Image1 ${imagedir}/${casename}_1.png set Image9 ${imagedir}/${casename}_9.png diff --git a/tests/v3d/glsl/clipping1 b/tests/v3d/glsl/clipping1 new file mode 100644 index 0000000000..126b99b85d --- /dev/null +++ b/tests/v3d/glsl/clipping1 @@ -0,0 +1,91 @@ +puts "========" +puts "0029729: Visualization, Graphic3d_ClipPlane - add support of clipping plane chains" +puts "========" + +vclear +vclose ALL +vinit View1 + +set aCapParams "-capping 1 -color 0.5 0.5 0.5 -texname [locate_data_file images/hatch_1.png] -texscale 0.02 -0.02 -useObjMaterial 1" + +pload MODELING VISUALIZATION + +# create the geometry +box b0sole 10 10 0 30 30 70 +box b0hole 20 20 -10 10 10 90 +bcut b0 b0sole b0hole +box b1 40 20 0 10 30 70 +box b2 20 40 0 20 10 70 +box b3 0 40 0 20 10 70 +box b4 0 10 0 10 30 70 +box b5 0 0 0 30 10 70 + +set aNbParts 6 +set aColors { RED YELLOW GREEN GRAY MAGENTA1 ORANGE } + +compound b0 b1 b2 b3 b4 b5 cc + +# create the viewer +vclear +vclose ALL +vinit name=View1 w=512 h=512 +vviewparams -scale 4.66737 -proj 0.465292 -0.577133 0.671134 -up -0.46873 0.482524 0.739907 -at 15.807 37.1157 21.9799 + +vpoint p0 0 0 0 +vzbufftrihedron + +puts "Display the geometry as dedicated objects" +for { set aPartIter 0 } { $aPartIter < $aNbParts } { incr aPartIter } { + vdisplay -noupdate -dispMode 1 b${aPartIter} + set aColor [lindex $aColors $aPartIter] + vsetcolor -noupdate b${aPartIter} $aColor +} + +puts "Display the geometry as sole object" +vdisplay -noupdate -dispMode 1 cc +for { set aPartIter 0 } { $aPartIter < $aNbParts } { incr aPartIter } { + set aColor [lindex $aColors $aPartIter] + vaspects -noupdate cc -subShapes b${aPartIter} -setColor $aColor +} +# show also connected interactive object +vconnectto co -70 0 0 cc +vsetdispmode co 1 +vsetlocation cc 70 0 0 + +set aPln1Z 40 +set aPln2Y 15 + +vremove -noupdate p1 p2 p3 pp1 pp2 +vpoint p1 0 0 1 +vpoint p2 1 0 1 +vpoint p3 0 1 1 +vplane pp1 p1 p2 p3 +vsetlocation -noupdate pp1 25 0 [expr $aPln1Z - 1] +vremove -noupdate p1 p2 p3 + +vpoint p1 0 1 0 +vpoint p2 1 1 0 +vpoint p3 0 1 1 +vplane pp2 p1 p2 p3 +vsetlocation -noupdate pp2 25 $aPln2Y 35 +vremove -noupdate p1 p2 p3 +verase pp1 pp2 +vfit +vdisplay pp1 pp2 + +vclipplane pln -set {*}$aCapParams -equation1 0 0 -1 40 -equation2 0 1 0 -15 +vdump $::imagedir/${::casename}_2.png + +vclipplane pln -set {*}$aCapParams -equation1 0 0 -1 40 -equation2 0 1 0 -15 -equation3 -1 0 0 5 +vdump $::imagedir/${::casename}_3.png + +vsettransparency b0 b1 b2 b3 b4 b5 0.5 +vdump $::imagedir/${::casename}_3transp.png + +vviewparams -scale 8.51584 -proj 0.284186 0.750426 0.59674 -up -0.228109 -0.55161 0.802305 -at 24.2647 23.8116 32.8743 +vclipplane pln -set {*}$aCapParams -boxint 25 25 25 55 55 55 +vsettransparency b0 b1 b2 b3 b4 b5 0 +vdump $::imagedir/${::casename}_6.png + +vsettransparency b0 b1 b2 b3 b4 b5 0.5 +vdump $::imagedir/${::casename}_6transp.png