diff --git a/src/Graphic3d/Graphic3d_Structure.cxx b/src/Graphic3d/Graphic3d_Structure.cxx index e66e2ec58d..3ec6316e17 100644 --- a/src/Graphic3d/Graphic3d_Structure.cxx +++ b/src/Graphic3d/Graphic3d_Structure.cxx @@ -1616,7 +1616,7 @@ void Graphic3d_Structure::SetTransform (const TColStd_Array2OfReal& theMat ReCompute(); } - GraphicTransform (aNewTrsf); + myCStructure->UpdateTransformation(); myStructureManager->SetTransform (this, aNewTrsf); Update(); diff --git a/src/OpenGl/OpenGl_Context.cxx b/src/OpenGl/OpenGl_Context.cxx index a936cd10f0..54c225eb3e 100644 --- a/src/OpenGl/OpenGl_Context.cxx +++ b/src/OpenGl/OpenGl_Context.cxx @@ -120,6 +120,7 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps) myGlVerMinor (0), myIsInitialized (Standard_False), myIsStereoBuffers (Standard_False), + myIsGlNormalizeEnabled (Standard_False), #if !defined(GL_ES_VERSION_2_0) myRenderMode (GL_RENDER), #else @@ -2126,3 +2127,32 @@ void OpenGl_Context::SetPointSize (const Standard_ShortReal theSize) } #endif } + +// ======================================================================= +// function : SetGlNormalizeEnabled +// purpose : +// ======================================================================= +Standard_Boolean OpenGl_Context::SetGlNormalizeEnabled (Standard_Boolean isEnabled) +{ + if (isEnabled == myIsGlNormalizeEnabled) + { + return myIsGlNormalizeEnabled; + } + + Standard_Boolean anOldGlNormalize = myIsGlNormalizeEnabled; + + myIsGlNormalizeEnabled = isEnabled; + +#if !defined(GL_ES_VERSION_2_0) + if (isEnabled) + { + glEnable (GL_NORMALIZE); + } + else + { + glDisable (GL_NORMALIZE); + } +#endif + + return anOldGlNormalize; +} diff --git a/src/OpenGl/OpenGl_Context.hxx b/src/OpenGl/OpenGl_Context.hxx index 916502b267..c41298ac61 100644 --- a/src/OpenGl/OpenGl_Context.hxx +++ b/src/OpenGl/OpenGl_Context.hxx @@ -372,6 +372,13 @@ public: && !caps->vboDisable; } + //! @return cached state of GL_NORMALIZE. + Standard_Boolean IsGlNormalizeEnabled() const { return myIsGlNormalizeEnabled; } + + //! Sets GL_NORMALIZE enabled or disabled. + //! @return old value of the flag + Standard_EXPORT Standard_Boolean SetGlNormalizeEnabled (Standard_Boolean isEnabled); + public: //! @return messenger instance @@ -527,17 +534,19 @@ private: // context info OpenGl_Clipping myClippingState; //!< state of clip planes - void* myGlLibHandle; //!< optional handle to GL library + void* myGlLibHandle; //!< optional handle to GL library NCollection_Handle - myFuncs; //!< mega structure for all GL functions - Standard_Integer myAnisoMax; //!< maximum level of anisotropy texture filter - Standard_Integer myTexClamp; //!< either GL_CLAMP_TO_EDGE (1.2+) or GL_CLAMP (1.1) - Standard_Integer myMaxTexDim; //!< value for GL_MAX_TEXTURE_SIZE - Standard_Integer myMaxClipPlanes; //!< value for GL_MAX_CLIP_PLANES - Standard_Integer myGlVerMajor; //!< cached GL version major number - Standard_Integer myGlVerMinor; //!< cached GL version minor number - Standard_Boolean myIsInitialized; //!< flag indicates initialization state - Standard_Boolean myIsStereoBuffers; //!< context supports stereo buffering + myFuncs; //!< mega structure for all GL functions + Standard_Integer myAnisoMax; //!< maximum level of anisotropy texture filter + Standard_Integer myTexClamp; //!< either GL_CLAMP_TO_EDGE (1.2+) or GL_CLAMP (1.1) + Standard_Integer myMaxTexDim; //!< value for GL_MAX_TEXTURE_SIZE + Standard_Integer myMaxClipPlanes; //!< value for GL_MAX_CLIP_PLANES + Standard_Integer myGlVerMajor; //!< cached GL version major number + Standard_Integer myGlVerMinor; //!< cached GL version minor number + Standard_Boolean myIsInitialized; //!< flag indicates initialization state + Standard_Boolean myIsStereoBuffers; //!< context supports stereo buffering + Standard_Boolean myIsGlNormalizeEnabled; //!< GL_NORMALIZE flag + //!< Used to tell OpenGl that normals should be normalized Handle(OpenGl_ShaderManager) myShaderManager; //! support object for managing shader programs diff --git a/src/OpenGl/OpenGl_Structure.cxx b/src/OpenGl/OpenGl_Structure.cxx index 57f75786bf..a6ededc13e 100644 --- a/src/OpenGl/OpenGl_Structure.cxx +++ b/src/OpenGl/OpenGl_Structure.cxx @@ -147,7 +147,8 @@ OpenGl_Structure::OpenGl_Structure (const Handle(Graphic3d_StructureManager)& th myZLayer(0), myIsRaytracable (Standard_False), myModificationState (0), - myIsCulled (Standard_True) + myIsCulled (Standard_True), + myIsMirrored (Standard_False) { UpdateNamedStatus(); } @@ -195,6 +196,16 @@ void OpenGl_Structure::UpdateTransformation() myTransformation = new OpenGl_Matrix(); } + Standard_ShortReal (*aMat)[4] = Graphic3d_CStructure::Transformation; + + Standard_ShortReal aDet = + aMat[0][0] * (aMat[1][1] * aMat[2][2] - aMat[2][1] * aMat[1][2]) - + aMat[0][1] * (aMat[1][0] * aMat[2][2] - aMat[2][0] * aMat[1][2]) + + aMat[0][2] * (aMat[1][0] * aMat[2][1] - aMat[2][0] * aMat[1][1]); + + // Determinant of transform matrix less then 0 means that mirror transform applied. + myIsMirrored = aDet < 0.0f; + matcpy (myTransformation->mat, &Graphic3d_CStructure::Transformation[0][0]); if (myIsRaytracable) @@ -296,11 +307,11 @@ void OpenGl_Structure::clearHighlightBox (const Handle(OpenGl_Context)& theGlCtx void OpenGl_Structure::HighlightWithColor (const Graphic3d_Vec3& theColor, const Standard_Boolean theToCreate) { - const Handle(OpenGl_Context)& aCtx = GlDriver()->GetSharedContext(); + const Handle(OpenGl_Context)& aContext = GlDriver()->GetSharedContext(); if (theToCreate) - setHighlightColor (aCtx, theColor); + setHighlightColor (aContext, theColor); else - clearHighlightColor (aCtx); + clearHighlightColor (aContext); } // ======================================================================= @@ -310,16 +321,16 @@ void OpenGl_Structure::HighlightWithColor (const Graphic3d_Vec3& theColor, void OpenGl_Structure::HighlightWithBndBox (const Handle(Graphic3d_Structure)& theStruct, const Standard_Boolean theToCreate) { - const Handle(OpenGl_Context)& aCtx = GlDriver()->GetSharedContext(); + const Handle(OpenGl_Context)& aContext = GlDriver()->GetSharedContext(); if (!theToCreate) { - clearHighlightBox (aCtx); + clearHighlightBox (aContext); return; } if (!myHighlightBox.IsNull()) { - myHighlightBox->Release (aCtx); + myHighlightBox->Release (aContext); } else { @@ -612,13 +623,13 @@ void OpenGl_Structure::Clear (const Handle(OpenGl_Context)& theGlCtx) // function : RenderGeometry // purpose : // ======================================================================= -void OpenGl_Structure::RenderGeometry (const Handle(OpenGl_Workspace) &AWorkspace) const +void OpenGl_Structure::RenderGeometry (const Handle(OpenGl_Workspace) &theWorkspace) const { // Render groups const Graphic3d_SequenceOfGroup& aGroups = DrawGroups(); for (OpenGl_Structure::GroupIterator aGroupIter (aGroups); aGroupIter.More(); aGroupIter.Next()) { - aGroupIter.Value()->Render (AWorkspace); + aGroupIter.Value()->Render (theWorkspace); } } @@ -626,35 +637,50 @@ void OpenGl_Structure::RenderGeometry (const Handle(OpenGl_Workspace) &AWorkspac // function : Render // purpose : // ======================================================================= -void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &AWorkspace) const +void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) const { // Process the structure only if visible - if ( myNamedStatus & OPENGL_NS_HIDE ) + if (myNamedStatus & OPENGL_NS_HIDE) + { return; + } - const Handle(OpenGl_Context)& aCtx = AWorkspace->GetGlContext(); + const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext(); // Render named status - const Standard_Integer named_status = AWorkspace->NamedStatus; - AWorkspace->NamedStatus |= myNamedStatus; + const Standard_Integer aNamedStatus = theWorkspace->NamedStatus; + theWorkspace->NamedStatus |= myNamedStatus; // Is rendering in ADD or IMMEDIATE mode? - const Standard_Boolean isImmediate = (AWorkspace->NamedStatus & OPENGL_NS_IMMEDIATE) != 0; + const Standard_Boolean isImmediate = (theWorkspace->NamedStatus & OPENGL_NS_IMMEDIATE) != 0; + + // Do we need to restore GL_NORMALIZE? + Standard_Boolean anOldGlNormalize = aContext->IsGlNormalizeEnabled(); // Apply local transformation - GLint matrix_mode = 0; - const OpenGl_Matrix *local_trsf = NULL; + GLint aMatrixMode = 0; + const OpenGl_Matrix* aLocalTrsf = NULL; if (myTransformation) { #if !defined(GL_ES_VERSION_2_0) + + Standard_ShortReal aScaleX = OpenGl_Vec3 (myTransformation->mat[0][0], + myTransformation->mat[0][1], + myTransformation->mat[0][2]).SquareModulus(); + // Scale transform detected. + if (Abs (aScaleX - 1.f) > Precision::Confusion()) + { + anOldGlNormalize = aContext->SetGlNormalizeEnabled (Standard_True); + } + if (isImmediate) { Tmatrix3 aModelWorld; call_util_transpose_mat (*aModelWorld, myTransformation->mat); - glGetIntegerv (GL_MATRIX_MODE, &matrix_mode); + glGetIntegerv (GL_MATRIX_MODE, &aMatrixMode); - if (!aCtx->ShaderManager()->IsEmpty()) + if (!aContext->ShaderManager()->IsEmpty()) { Tmatrix3 aWorldView; glGetFloatv (GL_MODELVIEW_MATRIX, *aWorldView); @@ -662,14 +688,14 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &AWorkspace) const Tmatrix3 aProjection; glGetFloatv (GL_PROJECTION_MATRIX, *aProjection); - aCtx->ShaderManager()->UpdateModelWorldStateTo (&aModelWorld); - aCtx->ShaderManager()->UpdateWorldViewStateTo (&aWorldView); - aCtx->ShaderManager()->UpdateProjectionStateTo (&aProjection); + aContext->ShaderManager()->UpdateModelWorldStateTo (&aModelWorld); + aContext->ShaderManager()->UpdateWorldViewStateTo (&aWorldView); + aContext->ShaderManager()->UpdateProjectionStateTo (&aProjection); } glMatrixMode (GL_MODELVIEW); glPushMatrix (); - glScalef (1.F, 1.F, 1.F); + glScalef (1.0f, 1.0f, 1.0f); glMultMatrixf (*aModelWorld); } else @@ -677,58 +703,70 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &AWorkspace) const glMatrixMode (GL_MODELVIEW); glPushMatrix(); - local_trsf = AWorkspace->SetStructureMatrix (myTransformation); + aLocalTrsf = theWorkspace->SetStructureMatrix (myTransformation); } #endif } // Apply transform persistence - const TEL_TRANSFORM_PERSISTENCE *trans_pers = NULL; + const TEL_TRANSFORM_PERSISTENCE *aTransPersistence = NULL; if ( myTransPers && myTransPers->mode != 0 ) { - trans_pers = AWorkspace->ActiveView()->BeginTransformPersistence (aCtx, myTransPers); + aTransPersistence = theWorkspace->ActiveView()->BeginTransformPersistence (aContext, myTransPers); } // Apply aspects - const OpenGl_AspectLine *aspect_line = AWorkspace->AspectLine(Standard_False); - const OpenGl_AspectFace *aspect_face = AWorkspace->AspectFace(Standard_False); - const OpenGl_AspectMarker *aspect_marker = AWorkspace->AspectMarker(Standard_False); - const OpenGl_AspectText *aspect_text = AWorkspace->AspectText(Standard_False); + const OpenGl_AspectLine *anAspectLine = theWorkspace->AspectLine (Standard_False); + const OpenGl_AspectFace *anAspectFace = theWorkspace->AspectFace (Standard_False); + const OpenGl_AspectMarker *anAspectMarker = theWorkspace->AspectMarker (Standard_False); + const OpenGl_AspectText *anAspectText = theWorkspace->AspectText (Standard_False); if (myAspectLine) - AWorkspace->SetAspectLine(myAspectLine); + { + theWorkspace->SetAspectLine (myAspectLine); + } if (myAspectFace) - AWorkspace->SetAspectFace(myAspectFace); + { + theWorkspace->SetAspectFace (myAspectFace); + } if (myAspectMarker) - AWorkspace->SetAspectMarker(myAspectMarker); + { + theWorkspace->SetAspectMarker (myAspectMarker); + } if (myAspectText) - AWorkspace->SetAspectText(myAspectText); + { + theWorkspace->SetAspectText (myAspectText); + } + + // Apply correction for mirror transform + if (myIsMirrored) + { + glFrontFace (GL_CW); + } // Apply highlight color - const TEL_COLOUR *highlight_color = AWorkspace->HighlightColor; + const TEL_COLOUR *aHighlightColor = theWorkspace->HighlightColor; if (myHighlightColor) - AWorkspace->HighlightColor = myHighlightColor; + theWorkspace->HighlightColor = myHighlightColor; // Render connected structures - OpenGl_ListOfStructure::Iterator its(myConnected); - while (its.More()) + OpenGl_ListOfStructure::Iterator anIter (myConnected); + while (anIter.More()) { - its.Value()->RenderGeometry (AWorkspace); - its.Next(); + anIter.Value()->RenderGeometry (theWorkspace); + anIter.Next(); } // Set up plane equations for non-structure transformed global model-view matrix - const Handle(OpenGl_Context)& aContext = AWorkspace->GetGlContext(); - // List of planes to be applied to context state Handle(Graphic3d_SequenceOfHClipPlane) aUserPlanes; // Collect clipping planes of structure scope if (!myClipPlanes.IsEmpty()) { - Graphic3d_SequenceOfHClipPlane::Iterator aClippingIt (myClipPlanes); - for (; aClippingIt.More(); aClippingIt.Next()) + Graphic3d_SequenceOfHClipPlane::Iterator aClippingIter (myClipPlanes); + for (; aClippingIter.More(); aClippingIter.Next()) { - const Handle(Graphic3d_ClipPlane)& aClipPlane = aClippingIt.Value(); + const Handle(Graphic3d_ClipPlane)& aClipPlane = aClippingIter.Value(); if (!aClipPlane->IsOn()) { continue; @@ -746,7 +784,7 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &AWorkspace) const if (!aUserPlanes.IsNull() && !aUserPlanes->IsEmpty()) { // add planes at loaded view matrix state - aContext->ChangeClipping().AddWorld (*aUserPlanes, AWorkspace); + aContext->ChangeClipping().AddWorld (*aUserPlanes, theWorkspace); // Set OCCT state uniform variables if (!aContext->ShaderManager()->IsEmpty()) @@ -759,13 +797,17 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &AWorkspace) const const Graphic3d_SequenceOfGroup& aGroups = DrawGroups(); for (OpenGl_Structure::GroupIterator aGroupIter (aGroups); aGroupIter.More(); aGroupIter.Next()) { - aGroupIter.Value()->Render (AWorkspace); + aGroupIter.Value()->Render (theWorkspace); } + // Reset correction for mirror transform + if (myIsMirrored) + glFrontFace (GL_CCW); // default + // Render capping for structure groups if (!aContext->Clipping().Planes().IsEmpty()) { - OpenGl_CappingAlgo::RenderCapping (AWorkspace, aGroups); + OpenGl_CappingAlgo::RenderCapping (theWorkspace, aGroups); } // Revert structure clippings @@ -781,28 +823,31 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &AWorkspace) const } // Restore highlight color - AWorkspace->HighlightColor = highlight_color; + theWorkspace->HighlightColor = aHighlightColor; // Restore aspects - AWorkspace->SetAspectLine(aspect_line); - AWorkspace->SetAspectFace(aspect_face); - AWorkspace->SetAspectMarker(aspect_marker); - AWorkspace->SetAspectText(aspect_text); + theWorkspace->SetAspectLine (anAspectLine); + theWorkspace->SetAspectFace (anAspectFace); + theWorkspace->SetAspectMarker (anAspectMarker); + theWorkspace->SetAspectText (anAspectText); // Restore transform persistence if ( myTransPers && myTransPers->mode != 0 ) { - AWorkspace->ActiveView()->BeginTransformPersistence (aContext, trans_pers); + theWorkspace->ActiveView()->BeginTransformPersistence (aContext, aTransPersistence); } // Restore local transformation if (myTransformation) { #if !defined(GL_ES_VERSION_2_0) + + aContext->SetGlNormalizeEnabled (anOldGlNormalize); + if (isImmediate) { glPopMatrix (); - glMatrixMode (matrix_mode); + glMatrixMode (aMatrixMode); Tmatrix3 aModelWorldState = { { 1.f, 0.f, 0.f, 0.f }, { 0.f, 1.f, 0.f, 0.f }, @@ -813,7 +858,7 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &AWorkspace) const } else { - AWorkspace->SetStructureMatrix (local_trsf, true); + theWorkspace->SetStructureMatrix (aLocalTrsf, true); glMatrixMode (GL_MODELVIEW); glPopMatrix(); @@ -824,11 +869,11 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &AWorkspace) const // Apply highlight box if (!myHighlightBox.IsNull()) { - myHighlightBox->Render (AWorkspace); + myHighlightBox->Render (theWorkspace); } // Restore named status - AWorkspace->NamedStatus = named_status; + theWorkspace->NamedStatus = aNamedStatus; } // ======================================================================= diff --git a/src/OpenGl/OpenGl_Structure.hxx b/src/OpenGl/OpenGl_Structure.hxx index d603cea93d..24ce51603d 100644 --- a/src/OpenGl/OpenGl_Structure.hxx +++ b/src/OpenGl/OpenGl_Structure.hxx @@ -250,6 +250,8 @@ protected: mutable Standard_Boolean myIsCulled; //!< A status specifying is structure needs to be rendered after BVH tree traverse. + Standard_Boolean myIsMirrored; //!< Used to tell OpenGl to interpret polygons in clockwise order. + public: DEFINE_STANDARD_RTTI(OpenGl_Structure) // Type definition diff --git a/src/OpenGl/OpenGl_View_2.cxx b/src/OpenGl/OpenGl_View_2.cxx index f346cb4877..91164cce91 100644 --- a/src/OpenGl/OpenGl_View_2.cxx +++ b/src/OpenGl/OpenGl_View_2.cxx @@ -483,12 +483,16 @@ void OpenGl_View::Render (const Handle(OpenGl_PrinterContext)& thePrintContext, // if the view is scaled normal vectors are scaled to unit // length for correct displaying of shaded objects const gp_Pnt anAxialScale = myCamera->AxialScale(); - if(anAxialScale.X() != 1.F || - anAxialScale.Y() != 1.F || - anAxialScale.Z() != 1.F) - glEnable(GL_NORMALIZE); - else if(glIsEnabled(GL_NORMALIZE)) - glDisable(GL_NORMALIZE); + if (anAxialScale.X() != 1.F || + anAxialScale.Y() != 1.F || + anAxialScale.Z() != 1.F) + { + aContext->SetGlNormalizeEnabled (Standard_True); + } + else + { + aContext->SetGlNormalizeEnabled (Standard_False); + } // Apply Fog if ( myFog.IsOn ) diff --git a/src/StdPrs/StdPrs_ShadedShape.cxx b/src/StdPrs/StdPrs_ShadedShape.cxx index cfbb5eb6cf..160417bd5a 100644 --- a/src/StdPrs/StdPrs_ShadedShape.cxx +++ b/src/StdPrs/StdPrs_ShadedShape.cxx @@ -149,6 +149,10 @@ namespace continue; } const gp_Trsf& aTrsf = aLoc.Transformation(); + + // Determinant of transform matrix less then 0 means that mirror transform applied. + Standard_Boolean isMirrored = aTrsf.VectorialPart().Determinant() < 0; + Poly_Connect aPolyConnect (aT); // Extracts vertices & normals from nodes const TColgp_Array1OfPnt& aNodes = aT->Nodes(); @@ -170,7 +174,8 @@ namespace if (!aLoc.IsIdentity()) { aPoint.Transform (aTrsf); - aNormals (aNodeIter).Transform (aTrsf); + + aNormals (aNodeIter) = aNormals (aNodeIter).Transformed (aTrsf); } if (theHasTexels && aUVNodes.Upper() == aNodes.Upper()) @@ -190,7 +195,7 @@ namespace Standard_Integer anIndex[3]; for (Standard_Integer aTriIter = 1; aTriIter <= aT->NbTriangles(); ++aTriIter) { - if (aFace.Orientation() == TopAbs_REVERSED) + if ((aFace.Orientation() == TopAbs_REVERSED) ^ isMirrored) { aTriangles (aTriIter).Get (anIndex[0], anIndex[2], anIndex[1]); } diff --git a/src/ViewerTest/ViewerTest_ObjectCommands.cxx b/src/ViewerTest/ViewerTest_ObjectCommands.cxx index 222e88d58e..7248b4bb17 100644 --- a/src/ViewerTest/ViewerTest_ObjectCommands.cxx +++ b/src/ViewerTest/ViewerTest_ObjectCommands.cxx @@ -3542,6 +3542,166 @@ static Standard_Integer VSetLocation (Draw_Interpretor& /*di*/, return 0; } +//======================================================================= +//function : TransformPresentation +//purpose : Change transformation of AIS interactive object +//======================================================================= +static Standard_Integer LocalTransformPresentation (Draw_Interpretor& /*theDi*/, + Standard_Integer theArgNb, + const char** theArgVec) +{ + if (theArgNb <= 1) + { + std::cout << "Error: too few arguments.\n"; + return 1; + } + + Handle(AIS_InteractiveContext) aContext = ViewerTest::GetAISContext(); + ViewerTest_AutoUpdater anUpdateTool(aContext, ViewerTest::CurrentView()); + if (aContext.IsNull()) + { + std::cout << "Error: no active view!\n"; + return 1; + } + + gp_Trsf aTrsf; + Standard_Integer aLast = theArgNb; + const char* aName = theArgVec[0]; + + Standard_Boolean isReset = Standard_False; + Standard_Boolean isMove = Standard_False; + + // Prefix 'vloc' + aName += 4; + + if (!strcmp (aName, "reset")) + { + isReset = Standard_True; + } + else if (!strcmp (aName, "move")) + { + if (theArgNb < 3) + { + std::cout << "Error: too few arguments.\n"; + return 1; + } + + const ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS(); + + Handle(AIS_InteractiveObject) anIObj; + if (aMap.IsBound2 (theArgVec[theArgNb - 1])) + { + anIObj = Handle(AIS_InteractiveObject)::DownCast (aMap.Find2 (theArgVec[theArgNb - 1])); + } + + if (anIObj.IsNull()) + { + std::cout << "Error: object '" << theArgVec[theArgNb - 1] << "' is not displayed!\n"; + return 1; + } + + isMove = Standard_True; + + aTrsf = anIObj->Transformation(); + aLast = theArgNb - 1; + } + else if (!strcmp (aName, "translate")) + { + if (theArgNb < 5) + { + std::cout << "Error: too few arguments.\n"; + return 1; + } + aTrsf.SetTranslation (gp_Vec (Draw::Atof (theArgVec[theArgNb - 3]), + Draw::Atof (theArgVec[theArgNb - 2]), + Draw::Atof (theArgVec[theArgNb - 1]))); + aLast = theArgNb - 3; + } + else if (!strcmp (aName, "rotate")) + { + if (theArgNb < 9) + { + std::cout << "Error: too few arguments.\n"; + return 1; + } + + aTrsf.SetRotation ( + gp_Ax1 (gp_Pnt (Draw::Atof (theArgVec[theArgNb - 7]), + Draw::Atof (theArgVec[theArgNb - 6]), + Draw::Atof (theArgVec[theArgNb - 5])), + gp_Vec (Draw::Atof (theArgVec[theArgNb - 4]), + Draw::Atof (theArgVec[theArgNb - 3]), + Draw::Atof (theArgVec[theArgNb - 2]))), + Draw::Atof (theArgVec[theArgNb - 1]) * (M_PI / 180.0)); + + aLast = theArgNb - 7; + } + else if (!strcmp (aName, "mirror")) + { + if (theArgNb < 8) + { + std::cout << "Error: too few arguments.\n"; + return 1; + } + + aTrsf.SetMirror (gp_Ax2 (gp_Pnt (Draw::Atof(theArgVec[theArgNb - 6]), + Draw::Atof(theArgVec[theArgNb - 5]), + Draw::Atof(theArgVec[theArgNb - 4])), + gp_Vec (Draw::Atof(theArgVec[theArgNb - 3]), + Draw::Atof(theArgVec[theArgNb - 2]), + Draw::Atof(theArgVec[theArgNb - 1])))); + aLast = theArgNb - 6; + } + else if (!strcmp (aName, "scale")) + { + if (theArgNb < 6) + { + std::cout << "Error: too few arguments.\n"; + return 1; + } + + aTrsf.SetScale (gp_Pnt (Draw::Atof(theArgVec[theArgNb - 4]), + Draw::Atof(theArgVec[theArgNb - 3]), + Draw::Atof(theArgVec[theArgNb - 2])), + Draw::Atof(theArgVec[theArgNb - 1])); + aLast = theArgNb - 4; + } + + for (Standard_Integer anIdx = 1; anIdx < aLast; anIdx++) + { + // find object + const ViewerTest_DoubleMapOfInteractiveAndName& aMap = GetMapOfAIS(); + Handle(AIS_InteractiveObject) anIObj; + if (aMap.IsBound2 (theArgVec[anIdx])) + { + anIObj = Handle(AIS_InteractiveObject)::DownCast (aMap.Find2 (theArgVec[anIdx])); + } + if (anIObj.IsNull()) + { + std::cout << "Error: object '" << theArgVec[anIdx] << "' is not displayed!\n"; + return 1; + } + + if (isReset) + { + // aTrsf already identity + } + else if (isMove) + { + aTrsf = anIObj->LocalTransformation() * anIObj->Transformation().Inverted() * aTrsf; + } + else + { + aTrsf = anIObj->LocalTransformation() * aTrsf; + } + + TopLoc_Location aLocation (aTrsf); + aContext->SetLocation (anIObj, aLocation); + } + + return 0; +} + //=============================================================================================== //function : VConnect //purpose : Creates and displays AIS_ConnectedInteractive object from input object and location @@ -5818,4 +5978,34 @@ void ViewerTest::ObjectCommands(Draw_Interpretor& theCommands) "\n\t\t: -noNormals - do not generate normal per point" "\n", __FILE__, VPointCloud, group); + + theCommands.Add("vlocreset", + "vlocreset name1 name2 ...\n\t\t remove object local transformation", + __FILE__, + LocalTransformPresentation, group); + + theCommands.Add("vlocmove", + "vlocmove name1 name2 ... name\n\t\t set local transform to match transform of 'name'", + __FILE__, + LocalTransformPresentation, group); + + theCommands.Add("vloctranslate", + "vloctranslate name1 name2 ... dx dy dz\n\t\t applies translation to local transformation", + __FILE__, + LocalTransformPresentation, group); + + theCommands.Add("vlocrotate", + "vlocrotate name1 name2 ... x y z dx dy dz angle\n\t\t applies rotation to local transformation", + __FILE__, + LocalTransformPresentation, group); + + theCommands.Add("vlocmirror", + "vlocmirror name x y z dx dy dz\n\t\t applies mirror to local transformation", + __FILE__, + LocalTransformPresentation, group); + + theCommands.Add("vlocscale", + "vlocscale name x y z scale\n\t\t applies scale to local transformation", + __FILE__, + LocalTransformPresentation, group); } diff --git a/tests/bugs/vis/bug25276 b/tests/bugs/vis/bug25276 new file mode 100644 index 0000000000..20c19db6df --- /dev/null +++ b/tests/bugs/vis/bug25276 @@ -0,0 +1,40 @@ +puts "============" +puts "OCC25276" +puts "============" +puts "" +####################################################################### +# Visualization - Lighting is broken if some kinds of transformation applied to a shape +####################################################################### + +pload ALL +vinit +box b1 1 6 1 +vsetdispmode 1 +vdisplay b1 +vconnectto b2 6 0 0 b1 +box b3 7 1 1 +vdisplay b3 +vloctranslate b3 0 4 0 +vconnect z 0 0 0 b1 b2 b3 + +vconnect z1 0 0 0 z +vloctranslate z1 10 0 0 + +vconnect z2 0 10 0 z +vlocrotate z2 0 0 0 1 0 0 90 + +vconnect z3 -10 0 0 z +vlocscale z3 0 0 0 0.5 + +vconnect z4 0 0 0 z +vlocmove z4 z3 + +psphere sp 3 +vdisplay sp +vlocmove sp z3 +vlocreset sp + +vlocmirror z 0 -0.5 0 0 1 0 +vfit + +vdump $imagedir/${casename}.png