diff --git a/src/InterfaceGraphic/InterfaceGraphic_telem.hxx b/src/InterfaceGraphic/InterfaceGraphic_telem.hxx index 77620bec88..b55025c647 100644 --- a/src/InterfaceGraphic/InterfaceGraphic_telem.hxx +++ b/src/InterfaceGraphic/InterfaceGraphic_telem.hxx @@ -44,10 +44,11 @@ struct TEL_COLOUR }; typedef TEL_COLOUR* tel_colour; -typedef enum +typedef enum { - TelCullNone, - TelCullFront, + TelCullUndefined = -1, + TelCullNone = 0, + TelCullFront, TelCullBack } TelCullMode; diff --git a/src/OpenGl/OpenGl_Clipping.cxx b/src/OpenGl/OpenGl_Clipping.cxx index 7cdaf5401b..aa27efa6df 100755 --- a/src/OpenGl/OpenGl_Clipping.cxx +++ b/src/OpenGl/OpenGl_Clipping.cxx @@ -27,9 +27,9 @@ namespace // purpose : // ======================================================================= OpenGl_Clipping::OpenGl_Clipping () -: myPlanes(), - myPlaneStates(), - myEmptyPlaneIds (new Aspect_GenId (GL_CLIP_PLANE0, GL_CLIP_PLANE5)) +: myEmptyPlaneIds (new Aspect_GenId (GL_CLIP_PLANE0, GL_CLIP_PLANE5)), + myNbClipping (0), + myNbCapping (0) {} // ======================================================================= @@ -40,6 +40,8 @@ void OpenGl_Clipping::Init (const Standard_Integer theMaxPlanes) { myPlanes.Clear(); myPlaneStates.Clear(); + myNbClipping = 0; + myNbCapping = 0; Standard_Integer aLowerId = GL_CLIP_PLANE0; Standard_Integer aUpperId = GL_CLIP_PLANE0 + theMaxPlanes - 1; myEmptyPlaneIds = new Aspect_GenId (aLowerId, aUpperId); @@ -104,6 +106,15 @@ void OpenGl_Clipping::Add (Graphic3d_SequenceOfHClipPlane& thePlanes, const Equa glEnable ((GLenum)anID); glClipPlane ((GLenum)anID, aPlane->GetEquation()); + if (aPlane->IsCapping()) + { + ++myNbCapping; + } + else + { + ++myNbClipping; + } + aPlaneIt.Next(); } @@ -129,10 +140,22 @@ void OpenGl_Clipping::Remove (const Graphic3d_SequenceOfHClipPlane& thePlanes) } Standard_Integer anID = myPlaneStates.Find (aPlane).ContextID; + PlaneProps& aProps = myPlaneStates.ChangeFind (aPlane); + if (aProps.IsEnabled) + { + glDisable ((GLenum)anID); + if (aPlane->IsCapping()) + { + --myNbCapping; + } + else + { + --myNbClipping; + } + } + myEmptyPlaneIds->Free (anID); myPlaneStates.UnBind (aPlane); - - glDisable ((GLenum)anID); } // renew collection of planes @@ -173,10 +196,26 @@ void OpenGl_Clipping::SetEnabled (const Handle(Graphic3d_ClipPlane)& thePlane, if (theIsEnabled) { glEnable (anID); + if (thePlane->IsCapping()) + { + ++myNbCapping; + } + else + { + ++myNbClipping; + } } else { glDisable (anID); + if (thePlane->IsCapping()) + { + --myNbCapping; + } + else + { + --myNbClipping; + } } aProps.IsEnabled = theIsEnabled; diff --git a/src/OpenGl/OpenGl_Clipping.hxx b/src/OpenGl/OpenGl_Clipping.hxx index df5b1a9bf4..a453192b07 100755 --- a/src/OpenGl/OpenGl_Clipping.hxx +++ b/src/OpenGl/OpenGl_Clipping.hxx @@ -81,6 +81,24 @@ public: //! @name non-modifying getters return myPlaneStates.Find (thePlane).IsEnabled; } + //! @return true if there are enabled clipping planes (NOT capping) + inline Standard_Boolean IsClippingOn() const + { + return myNbClipping > 0; + } + + //! @return true if there are enabled capping planes + inline Standard_Boolean IsCappingOn() const + { + return myNbCapping > 0; + } + + //! @return true if there are enabled clipping or capping planes + inline Standard_Boolean IsClippingOrCappingOn() const + { + return (myNbClipping + myNbCapping) > 0; + } + public: //! @name clipping state modification commands //! Add planes to the context clipping at the specified system of coordinates. @@ -198,9 +216,11 @@ private: typedef NCollection_DataMap OpenGl_MapOfPlaneStates; typedef NCollection_Handle OpenGl_EmptyPlaneIds; - Graphic3d_SequenceOfHClipPlane myPlanes; //!< defined clipping planes. - OpenGl_MapOfPlaneStates myPlaneStates; //!< map of clip planes bound for the props. - OpenGl_EmptyPlaneIds myEmptyPlaneIds; //!< generator of empty ids. + Graphic3d_SequenceOfHClipPlane myPlanes; //!< defined clipping planes + OpenGl_MapOfPlaneStates myPlaneStates; //!< map of clip planes bound for the props + OpenGl_EmptyPlaneIds myEmptyPlaneIds; //!< generator of empty ids + Standard_Boolean myNbClipping; //!< number of enabled clipping-only planes (NOT capping) + Standard_Boolean myNbCapping; //!< number of enabled capping planes private: diff --git a/src/OpenGl/OpenGl_Workspace.cxx b/src/OpenGl/OpenGl_Workspace.cxx index fd19037d13..593bbf5451 100644 --- a/src/OpenGl/OpenGl_Workspace.cxx +++ b/src/OpenGl/OpenGl_Workspace.cxx @@ -166,6 +166,7 @@ OpenGl_Workspace::OpenGl_Workspace (const Handle(OpenGl_Display)& theDisplay, TextParam_applied (NULL), ViewMatrix_applied (&myDefaultMatrix), StructureMatrix_applied (&myDefaultMatrix), + myCullingMode (TelCullUndefined), myModelViewMatrix (myDefaultMatrix), PolygonOffset_applied (NULL) { @@ -269,6 +270,7 @@ void OpenGl_Workspace::ResetAppliedAspect() TextParam_set = &myDefaultTextParam; TextParam_applied = NULL; PolygonOffset_applied = NULL; + myCullingMode = TelCullUndefined; AspectLine(Standard_True); AspectFace(Standard_True); diff --git a/src/OpenGl/OpenGl_Workspace.hxx b/src/OpenGl/OpenGl_Workspace.hxx index 696bff29a6..42002bbca3 100755 --- a/src/OpenGl/OpenGl_Workspace.hxx +++ b/src/OpenGl/OpenGl_Workspace.hxx @@ -439,9 +439,10 @@ protected: //! @name fields related to status const OpenGl_Matrix* ViewMatrix_applied; const OpenGl_Matrix* StructureMatrix_applied; - OpenGl_Material myMatFront; //!< current front material state (cached to reduce GL context updates) - OpenGl_Material myMatBack; //!< current back material state - OpenGl_Material myMatTmp; //!< temporary variable + OpenGl_Material myMatFront; //!< current front material state (cached to reduce GL context updates) + OpenGl_Material myMatBack; //!< current back material state + OpenGl_Material myMatTmp; //!< temporary variable + TelCullMode myCullingMode; //!< back face culling mode, applied from face aspect //! Model matrix with applied structure transformations OpenGl_Matrix myModelViewMatrix; diff --git a/src/OpenGl/OpenGl_Workspace_5.cxx b/src/OpenGl/OpenGl_Workspace_5.cxx index 29bb1fd005..6800eb6fb6 100644 --- a/src/OpenGl/OpenGl_Workspace_5.cxx +++ b/src/OpenGl/OpenGl_Workspace_5.cxx @@ -319,7 +319,55 @@ const OpenGl_AspectLine * OpenGl_Workspace::AspectLine(const Standard_Boolean Wi const OpenGl_AspectFace* OpenGl_Workspace::AspectFace (const Standard_Boolean theToApply) { - if (!theToApply || (AspectFace_set == AspectFace_applied)) + if (!theToApply) + { + return AspectFace_set; + } + + if (!ActiveView()->Backfacing()) + { + // manage back face culling mode, disable culling when clipping is enabled + TelCullMode aCullingMode = (myGlContext->Clipping().IsClippingOrCappingOn() + || AspectFace_set->InteriorStyle() == Aspect_IS_HATCH) + ? TelCullNone + : (TelCullMode )AspectFace_set->CullingMode(); + if (aCullingMode != TelCullNone + && myUseTransparency && !(NamedStatus & OPENGL_NS_2NDPASSDO)) + { + // disable culling in case of translucent shading aspect + if (AspectFace_set->IntFront().trans != 1.0f) + { + aCullingMode = TelCullNone; + } + } + if (myCullingMode != aCullingMode) + { + myCullingMode = aCullingMode; + switch (myCullingMode) + { + case TelCullNone: + case TelCullUndefined: + { + glDisable (GL_CULL_FACE); + break; + } + case TelCullFront: + { + glCullFace (GL_FRONT); + glEnable (GL_CULL_FACE); + break; + } + case TelCullBack: + { + glCullFace (GL_BACK); + glEnable (GL_CULL_FACE); + break; + } + } + } + } + + if (AspectFace_set == AspectFace_applied) { return AspectFace_set; } @@ -365,34 +413,6 @@ const OpenGl_AspectFace* OpenGl_Workspace::AspectFace (const Standard_Boolean th } } - if (!ActiveView()->Backfacing()) - { - const Tint aCullingMode = AspectFace_set->CullingMode(); - if (AspectFace_applied == NULL || AspectFace_applied->CullingMode() != aCullingMode) - { - switch ((TelCullMode )aCullingMode) - { - case TelCullNone: - { - glDisable (GL_CULL_FACE); - break; - } - case TelCullFront: - { - glCullFace (GL_FRONT); - glEnable (GL_CULL_FACE); - break; - } - case TelCullBack: - { - glCullFace (GL_BACK); - glEnable (GL_CULL_FACE); - break; - } - } - } - } - // Aspect_POM_None means: do not change current settings if ((AspectFace_set->PolygonOffset().mode & Aspect_POM_None) != Aspect_POM_None) { diff --git a/src/StdPrs/StdPrs_ShadedShape.cxx b/src/StdPrs/StdPrs_ShadedShape.cxx index 0304a8a93f..77100f9aa1 100644 --- a/src/StdPrs/StdPrs_ShadedShape.cxx +++ b/src/StdPrs/StdPrs_ShadedShape.cxx @@ -100,7 +100,7 @@ namespace Standard_Real aUmin (0.0), aUmax (0.0), aVmin (0.0), aVmax (0.0), dUmax (0.0), dVmax (0.0); // precision for compare square distances - const double aPreci = Precision::SquareConfusion(); + const Standard_Real aPreci = Precision::SquareConfusion(); if (!theDrawer->ShadingAspectGlobal()) { @@ -126,99 +126,102 @@ namespace nbVertices += T->NbNodes(); } } - - if (nbVertices > 2 && nbTriangles > 0) + if (nbVertices < 3 + || nbTriangles <= 0) { - Handle(Graphic3d_ArrayOfTriangles) aPArray - = new Graphic3d_ArrayOfTriangles (nbVertices, 3 * nbTriangles, - Standard_True, Standard_False, theHasTexels, Standard_True); - for (SST.Init (theShape); SST.MoreFace(); SST.NextFace()) + return Standard_False; + } + + Handle(Graphic3d_ArrayOfTriangles) aPArray + = new Graphic3d_ArrayOfTriangles (nbVertices, 3 * nbTriangles, + Standard_True, Standard_False, theHasTexels, Standard_True); + for (SST.Init (theShape); SST.MoreFace(); SST.NextFace()) + { + const TopoDS_Face& aFace = SST.CurrentFace(); + T = SST.Triangulation (aFace, aLoc); + if (T.IsNull()) { - const TopoDS_Face& aFace = SST.CurrentFace(); - T = SST.Triangulation (aFace, aLoc); - if (T.IsNull()) + continue; + } + const gp_Trsf& aTrsf = aLoc.Transformation(); + Poly_Connect pc (T); + // Extracts vertices & normals from nodes + const TColgp_Array1OfPnt& aNodes = T->Nodes(); + const TColgp_Array1OfPnt2d& aUVNodes = T->UVNodes(); + TColgp_Array1OfDir aNormals (aNodes.Lower(), aNodes.Upper()); + SST.Normal (aFace, pc, aNormals); + + if (theHasTexels) + { + BRepTools::UVBounds (aFace, aUmin, aUmax, aVmin, aVmax); + dUmax = (aUmax - aUmin); + dVmax = (aVmax - aVmin); + } + + decal = aPArray->VertexNumber(); + for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter) + { + p = aNodes (aNodeIter); + if (!aLoc.IsIdentity()) + { + p.Transform (aTrsf); + aNormals (aNodeIter).Transform (aTrsf); + } + + if (theHasTexels && aUVNodes.Upper() == aNodes.Upper()) + { + const gp_Pnt2d aTexel = gp_Pnt2d ((-theUVOrigin.X() + (theUVRepeat.X() * (aUVNodes (aNodeIter).X() - aUmin)) / dUmax) / theUVScale.X(), + (-theUVOrigin.Y() + (theUVRepeat.Y() * (aUVNodes (aNodeIter).Y() - aVmin)) / dVmax) / theUVScale.Y()); + aPArray->AddVertex (p, aNormals (aNodeIter), aTexel); + } + else + { + aPArray->AddVertex (p, aNormals (aNodeIter)); + } + } + + // Fill array with vertex and edge visibility info + const Poly_Array1OfTriangle& aTriangles = T->Triangles(); + for (Standard_Integer aTriIter = 1; aTriIter <= T->NbTriangles(); ++aTriIter) + { + pc.Triangles (aTriIter, t[0], t[1], t[2]); + if (SST.Orientation (aFace) == TopAbs_REVERSED) + aTriangles (aTriIter).Get (n[0], n[2], n[1]); + else + aTriangles (aTriIter).Get (n[0], n[1], n[2]); + + gp_Pnt P1 = aNodes (n[0]); + gp_Pnt P2 = aNodes (n[1]); + gp_Pnt P3 = aNodes (n[2]); + + gp_Vec V1 (P1, P2); + if (V1.SquareMagnitude() <= aPreci) { continue; } - const gp_Trsf& aTrsf = aLoc.Transformation(); - Poly_Connect pc (T); - // Extracts vertices & normals from nodes - const TColgp_Array1OfPnt& aNodes = T->Nodes(); - const TColgp_Array1OfPnt2d& aUVNodes = T->UVNodes(); - TColgp_Array1OfDir aNormals (aNodes.Lower(), aNodes.Upper()); - SST.Normal (aFace, pc, aNormals); - - if (theHasTexels) + gp_Vec V2 (P2, P3); + if (V2.SquareMagnitude() <= aPreci) { - BRepTools::UVBounds (aFace, aUmin, aUmax, aVmin, aVmax); - dUmax = (aUmax - aUmin); - dVmax = (aVmax - aVmin); + continue; } - - decal = aPArray->VertexNumber(); - for (Standard_Integer aNodeIter = aNodes.Lower(); aNodeIter <= aNodes.Upper(); ++aNodeIter) + gp_Vec V3 (P3, P1); + if (V3.SquareMagnitude() <= aPreci) { - p = aNodes (aNodeIter); - if (!aLoc.IsIdentity()) - { - p.Transform (aTrsf); - aNormals (aNodeIter).Transform (aTrsf); - } - - if (theHasTexels && aUVNodes.Upper() == aNodes.Upper()) - { - const gp_Pnt2d aTexel = gp_Pnt2d ((-theUVOrigin.X() + (theUVRepeat.X() * (aUVNodes (aNodeIter).X() - aUmin)) / dUmax) / theUVScale.X(), - (-theUVOrigin.Y() + (theUVRepeat.Y() * (aUVNodes (aNodeIter).Y() - aVmin)) / dVmax) / theUVScale.Y()); - aPArray->AddVertex (p, aNormals (aNodeIter), aTexel); - } - else - { - aPArray->AddVertex (p, aNormals (aNodeIter)); - } + continue; } - - // Fill parray with vertex and edge visibillity info - const Poly_Array1OfTriangle& aTriangles = T->Triangles(); - for (Standard_Integer aTriIter = 1; aTriIter <= T->NbTriangles(); ++aTriIter) + V1.Normalize(); + V2.Normalize(); + V1.Cross (V2); + if (V1.SquareMagnitude() > aPreci) { - pc.Triangles (aTriIter, t[0], t[1], t[2]); - if (SST.Orientation (aFace) == TopAbs_REVERSED) - aTriangles (aTriIter).Get (n[0], n[2], n[1]); - else - aTriangles (aTriIter).Get (n[0], n[1], n[2]); - - gp_Pnt P1 = aNodes (n[0]); - gp_Pnt P2 = aNodes (n[1]); - gp_Pnt P3 = aNodes (n[2]); - - gp_Vec V1 (P1, P2); - if (V1.SquareMagnitude() <= aPreci) - { - continue; - } - gp_Vec V2 (P2, P3); - if (V2.SquareMagnitude() <= aPreci) - { - continue; - } - gp_Vec V3 (P3, P1); - if (V3.SquareMagnitude() <= aPreci) - { - continue; - } - V1.Normalize(); - V2.Normalize(); - V1.Cross (V2); - if (V1.SquareMagnitude() > aPreci) - { - aPArray->AddEdge (n[0] + decal, t[0] == 0); - aPArray->AddEdge (n[1] + decal, t[1] == 0); - aPArray->AddEdge (n[2] + decal, t[2] == 0); - } + aPArray->AddEdge (n[0] + decal, t[0] == 0); + aPArray->AddEdge (n[1] + decal, t[1] == 0); + aPArray->AddEdge (n[2] + decal, t[2] == 0); } } - Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPArray); } + Prs3d_Root::CurrentGroup (thePresentation)->AddPrimitiveArray (aPArray); + return Standard_True; } diff --git a/src/StdPrs/StdPrs_ToolShadedShape.cdl b/src/StdPrs/StdPrs_ToolShadedShape.cdl index 80ba65c59f..0ff5b7c29c 100644 --- a/src/StdPrs/StdPrs_ToolShadedShape.cdl +++ b/src/StdPrs/StdPrs_ToolShadedShape.cdl @@ -25,14 +25,16 @@ uses Location from TopLoc is - IsClosed(myclass; aShape: Shape from TopoDS) returns Boolean from Standard; - + IsClosed (myclass; theShape : Shape from TopoDS) returns Boolean from Standard; + ---Purpose: Checks back faces visibility for specified shape (to activate back-face culling). + -- @return true if shape is closed Solid or compound of closed Solids. + Triangulation(myclass; aFace: Face from TopoDS; loc : out Location from TopLoc) returns Triangulation from Poly; - + Normal(myclass; aFace: Face from TopoDS; PC : in out Connect from Poly; Nor : out Array1OfDir from TColgp); - + end ToolShadedShape from StdPrs; diff --git a/src/StdPrs/StdPrs_ToolShadedShape.cxx b/src/StdPrs/StdPrs_ToolShadedShape.cxx index c9fa548add..c3aa6062e8 100644 --- a/src/StdPrs/StdPrs_ToolShadedShape.cxx +++ b/src/StdPrs/StdPrs_ToolShadedShape.cxx @@ -32,13 +32,99 @@ #include #include +namespace +{ + //======================================================================= + //function : isTriangulated + //purpose : Returns true if all faces within shape are triangulated. + // Same as BRepTools::Triangulation() but without extra checks. + //======================================================================= + static Standard_Boolean isTriangulated (const TopoDS_Shape& theShape) + { + TopLoc_Location aLocDummy; + for (TopExp_Explorer aFaceIter (theShape, TopAbs_FACE); aFaceIter.More(); aFaceIter.Next()) + { + const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Current()); + const Handle(Poly_Triangulation)& aTri = BRep_Tool::Triangulation (aFace, aLocDummy); + if (aTri.IsNull()) + { + return Standard_False; + } + } + return Standard_True; + } +} + //======================================================================= //function : IsClosed //purpose : //======================================================================= Standard_Boolean StdPrs_ToolShadedShape::IsClosed (const TopoDS_Shape& theShape) { - return theShape.Closed(); + if (theShape.IsNull()) + { + return Standard_True; + } + + switch (theShape.ShapeType()) + { + case TopAbs_COMPOUND: + case TopAbs_COMPSOLID: + default: + { + // check that compound consists of closed solids + for (TopoDS_Iterator anIter (theShape); anIter.More(); anIter.Next()) + { + const TopoDS_Shape& aShape = anIter.Value(); + if (!IsClosed (aShape)) + { + return Standard_False; + } + } + return Standard_True; + } + case TopAbs_SOLID: + { + for (TopoDS_Iterator anIter (theShape); anIter.More(); anIter.Next()) + { + const TopoDS_Shape& aShape = anIter.Value(); + if (aShape.IsNull()) + { + continue; + } + + if (aShape.ShapeType() == TopAbs_SHELL + && !aShape.Closed()) + { + return Standard_False; + } + else if (aShape.ShapeType() == TopAbs_FACE) + { + // invalid solid + return Standard_False; + } + else if (!isTriangulated (aShape)) + { + // mesh contains holes + return Standard_False; + } + } + return Standard_True; + } + case TopAbs_SHELL: + case TopAbs_FACE: + { + // free faces / shell are not allowed + return Standard_False; + } + case TopAbs_WIRE: + case TopAbs_EDGE: + case TopAbs_VERTEX: + { + // ignore + return Standard_True; + } + } } //======================================================================= diff --git a/tests/bugs/vis/bug23227 b/tests/bugs/vis/bug23227 index 7f40fbbab9..efa6a41190 100755 --- a/tests/bugs/vis/bug23227 +++ b/tests/bugs/vis/bug23227 @@ -1,19 +1,19 @@ puts "============" puts "OCC23227" +puts "New Draw Harness command to estimate current geometry complexity of OpenGL scene" puts "============" puts "" -####################################################################### -# New Draw Harness command to estimate current geometry complexity of OpenGL scene -####################################################################### set BugNumber OCC23227 box b 1 2 3 -vinit +vinit View1 +vclear vdisplay b vsetdispmode 1 vfit set vfeedback1 [vfeedback] +vdump $imagedir/${casename}_box.png vclear set vfeedback2 [vfeedback] @@ -24,17 +24,16 @@ set IndexTriangles1 [lsearch ${vfeedback1} Triangles:] set IndexTriangles2 [lsearch ${vfeedback2} Triangles:] if { ${llength_vfeedback1} < 36 || ${llength_vfeedback2} < 36 || ${IndexTriangles1} < 0 || ${IndexTriangles2} < 0 } { - puts "Bad format of vfeedback command" - puts "Faulty ${BugNumber}" + puts "Bad format of vfeedback command" + puts "Faulty ${BugNumber}" } else { - set Triangles1 [lindex ${vfeedback1} ${IndexTriangles1}+1] - set Triangles2 [lindex ${vfeedback2} ${IndexTriangles1}+1] - if { ${Triangles1} == 12 && ${Triangles2} == 0 } { - puts "OK ${BugNumber}" - } else { - puts "Faulty ${BugNumber}" - } + set Triangles1 [lindex ${vfeedback1} ${IndexTriangles1}+1] + set Triangles2 [lindex ${vfeedback2} ${IndexTriangles1}+1] + if { ${Triangles1} == 6 && ${Triangles2} == 0 } { + puts "OK ${BugNumber}" + } else { + puts "Faulty ${BugNumber}" + } } set only_screen 1 -