diff --git a/src/AIS/AIS_KindOfInteractive.hxx b/src/AIS/AIS_KindOfInteractive.hxx index 7151a05062..b2e7726901 100644 --- a/src/AIS/AIS_KindOfInteractive.hxx +++ b/src/AIS/AIS_KindOfInteractive.hxx @@ -28,6 +28,7 @@ enum AIS_KindOfInteractive AIS_KindOfInteractive_Object, //!< presentation of group of topological shapes AIS_KindOfInteractive_Relation, //!< presentation of relation (dimensions and constraints) AIS_KindOfInteractive_Dimension, //!< presentation of dimension (length, radius, diameter and angle) + AIS_KindOfInteractive_LightSource, //!< presentation of light source // old aliases AIS_KOI_None = AIS_KindOfInteractive_None, diff --git a/src/AIS/AIS_LightSource.cxx b/src/AIS/AIS_LightSource.cxx new file mode 100644 index 0000000000..f5112fa839 --- /dev/null +++ b/src/AIS/AIS_LightSource.cxx @@ -0,0 +1,693 @@ +// Created on: 2020-09-07 +// Created by: Maria KRYLOVA +// Copyright (c) 2020 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +IMPLEMENT_STANDARD_RTTIEXT(AIS_LightSource, AIS_InteractiveObject) +IMPLEMENT_STANDARD_RTTIEXT(AIS_LightSourceOwner, SelectMgr_EntityOwner) + +// ======================================================================= +// function : AIS_LightSourceOwner +// purpose : +// ======================================================================= +AIS_LightSourceOwner::AIS_LightSourceOwner (const Handle(AIS_LightSource)& theObject, + Standard_Integer thePriority) +: SelectMgr_EntityOwner ((const Handle(SelectMgr_SelectableObject)&)theObject, thePriority) +{ + // +} + +// ======================================================================= +// function : HandleMouseClick +// purpose : +// ======================================================================= +Standard_Boolean AIS_LightSourceOwner::HandleMouseClick (const Graphic3d_Vec2i& , + Aspect_VKeyMouse theKey, + Aspect_VKeyFlags theFlags, + bool ) +{ + AIS_LightSource* aLightSource = dynamic_cast(mySelectable); + if (aLightSource != NULL + && aLightSource->ToSwitchOnClick() + && theKey == Aspect_VKeyMouse_LeftButton + && theFlags == Aspect_VKeyFlags_NONE) + { + aLightSource->Light()->SetEnabled (!aLightSource->Light()->IsEnabled()); + aLightSource->updateLightAspects(); + return true; + } + return false; +} + +// ======================================================================= +// function : Constructor +// purpose : +// ======================================================================= +AIS_LightSource::AIS_LightSource (const Handle(Graphic3d_CLight)& theLight) +: myLightSource (theLight), + myCodirMarkerType (Aspect_TOM_X), + myOpposMarkerType (Aspect_TOM_O_POINT), + mySize (50), + myNbArrows (5), + myNbSplitsQuadric (theLight->Type() == Graphic3d_TOLS_AMBIENT ? 10 : 30), + myNbSplitsArrow (20), + myIsZoomable (theLight->Type() == Graphic3d_TOLS_POSITIONAL + || theLight->Type() == Graphic3d_TOLS_SPOT), + myToDisplayName (true), + myToDisplayRange (true), + myToSwitchOnClick (true) +{ + myMarkerTypes[0] = Aspect_TOM_O_X; + myMarkerTypes[1] = Aspect_TOM_O_POINT; + + myInfiniteState = true; + + const Quantity_Color aColor = theLight->Color(); + myDrawer->SetPointAspect (new Prs3d_PointAspect (myMarkerTypes[1], aColor, 3.0f)); + myDisabledMarkerAspect = new Graphic3d_AspectMarker3d (Aspect_TOM_EMPTY, aColor, 3.0f); + + Graphic3d_MaterialAspect aMat (Graphic3d_NameOfMaterial_UserDefined); + aMat.SetColor (aColor); + myDrawer->SetArrowAspect (new Prs3d_ArrowAspect()); + myDrawer->ArrowAspect()->SetColor (aColor); + myDrawer->ArrowAspect()->Aspect()->SetShadingModel (Graphic3d_TOSM_UNLIT); + myDrawer->ArrowAspect()->Aspect()->ChangeFrontMaterial() = aMat; + myDrawer->ArrowAspect()->Aspect()->SetMarkerType (Aspect_TOM_EMPTY); + myDrawer->ArrowAspect()->Aspect()->SetMarkerScale (2.0f); + myArrowLineAspectShadow = new Graphic3d_AspectLine3d (Quantity_NOC_BLACK, Aspect_TOL_SOLID, + theLight->Type() != Graphic3d_TOLS_AMBIENT ? 3.0f : 1.0f); + + myDrawer->SetupOwnShadingAspect(); + myDrawer->ShadingAspect()->SetColor (aColor); + myDrawer->ShadingAspect()->SetMaterial (aMat); + myDrawer->ShadingAspect()->SetTransparency (0.5f); + myDrawer->ShadingAspect()->Aspect()->SetShadingModel (Graphic3d_TOSM_UNLIT); + + myDrawer->SetTextAspect (new Prs3d_TextAspect()); + myDrawer->TextAspect()->Aspect()->SetDisplayType (Aspect_TODT_SHADOW); + myDrawer->TextAspect()->Aspect()->SetColorSubTitle (Quantity_NOC_BLACK); + myDrawer->TextAspect()->SetHorizontalJustification (Graphic3d_HTA_LEFT); + myDrawer->TextAspect()->SetVerticalJustification (Graphic3d_VTA_TOPFIRSTLINE); + + updateLightTransformPersistence(); + + myDrawer->SetDisplayMode (0); + myDynHilightDrawer = new Prs3d_Drawer(); + myDynHilightDrawer->Link (myDrawer); + myDynHilightDrawer->SetDisplayMode (1); + myDynHilightDrawer->SetColor (Quantity_NOC_CYAN1); + + if (!myTransformPersistence.IsNull() + && myTransformPersistence->IsTrihedronOr2d()) + { + myDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost); + myDynHilightDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost); + myDrawer->TextAspect()->SetHorizontalJustification (Graphic3d_HTA_CENTER); + myDrawer->TextAspect()->SetVerticalJustification (Graphic3d_VTA_TOP); + } +} + +// ======================================================================= +// function : updateLightAspects +// purpose : +// ======================================================================= +void AIS_LightSource::updateLightAspects() +{ + const Quantity_Color aBaseColor = myLightSource->Color(); + const Quantity_Color aDimColor (aBaseColor.Rgb() * 0.3f); + const Quantity_Color aColor = myLightSource->IsEnabled() ? aBaseColor : aDimColor; + myDrawer->PointAspect()->SetColor (aColor); + myDrawer->PointAspect()->Aspect()->SetMarkerType (MarkerType (myLightSource->IsEnabled())); + myDrawer->PointAspect()->Aspect()->SetMarkerImage(MarkerImage(myLightSource->IsEnabled())); + + myDisabledMarkerAspect->SetColor (aColor); + myDisabledMarkerAspect->SetMarkerScale(myDrawer->PointAspect()->Aspect()->MarkerScale()); + myDisabledMarkerAspect->SetMarkerType (myLightSource->IsEnabled() ? Aspect_TOM_EMPTY : MarkerType (false)); + myDisabledMarkerAspect->SetMarkerImage(MarkerImage (false)); + + myDrawer->ShadingAspect()->SetColor (aColor); + myDrawer->ArrowAspect() ->SetColor (aColor); + myDrawer->ArrowAspect()->Aspect()->ChangeFrontMaterial().SetColor (aColor); + + if (myLightSource->Type() == Graphic3d_TOLS_DIRECTIONAL) + { + const Standard_Real anAngleTol = 2.0 * M_PI / 180.0; + Aspect_TypeOfMarker aDirMark = Aspect_TOM_EMPTY; + if (myLightSource->IsEnabled() + && myLightSource->IsHeadlight() + && myLightSource->Direction().IsParallel (gp::DZ(), anAngleTol)) + { + aDirMark = myLightSource->Direction().IsOpposite (-gp::DZ(), anAngleTol) ? myOpposMarkerType : myCodirMarkerType; + } + myDrawer->ArrowAspect()->Aspect()->SetMarkerType (aDirMark); + } + SynchronizeAspects(); +} + +// ======================================================================= +// function : updateLightTransformPersistence +// purpose : +// ======================================================================= +void AIS_LightSource::updateLightTransformPersistence() +{ + Handle(Graphic3d_TransformPers) aTrsfPers = myTransformPersistence; + switch (myLightSource->Type()) + { + case Graphic3d_TOLS_AMBIENT: + { + if (!myIsZoomable) + { + if (aTrsfPers.IsNull() || !aTrsfPers->IsTrihedronOr2d()) + { + aTrsfPers = new Graphic3d_TransformPers (Graphic3d_TMF_TriedronPers, Aspect_TOTP_LEFT_UPPER, Graphic3d_Vec2i(50)); + } + } + else + { + aTrsfPers.Nullify(); + } + break; + } + case Graphic3d_TOLS_DIRECTIONAL: + { + Graphic3d_TransModeFlags aMode = myLightSource->IsHeadlight() ? Graphic3d_TMF_2d : Graphic3d_TMF_TriedronPers; + if (myIsZoomable) + { + aMode = myLightSource->IsHeadlight() ? Graphic3d_TMF_CameraPers : Graphic3d_TMF_None; + } + if (aMode != Graphic3d_TMF_None) + { + if (aTrsfPers.IsNull() || aTrsfPers->Mode() != aMode) + { + if (aMode == Graphic3d_TMF_CameraPers) + { + aTrsfPers = new Graphic3d_TransformPers (Graphic3d_TMF_CameraPers); + } + else + { + aTrsfPers = new Graphic3d_TransformPers (aMode, Aspect_TOTP_LEFT_UPPER, Graphic3d_Vec2i(50)); + } + } + } + else + { + aTrsfPers.Nullify(); + } + break; + } + case Graphic3d_TOLS_POSITIONAL: + case Graphic3d_TOLS_SPOT: + { + Graphic3d_TransModeFlags aMode = myLightSource->IsHeadlight() + ? Graphic3d_TMF_CameraPers + : (!myIsZoomable ? Graphic3d_TMF_ZoomPers : Graphic3d_TMF_None); + if (aMode != Graphic3d_TMF_None) + { + if (aTrsfPers.IsNull() || aTrsfPers->Mode() != aMode) + { + if (aMode == Graphic3d_TMF_CameraPers) + { + aTrsfPers = new Graphic3d_TransformPers (Graphic3d_TMF_CameraPers); + } + else + { + aTrsfPers = new Graphic3d_TransformPers (aMode, myLightSource->Position()); + } + } + if (aMode == Graphic3d_TMF_ZoomPers) + { + aTrsfPers->SetAnchorPoint (myLightSource->Position()); + } + } + else + { + aTrsfPers.Nullify(); + } + break; + } + } + + SetTransformPersistence (aTrsfPers); +} + +// ======================================================================= +// function : updateLightLocalTransformation +// purpose : +// ======================================================================= +void AIS_LightSource::updateLightLocalTransformation() +{ + myLocalTransformation.Nullify(); + switch (myLightSource->Type()) + { + case Graphic3d_TOLS_AMBIENT: + { + if (myIsZoomable) + { + gp_Trsf aTrsf; + aTrsf.SetTranslation (gp::Origin(), myLightSource->Position()); + myLocalTransformation = new TopLoc_Datum3D (aTrsf); + } + break; + } + case Graphic3d_TOLS_DIRECTIONAL: + { + const gp_Pnt aLightPos = (myIsZoomable && !myLightSource->IsHeadlight()) + ? myLightSource->DisplayPosition() + : gp::Origin(); + gp_Trsf aTrsf; + const gp_Ax2 anAx2 (aLightPos, -myLightSource->Direction()); + aTrsf.SetTransformation (anAx2, gp_Ax3()); + myLocalTransformation = new TopLoc_Datum3D (aTrsf); + break; + } + case Graphic3d_TOLS_POSITIONAL: + { + if (myIsZoomable) + { + gp_Trsf aTrsf; + aTrsf.SetTranslation (gp::Origin(), myLightSource->Position()); + myLocalTransformation = new TopLoc_Datum3D (aTrsf); + } + break; + } + case Graphic3d_TOLS_SPOT: + { + gp_Trsf aTrsf; + const gp_Ax2 anAx2 (myIsZoomable ? myLightSource->Position() : gp::Origin(), -myLightSource->Direction()); + aTrsf.SetTransformation (anAx2, gp_Ax3()); + myLocalTransformation = new TopLoc_Datum3D (aTrsf); + break; + } + } + UpdateTransformation(); +} + +// ======================================================================= +// function : setLocalTransformation +// purpose : +// ======================================================================= +void AIS_LightSource::setLocalTransformation (const Handle(TopLoc_Datum3D)& theTrsf) +{ + const gp_Trsf aTrsf = theTrsf->Transformation(); + switch (myLightSource->Type()) + { + case Graphic3d_TOLS_AMBIENT: + { + break; + } + case Graphic3d_TOLS_DIRECTIONAL: + { + gp_Dir aNewDir = (-gp::DZ()).Transformed (aTrsf); + myLightSource->SetDirection (aNewDir); + if (myIsZoomable) + { + gp_Pnt aNewPos = gp::Origin().Transformed (aTrsf); + myLightSource->SetDisplayPosition (aNewPos); + } + break; + } + case Graphic3d_TOLS_POSITIONAL: + { + gp_Pnt aNewPos = gp::Origin().Transformed (aTrsf); + myLightSource->SetPosition (aNewPos); + break; + } + case Graphic3d_TOLS_SPOT: + { + gp_Pnt aNewPos = gp::Origin().Transformed (aTrsf); + myLightSource->SetPosition (aNewPos); + + gp_Dir aNewDir = (-gp::DZ()).Transformed (aTrsf); + myLightSource->SetDirection (aNewDir); + break; + } + } + + base_type::setLocalTransformation (new TopLoc_Datum3D (aTrsf)); + + updateLightAspects(); + updateLightTransformPersistence(); +} + +// ======================================================================= +// function : Compute +// purpose : +// ======================================================================= +void AIS_LightSource::Compute (const Handle(PrsMgr_PresentationManager3d)& , + const Handle(Prs3d_Presentation)& thePrs, + const Standard_Integer theMode) +{ + thePrs->SetInfiniteState (myInfiniteState); + if (theMode != 0 + && theMode != 1) + { + return; + } + + if (theMode == 0) + { + updateLightAspects(); + updateLightTransformPersistence(); + updateLightLocalTransformation(); + } + + switch (myLightSource->Type()) + { + case Graphic3d_TOLS_AMBIENT: computeAmbient (thePrs, theMode); break; + case Graphic3d_TOLS_DIRECTIONAL: computeDirectional(thePrs, theMode); break; + case Graphic3d_TOLS_POSITIONAL: computePositional (thePrs, theMode); break; + case Graphic3d_TOLS_SPOT: computeSpot (thePrs, theMode); break; + } + + if (myToDisplayName) + { + TCollection_AsciiString aPrefix = !myTransformPersistence.IsNull() + && myTransformPersistence->IsTrihedronOr2d() + ? "\n" : " "; + TCollection_AsciiString aName = aPrefix + myLightSource->Name(); + Prs3d_Text::Draw (thePrs->NewGroup(), myDrawer->TextAspect(), aName, gp::Origin()); + } +} + +// ======================================================================= +// function : computeAmbient +// purpose : +// ======================================================================= +void AIS_LightSource::computeAmbient (const Handle(Prs3d_Presentation)& thePrs, + const Standard_Integer theMode) +{ + const gp_XYZ aLightPos = gp::Origin().XYZ(); + if (theMode == 0) + { + Handle(Graphic3d_ArrayOfTriangles) aSphereArray = Prs3d_ToolSphere::Create (mySize * 0.25, myNbSplitsQuadric, myNbSplitsQuadric, gp_Trsf()); + Handle(Graphic3d_Group) aSphereGroup = thePrs->NewGroup(); + aSphereGroup->SetClosed (true); + aSphereGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect()); + aSphereGroup->AddPrimitiveArray (aSphereArray); + } + if (theMode == 0 + || theMode == 1) + { + const Standard_Real aLen = mySize * 0.25; + const Standard_Integer aNbArrows = 6; + const gp_Dir aDirList[6] = { -gp::DX(), gp::DX(), -gp::DY(), gp::DY(), -gp::DZ(), gp::DZ() }; + + const Prs3d_ToolCylinder aCylTool (mySize * 0.1, 0.0, mySize * 0.2, myNbSplitsArrow, myNbSplitsArrow); + Handle(Graphic3d_ArrayOfTriangles) aTrisArray = new Graphic3d_ArrayOfTriangles (aNbArrows * aCylTool.VerticesNb(), + aNbArrows * aCylTool.TrianglesNb() * 3, + Graphic3d_ArrayFlags_VertexNormal); + Handle(Graphic3d_ArrayOfSegments) aLineArray = new Graphic3d_ArrayOfSegments (aNbArrows * 2); + for (Standard_Integer anArrIter = 0; anArrIter < aNbArrows; ++anArrIter) + { + const gp_Dir& aDir = aDirList[anArrIter]; + const gp_XYZ aPnt = aLightPos + aDir.XYZ() * aLen; + if (!aLineArray.IsNull()) + { + aLineArray->AddVertex (aPnt + aDir.XYZ() * aLen * 0.5); + aLineArray->AddVertex (aPnt + aDir.XYZ() * aLen * 1.5); + } + if (!aTrisArray.IsNull()) + { + const gp_Ax3 aSystem (aPnt + aDir.XYZ() * aLen, -aDir); + gp_Trsf aTrsfCone; + aTrsfCone.SetTransformation (aSystem, gp_Ax3()); + aCylTool.FillArray (aTrisArray, aTrsfCone); + } + } + + if (!aLineArray.IsNull()) + { + Handle(Graphic3d_Group) aDirGroupShadow = thePrs->NewGroup(); + aDirGroupShadow->SetGroupPrimitivesAspect (myArrowLineAspectShadow); + aDirGroupShadow->AddPrimitiveArray (aLineArray); + } + if (!aTrisArray.IsNull()) + { + Handle(Graphic3d_Group) anArrowGroup = thePrs->NewGroup(); + anArrowGroup->SetClosed (true); + anArrowGroup->SetGroupPrimitivesAspect (myDrawer->ArrowAspect()->Aspect()); + anArrowGroup->AddPrimitiveArray (aTrisArray); + } + } + + { + Handle(Graphic3d_ArrayOfPoints) aPoints = new Graphic3d_ArrayOfPoints (1); + aPoints->AddVertex (aLightPos); + Handle(Graphic3d_Group) aGroup = thePrs->NewGroup(); + aGroup->SetGroupPrimitivesAspect (theMode == 1 ? myDrawer->PointAspect()->Aspect() : myDisabledMarkerAspect); + aGroup->AddPrimitiveArray (aPoints); + } +} + +// ======================================================================= +// function : computeDirectional +// purpose : +// ======================================================================= +void AIS_LightSource::computeDirectional (const Handle(Prs3d_Presentation)& thePrs, + const Standard_Integer theMode) +{ + const Standard_Real aDistance = mySize * 0.5; + const Standard_Real aStep = aDistance * 0.5; + + // light source direction is set to local transformation + const gp_Dir aLightDir = -gp::DZ(); + const gp_XYZ aLightPos = -aStep * aLightDir.XYZ(); + + Standard_Integer aNbArrows = 1; + if (myNbArrows >= 9) { aNbArrows = 9; } + else if (myNbArrows >= 5) { aNbArrows = 5; } + else if (myNbArrows >= 3) { aNbArrows = 3; } + TColgp_Array1OfPnt aPoints (1, aNbArrows); + { + const gp_Ax2 anAxes (gp::Origin(), aLightDir); + const gp_XYZ aDY = anAxes.YDirection().XYZ() * aStep; + const gp_XYZ aDX = anAxes.XDirection().XYZ() * aStep; + const gp_XYZ aDXY = aDX + aDY; + switch (aNbArrows) + { + case 9: + { + aPoints.SetValue (6, aLightPos + aDY); + aPoints.SetValue (7, aLightPos + aDX); + aPoints.SetValue (8, aLightPos - aDY); + aPoints.SetValue (9, aLightPos - aDX); + } + Standard_FALLTHROUGH + case 5: + { + aPoints.SetValue (4, aLightPos - aDY + aDX); + aPoints.SetValue (5, aLightPos + aDY - aDX); + } + Standard_FALLTHROUGH + case 3: + { + aPoints.SetValue (2, aLightPos + aDXY); + aPoints.SetValue (3, aLightPos - aDXY); + } + Standard_FALLTHROUGH + case 1: + { + aPoints.SetValue (1, aLightPos); + break; + } + } + } + + const Prs3d_ToolCylinder aCylTool (aDistance * 0.1, 0.0, aDistance * 0.2, myNbSplitsArrow, myNbSplitsArrow); + Handle(Graphic3d_ArrayOfTriangles) aTrisArray; + if (theMode == 0) + { + aTrisArray = new Graphic3d_ArrayOfTriangles (aNbArrows * aCylTool.VerticesNb(), + aNbArrows * aCylTool.TrianglesNb() * 3, + Graphic3d_ArrayFlags_VertexNormal); + } + Handle(Graphic3d_ArrayOfPoints) aPntArray = new Graphic3d_ArrayOfPoints (aNbArrows); + Handle(Graphic3d_ArrayOfSegments) aLineArray = new Graphic3d_ArrayOfSegments (aNbArrows * 2); + for (Standard_Integer aPntIter = aPoints.Lower(); aPntIter <= aPoints.Upper(); ++aPntIter) + { + const gp_Pnt aPnt = aPoints.Value (aPntIter); + if (!aPntArray.IsNull()) + { + aPntArray->AddVertex (aPnt); + } + if (!aLineArray.IsNull()) + { + aLineArray->AddVertex (aPnt); + aLineArray->AddVertex (gp_Pnt (aPnt.XYZ() + aLightDir.XYZ() * aDistance)); + } + if (!aTrisArray.IsNull()) + { + const gp_Ax3 aSystem (aPnt.XYZ() + aLightDir.XYZ() * aDistance, aLightDir); + gp_Trsf aTrsfCone; + aTrsfCone.SetTransformation (aSystem, gp_Ax3()); + aCylTool.FillArray (aTrisArray, aTrsfCone); + } + } + + if (!aLineArray.IsNull() && theMode == 0) + { + Handle(Graphic3d_Group) aDirGroupShadow = thePrs->NewGroup(); + aDirGroupShadow->SetGroupPrimitivesAspect (myArrowLineAspectShadow); + aDirGroupShadow->AddPrimitiveArray (aLineArray); + } + if (!aLineArray.IsNull()) + { + Handle(Graphic3d_Group) aDirGroup = thePrs->NewGroup(); + aDirGroup->SetGroupPrimitivesAspect (myDrawer->ArrowAspect()->Aspect()); + aDirGroup->AddPrimitiveArray (aLineArray); + } + if (!aTrisArray.IsNull()) + { + Handle(Graphic3d_Group) anArrowGroup = thePrs->NewGroup(); + anArrowGroup->SetClosed (true); + anArrowGroup->SetGroupPrimitivesAspect (myDrawer->ArrowAspect()->Aspect()); + anArrowGroup->AddPrimitiveArray (aTrisArray); + } + if (!aPntArray.IsNull()) + { + Handle(Graphic3d_Group) aGroup = thePrs->NewGroup(); + aGroup->SetGroupPrimitivesAspect (myDrawer->ArrowAspect()->Aspect()); + aGroup->AddPrimitiveArray (aPntArray); + } + { + Handle(Graphic3d_ArrayOfPoints) aPntArray2 = new Graphic3d_ArrayOfPoints (1); + aPntArray2->AddVertex (aLightPos); + Handle(Graphic3d_Group) aGroup = thePrs->NewGroup(); + aGroup->SetGroupPrimitivesAspect (myDisabledMarkerAspect); + aGroup->AddPrimitiveArray (aPntArray2); + } +} + +// ======================================================================= +// function : computePositional +// purpose : +// ======================================================================= +void AIS_LightSource::computePositional (const Handle(Prs3d_Presentation)& thePrs, + const Standard_Integer theMode) +{ + // light source position is set to local transformation + const gp_XYZ aLightPos = gp::Origin().XYZ(); + const Standard_Real aRadius = (myIsZoomable && myLightSource->HasRange()) ? myLightSource->Range() : 0.0; + if (theMode == 0 + && aRadius > 0.0 + && myToDisplayRange) + { + Handle(Graphic3d_ArrayOfTriangles) aPosRangeArray = Prs3d_ToolSphere::Create (aRadius, myNbSplitsQuadric, myNbSplitsQuadric, gp_Trsf()); + Handle(Graphic3d_Group) aRangeGroup = thePrs->NewGroup(); + aRangeGroup->SetClosed (true); + aRangeGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect()); + aRangeGroup->AddPrimitiveArray (aPosRangeArray); + } + { + Handle(Graphic3d_ArrayOfPoints) aPoints = new Graphic3d_ArrayOfPoints (1); + aPoints->AddVertex (aLightPos); + Handle(Graphic3d_Group) aGroup = thePrs->NewGroup(); + aGroup->SetGroupPrimitivesAspect (myDrawer->PointAspect()->Aspect()); + aGroup->AddPrimitiveArray (aPoints); + } +} + +// ======================================================================= +// function : computeSpot +// purpose : +// ======================================================================= +void AIS_LightSource::computeSpot (const Handle(Prs3d_Presentation)& thePrs, + const Standard_Integer theMode) +{ + // light source position and direction are set to local transformation + const gp_Dir aLightDir = -gp::DZ(); + const gp_XYZ aLightPos = gp::Origin().XYZ(); + const Standard_Real aDistance = (myIsZoomable && myLightSource->HasRange()) ? myLightSource->Range() : mySize; + { + Handle(Graphic3d_ArrayOfPoints) aPoints = new Graphic3d_ArrayOfPoints (1); + aPoints->AddVertex (aLightPos); + + Handle(Graphic3d_Group) aGroup = thePrs->NewGroup(); + aGroup->SetGroupPrimitivesAspect (myDrawer->PointAspect()->Aspect()); + aGroup->AddPrimitiveArray (aPoints); + } + + { + Handle(Graphic3d_ArrayOfSegments) aDirArray = new Graphic3d_ArrayOfSegments (2); + aDirArray->AddVertex (aLightPos); + aDirArray->AddVertex (gp_Pnt (aLightPos + aLightDir.XYZ() * aDistance)); + + Handle(Graphic3d_Group) aDirGroupShadow = thePrs->NewGroup(); + aDirGroupShadow->SetClosed (true); + aDirGroupShadow->SetGroupPrimitivesAspect (myArrowLineAspectShadow); + aDirGroupShadow->AddPrimitiveArray (aDirArray); + + Handle(Graphic3d_Group) aDirGroup = thePrs->NewGroup(); + aDirGroup->SetClosed (true); + aDirGroup->SetGroupPrimitivesAspect (myDrawer->ArrowAspect()->Aspect()); + aDirGroup->AddPrimitiveArray (aDirArray); + } + + if (theMode == 0 + && myToDisplayRange) + { + const Standard_ShortReal aHalfAngle = myLightSource->Angle() / 2.0f; + const Standard_Real aRadius = aDistance * Tan (aHalfAngle); + gp_Ax3 aSystem (aLightPos + aLightDir.XYZ() * aDistance, -aLightDir); + gp_Trsf aTrsfCone; + aTrsfCone.SetTransformation (aSystem, gp_Ax3()); + Handle(Graphic3d_ArrayOfTriangles) aSpotRangeArray = Prs3d_ToolCylinder::Create (aRadius, 0.0, aDistance, + myNbSplitsQuadric, myNbSplitsQuadric, aTrsfCone); + + Handle(Graphic3d_Group) aRangeGroup = thePrs->NewGroup(); + aRangeGroup->SetClosed (true); + aRangeGroup->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect()); + aRangeGroup->AddPrimitiveArray (aSpotRangeArray); + } +} + +// ======================================================================= +// function : ComputeSelection +// purpose : +// ======================================================================= +void AIS_LightSource::ComputeSelection (const Handle(SelectMgr_Selection)& theSel, + const Standard_Integer theMode) +{ + if (theMode != 0) + { + return; + } + + Handle(AIS_LightSourceOwner) anEntityOwner = new AIS_LightSourceOwner (this, 15); + { + Handle(Select3D_SensitivePoint) aSensPosition = new Select3D_SensitivePoint (anEntityOwner, gp::Origin()); + aSensPosition->SetSensitivityFactor (12); + if (!myTransformPersistence.IsNull() + && myTransformPersistence->IsTrihedronOr2d()) + { + aSensPosition->SetSensitivityFactor (Max (12, Standard_Integer (mySize * 0.5))); + } + theSel->Add (aSensPosition); + } +} diff --git a/src/AIS/AIS_LightSource.hxx b/src/AIS/AIS_LightSource.hxx new file mode 100644 index 0000000000..27b0bda4c6 --- /dev/null +++ b/src/AIS/AIS_LightSource.hxx @@ -0,0 +1,253 @@ +// Created on: 2020-09-07 +// Created by: Maria KRYLOVA +// Copyright (c) 2020 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 _AIS_LightSource_HeaderFile +#define _AIS_LightSource_HeaderFile + +#include +#include +#include + +class Prs3d_ShadingAspect; + +//! Interactive object for a light source. +//! Each type of light source has it's own presentation: +//! - Ambient light is displayed as a sphere at view corner; +//! - Positional light is represented by a sphere or marker; +//! - Spot light is represented by a cone; +//! - Directional light is represented by a set of arrows at the corner of view. +//! In addition, light source name could be displayed, and clicking on presentation will enable/disable light. +class AIS_LightSource : public AIS_InteractiveObject +{ + friend class AIS_LightSourceOwner; + DEFINE_STANDARD_RTTIEXT(AIS_LightSource, AIS_InteractiveObject) +public: + + //! Initializes the light source by copying Graphic3d_CLight settings. + Standard_EXPORT AIS_LightSource (const Handle(Graphic3d_CLight)& theLightSource); + + //! Returns the light. + const Handle(Graphic3d_CLight)& Light() const { return myLightSource; } + + //! Set the light. + void SetLight (const Handle(Graphic3d_CLight)& theLight) + { + myLightSource = theLight; + SetToUpdate(); + } + +public: //! @name Light properties + + //! Returns TRUE if the light source name should be displayed; TRUE by default. + Standard_Boolean ToDisplayName() const { return myToDisplayName; } + + //! Show/hide light source name. + void SetDisplayName(Standard_Boolean theToDisplay) + { + if (myToDisplayName != theToDisplay) + { + myToDisplayName = theToDisplay; + SetToUpdate(); + } + } + + //! Returns TRUE to display light source range as sphere (positional light) or cone (spot light); TRUE by default. + //! Has no effect for non-zoomable presentation. + Standard_Boolean ToDisplayRange() const { return myToDisplayRange; } + + //! Show/hide light source range shaded presentation. + void SetDisplayRange (Standard_Boolean theToDisplay) + { + if (myToDisplayRange != theToDisplay) + { + myToDisplayRange = theToDisplay; + SetToUpdate(); + } + } + + //! Returns the size of presentation; 50 by default. + Standard_Real Size() const { return mySize; } + + //! Sets the size of presentation. + void SetSize (Standard_Real theSize) + { + if (mySize != theSize) + { + mySize = theSize; + SetToUpdate(); + } + } + + //! Returns TRUE if transform-persistence is allowed; + //! TRUE by default for Ambient and Directional lights + //! and FALSE by default for Positional and Spot lights. + bool IsZoomable() const { return myIsZoomable; } + + //! Sets if transform-persistence is allowed. + void SetZoomable (bool theIsZoomable) + { + if (myIsZoomable != theIsZoomable) + { + myIsZoomable = theIsZoomable; + SetToUpdate(); + } + } + + //! Returns TRUE if mouse click will turn light on/off; TRUE by default. + bool ToSwitchOnClick() const { return myToSwitchOnClick; } + + //! Sets if mouse click should turn light on/off. + void SetSwitchOnClick (bool theToHandle) { myToSwitchOnClick = theToHandle; } + + //! Returns a number of directional light arrows to display; 5 by default. + Standard_Integer NbArrows() const { return myNbArrows; } + + //! Returns a number of directional light arrows to display (supported values: 1, 3, 5, 9). + void SetNbArrows (Standard_Integer theNbArrows) + { + if (myNbArrows != theNbArrows) + { + myNbArrows = theNbArrows; + SetToUpdate(); + } + } + + //! Returns light source icon. + //! @param theIsEnabled [in] marker index for enabled/disabled light source states + const Handle(Graphic3d_MarkerImage)& MarkerImage (bool theIsEnabled) const { return myMarkerImages[theIsEnabled ? 1 : 0]; } + + //! Returns light source icon. + //! @param theIsEnabled [in] marker index for enabled/disabled light source states + Aspect_TypeOfMarker MarkerType (bool theIsEnabled) const { return myMarkerTypes[theIsEnabled ? 1 : 0]; } + + //! Sets custom icon to light source. + void SetMarkerImage (const Handle(Graphic3d_MarkerImage)& theImage, + bool theIsEnabled) + { + myMarkerImages[theIsEnabled ? 1 : 0] = theImage; + myMarkerTypes [theIsEnabled ? 1 : 0] = !theImage.IsNull() + ? Aspect_TOM_USERDEFINED + : (theIsEnabled ? Aspect_TOM_O_POINT : Aspect_TOM_O_X); + } + + //! Sets standard icon to light source. + void SetMarkerType (Aspect_TypeOfMarker theType, + bool theIsEnabled) + { + myMarkerTypes[theIsEnabled ? 1 : 0] = theType; + } + + //! Returns tessellation level for quadric surfaces; 30 by default. + Standard_Integer NbSplitsQuadric() const { return myNbSplitsQuadric; } + + //! Sets tessellation level for quadric surfaces. + void SetNbSplitsQuadric (Standard_Integer theNbSplits) { myNbSplitsQuadric = theNbSplits; } + + //! Returns tessellation level for arrows; 20 by default. + Standard_Integer NbSplitsArrow() const { return myNbSplitsArrow; } + + //! Sets tessellation level for arrows. + void SetNbSplitsArrow (Standard_Integer theNbSplits) { myNbSplitsArrow = theNbSplits; } + + //! Returns kind of the object. + virtual AIS_KindOfInteractive Type() const Standard_OVERRIDE { return AIS_KindOfInteractive_LightSource; } + +protected: + + //! Return true if specified display mode is supported: 0 for main presentation and 1 for highlight. + virtual Standard_Boolean AcceptDisplayMode (const Standard_Integer theMode) const Standard_OVERRIDE + { + return theMode == 0 + || theMode == 1; + } + + //! Computes selection sensitive zones(triangulation) for light source presentation. + Standard_EXPORT virtual void Compute (const Handle(PrsMgr_PresentationManager3d)& thePrsMgr, + const Handle(Prs3d_Presentation)& thePrs, + const Standard_Integer theMode) Standard_OVERRIDE; + + //! Fills presentation. + Standard_EXPORT virtual void ComputeSelection (const Handle(SelectMgr_Selection)& theSel, + const Standard_Integer theMode) Standard_OVERRIDE; + + //! Sets new local transformation, which is propagated to Graphic3d_CLight instance. + Standard_EXPORT virtual void setLocalTransformation (const Handle(TopLoc_Datum3D)& theTrsf) Standard_OVERRIDE; + + //! Updates local transformation basing on a type of light source. + Standard_EXPORT virtual void updateLightLocalTransformation(); + + //! Updates transform persistence basing on a type of light source. + Standard_EXPORT virtual void updateLightTransformPersistence(); + + //! Sets color of light. + Standard_EXPORT virtual void updateLightAspects(); + + //! Compute ambient light source presentation as a sphere at view corner. + Standard_EXPORT virtual void computeAmbient (const Handle(Prs3d_Presentation)& thePrs, + const Standard_Integer theMode); + + //! Compute directional light source presentation as a set of arrows at view corner. + Standard_EXPORT virtual void computeDirectional (const Handle(Prs3d_Presentation)& thePrs, + const Standard_Integer theMode); + + //! Compute positional light source presentation as a sphere of either fixed size (no range) or of size representing a maximum range. + Standard_EXPORT virtual void computePositional (const Handle(Prs3d_Presentation)& thePrs, + const Standard_Integer theMode); + + //! Compute spot light source presentation as a cone. + Standard_EXPORT virtual void computeSpot (const Handle(Prs3d_Presentation)& thePrs, + const Standard_Integer theMode); + +protected: + + Handle(Graphic3d_CLight) myLightSource; //!< displayed light source + + Handle(Graphic3d_AspectMarker3d) myDisabledMarkerAspect; //!< disabled light source marker style + Handle(Graphic3d_AspectLine3d) myArrowLineAspectShadow; //!< arrow shadow style + Handle(Graphic3d_MarkerImage) myMarkerImages[2]; //!< icon of disabled (0) and enabled (1) light + Aspect_TypeOfMarker myMarkerTypes[2]; //!< icon of disabled (0) and enabled (1) light + Aspect_TypeOfMarker myCodirMarkerType; //!< icon of arrow co-directional to camera direction (look from) + Aspect_TypeOfMarker myOpposMarkerType; //!< icon of arrow opposite to camera direction (look at) + + Standard_Real mySize; //!< presentation size + Standard_Integer myNbArrows; //!< number of directional light arrows + Standard_Integer myNbSplitsQuadric; //!< tessellation level for quadric surfaces + Standard_Integer myNbSplitsArrow; //!< tessellation level for arrows + Standard_Boolean myIsZoomable; //!< flag to allow/disallow transform-persistence when possible + Standard_Boolean myToDisplayName; //!< flag to show/hide name + Standard_Boolean myToDisplayRange; //!< flag to show/hide range of positional/spot light + Standard_Boolean myToSwitchOnClick; //!< flag to handle mouse click to turn light on/off + +}; + +//! Owner of AIS_LightSource presentation. +class AIS_LightSourceOwner : public SelectMgr_EntityOwner +{ + DEFINE_STANDARD_RTTIEXT(AIS_LightSourceOwner, SelectMgr_EntityOwner) +public: + + //! Main constructor. + Standard_EXPORT AIS_LightSourceOwner (const Handle(AIS_LightSource)& theObject, + Standard_Integer thePriority = 5); + + //! Handle mouse button click event. + Standard_EXPORT virtual Standard_Boolean HandleMouseClick (const Graphic3d_Vec2i& thePoint, + Aspect_VKeyMouse theButton, + Aspect_VKeyFlags theModifiers, + bool theIsDoubleClick) Standard_OVERRIDE; + +}; + +#endif // _AIS_LightSource_HeaderFile diff --git a/src/AIS/FILES b/src/AIS/FILES index 3720f133cb..6c0ef38ec4 100644 --- a/src/AIS/FILES +++ b/src/AIS/FILES @@ -54,6 +54,8 @@ AIS_InteractiveContext_3.cxx AIS_InteractiveObject.cxx AIS_InteractiveObject.hxx AIS_KindOfInteractive.hxx +AIS_LightSource.cxx +AIS_LightSource.hxx AIS_Line.cxx AIS_Line.hxx AIS_ListIteratorOfListOfInteractive.hxx diff --git a/src/Graphic3d/Graphic3d_CLight.cxx b/src/Graphic3d/Graphic3d_CLight.cxx index 182cbe06c1..228c6a64f8 100644 --- a/src/Graphic3d/Graphic3d_CLight.cxx +++ b/src/Graphic3d/Graphic3d_CLight.cxx @@ -164,7 +164,19 @@ void Graphic3d_CLight::SetPosition (const gp_Pnt& thePosition) { Standard_ProgramError_Raise_if (myType != Graphic3d_TOLS_SPOT && myType != Graphic3d_TOLS_POSITIONAL, - "Graphic3d_CLight::SetDirection(), incorrect light type"); + "Graphic3d_CLight::SetPosition(), incorrect light type"); + updateRevisionIf (!myPosition.IsEqual (thePosition, gp::Resolution())); + myPosition = thePosition; +} + +// ======================================================================= +// function : SetDisplayPosition +// purpose : +// ======================================================================= +void Graphic3d_CLight::SetDisplayPosition (const gp_Pnt& thePosition) +{ + Standard_ProgramError_Raise_if (myType == Graphic3d_TOLS_AMBIENT, + "Graphic3d_CLight::SetDisplayPosition(), incorrect light type"); updateRevisionIf (!myPosition.IsEqual (thePosition, gp::Resolution())); myPosition = thePosition; } diff --git a/src/Graphic3d/Graphic3d_CLight.hxx b/src/Graphic3d/Graphic3d_CLight.hxx index 12fbd73923..cb44777709 100644 --- a/src/Graphic3d/Graphic3d_CLight.hxx +++ b/src/Graphic3d/Graphic3d_CLight.hxx @@ -145,6 +145,14 @@ public: //! Sets direction of directional/spot light. void SetDirection (Standard_Real theVx, Standard_Real theVy, Standard_Real theVz) { SetDirection (gp_Dir (theVx, theVy, theVz)); } + //! Returns location of positional/spot/directional light, which is the same as returned by Position(). + const gp_Pnt& DisplayPosition() const { return myPosition; } + + //! Setup location of positional/spot/directional light, + //! which is the same as SetPosition() but allows directional light source + //! (technically having no position, but this point can be used for displaying light source presentation). + Standard_EXPORT void SetDisplayPosition (const gp_Pnt& thePosition); + //! @name spotlight additional definition parameters public: @@ -184,6 +192,9 @@ public: //! Modifies the smoothing angle (in radians) of directional light source; should be within range [0.0, M_PI/2]. Standard_EXPORT void SetSmoothAngle (Standard_ShortReal theValue); + //! Returns TRUE if maximum distance of point light source is defined. + bool HasRange() const { return myDirection.w() != 0.0f; } + //! Returns maximum distance on which point light source affects to objects and is considered during illumination calculations. //! 0.0 means disabling range considering at all without any distance limits. //! Has sense only for point light sources (positional and spot). diff --git a/src/Graphic3d/Graphic3d_TransModeFlags.hxx b/src/Graphic3d/Graphic3d_TransModeFlags.hxx index 550851f896..ae5f8f8019 100644 --- a/src/Graphic3d/Graphic3d_TransModeFlags.hxx +++ b/src/Graphic3d/Graphic3d_TransModeFlags.hxx @@ -24,6 +24,7 @@ enum Graphic3d_TransModeFlags Graphic3d_TMF_RotatePers = 0x0008, //!< object does not rotate; Graphic3d_TMF_TriedronPers = 0x0020, //!< object behaves like trihedron - it is fixed at the corner of view and does not resizing (but rotating) Graphic3d_TMF_2d = 0x0040, //!< object is defined in 2D screen coordinates (pixels) and does not resize, pan and rotate + Graphic3d_TMF_CameraPers = 0x0080, //!< object is in front of the camera Graphic3d_TMF_ZoomRotatePers = Graphic3d_TMF_ZoomPers | Graphic3d_TMF_RotatePers //!< object doesn't resize and rotate }; diff --git a/src/Graphic3d/Graphic3d_TransformPers.hxx b/src/Graphic3d/Graphic3d_TransformPers.hxx index 7bd40ed6e3..743b841f2a 100644 --- a/src/Graphic3d/Graphic3d_TransformPers.hxx +++ b/src/Graphic3d/Graphic3d_TransformPers.hxx @@ -73,6 +73,10 @@ public: { SetPersistence (theMode, Aspect_TOTP_LEFT_LOWER, Graphic3d_Vec2i (0, 0)); } + else if (theMode == Graphic3d_TMF_CameraPers) + { + myMode = theMode; + } else { throw Standard_ProgramError("Graphic3d_TransformPers::SetPersistence(), wrong persistence mode."); @@ -423,6 +427,10 @@ void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera, Graphic3d_TransformUtils::Scale (theWorldView, T(aScale), T(aScale), T(aScale)); return; } + else if ((myMode & Graphic3d_TMF_CameraPers) != 0) + { + theWorldView.InitIdentity(); + } else { // Compute reference point for transformation in untransformed projection space. diff --git a/src/OpenGl/OpenGl_Structure.cxx b/src/OpenGl/OpenGl_Structure.cxx index ac9e12d93b..1b4af0316e 100644 --- a/src/OpenGl/OpenGl_Structure.cxx +++ b/src/OpenGl/OpenGl_Structure.cxx @@ -441,6 +441,9 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con #endif bool anOldCastShadows = false; +#ifdef GL_DEPTH_CLAMP + bool toRestoreDepthClamp = false; +#endif if (!myTrsfPers.IsNull()) { // temporarily disable shadows on non-3d objects @@ -463,6 +466,15 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con } } #endif + + #ifdef GL_DEPTH_CLAMP + if (myTrsfPers->Mode() == Graphic3d_TMF_CameraPers + && aCtx->arbDepthClamp) + { + toRestoreDepthClamp = true; + aCtx->core11fwd->glEnable (GL_DEPTH_CLAMP); + } + #endif } // Take into account transform persistence @@ -613,6 +625,9 @@ void OpenGl_Structure::Render (const Handle(OpenGl_Workspace) &theWorkspace) con { aCtx->WorldViewState.Pop(); aCtx->ShaderManager()->SetCastShadows (anOldCastShadows); + #ifdef GL_DEPTH_CLAMP + if (toRestoreDepthClamp) { aCtx->core11fwd->glDisable (GL_DEPTH_CLAMP); } + #endif } // Restore named status diff --git a/src/Prs3d/Prs3d_ToolQuadric.hxx b/src/Prs3d/Prs3d_ToolQuadric.hxx index a041919c88..b5e8f65011 100644 --- a/src/Prs3d/Prs3d_ToolQuadric.hxx +++ b/src/Prs3d/Prs3d_ToolQuadric.hxx @@ -63,6 +63,17 @@ public: Standard_EXPORT void FillArray (Handle(Graphic3d_ArrayOfTriangles)& theArray, const gp_Trsf& theTrsf) const; + //! Return number of triangles in generated presentation. + Standard_Integer TrianglesNb() const { return mySlicesNb * myStacksNb * 2; } + + //! Return number of vertices in generated presentation. + Standard_Integer VerticesNb (bool theIsIndexed = true) const + { + return theIsIndexed + ? (mySlicesNb + 1) * (myStacksNb + 1) + : TrianglesNb() * 3; + } + public: //! Generate primitives for 3D quadric surface presentation. @@ -76,20 +87,6 @@ public: protected: - //! Return number of triangles in generated presentation. - Standard_Integer TrianglesNb() const - { - return mySlicesNb * myStacksNb * 2; - } - - //! Return number of vertices in generated presentation. - Standard_Integer VerticesNb (const Standard_Boolean theIsIndexed = Standard_True) const - { - return theIsIndexed - ? (mySlicesNb + 1) * (myStacksNb + 1) - : TrianglesNb() * 3; - } - //! Redefine this method to generate vertex at given parameters. virtual gp_Pnt Vertex (const Standard_Real theU, const Standard_Real theV) const = 0; diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 338025686e..a99bcfdee6 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -10728,6 +10729,31 @@ inline Standard_Integer getLightId (const TCollection_AsciiString& theArgNext) } } +static Handle(AIS_LightSource) findLightPrs (const Handle(V3d_Light)& theLight, + const bool theToShowErrors = true) +{ + if (theLight.IsNull()) + { + if (theToShowErrors) + { + Message::SendFail() << "Syntax error: no active light source to find presentation"; + } + return Handle(AIS_LightSource)(); + } + + Handle(AIS_InteractiveObject) anObject; + GetMapOfAIS().Find2 (theLight->Name(), anObject); + Handle(AIS_LightSource) aLightSource = Handle(AIS_LightSource)::DownCast (anObject); + if (aLightSource.IsNull()) + { + if (theToShowErrors) + { + Message::SendFail() << "Syntax error: could not find '" << theLight->Name() << "' AIS object"; + } + } + return aLightSource; +} + //=============================================================================================== //function : VLight //purpose : @@ -10818,8 +10844,7 @@ static int VLight (Draw_Interpretor& theDi, } } - Handle(V3d_Light) aLightNew; - Handle(V3d_Light) aLightOld; + Handle(V3d_Light) aLightNew, aLightOld; Graphic3d_ZLayerId aLayer = Graphic3d_ZLayerId_UNKNOWN; Standard_Boolean isGlobal = Standard_True; Standard_Boolean toCreate = Standard_False; @@ -10938,9 +10963,15 @@ static int VLight (Draw_Interpretor& theDi, if (aLayer == Graphic3d_ZLayerId_UNKNOWN) { + ViewerTest_DoubleMapOfInteractiveAndName aMap = GetMapOfAIS(); for (V3d_ListOfLightIterator aLightIter (aView->ActiveLightIterator()); aLightIter.More();) { Handle(V3d_Light) aLight = aLightIter.Value(); + if (Handle(AIS_LightSource) aLightSourceDel = findLightPrs (aLight, false)) + { + ViewerTest::GetAISContext()->Remove (aLightSourceDel, false); + GetMapOfAIS().UnBind2 (aLight->Name()); + } aViewer->DelLight (aLight); aLightIter = aView->ActiveLightIterator(); } @@ -11027,10 +11058,48 @@ static int VLight (Draw_Interpretor& theDi, return 1; } } - else if (anArgCase.IsEqual ("DEL") - || anArgCase.IsEqual ("DELETE") - || anArgCase.IsEqual ("-DEL") - || anArgCase.IsEqual ("-DELETE")) + else if (anArgCase == "-DISPLAY" + || anArgCase == "-DISP" + || anArgCase == "-PRESENTATION" + || anArgCase == "-PRS") + { + if (aLightCurr.IsNull()) + { + Message::SendFail() << "Syntax error at argument '" << anArg << "'"; + return 1; + } + + TCollection_AsciiString aLightName = aLightCurr->Name(); + if (++anArgIt > theArgsNb + && aLightName.IsEmpty()) + { + Message::SendFail() << "Syntax error at argument '" << anArg << "'"; + return 1; + } + if (anArgIt < theArgsNb) + { + if (theArgVec[anArgIt][0] != '-') + { + aLightName = theArgVec[anArgIt]; + aLightCurr->SetName (aLightName); + } + else + { + --anArgIt; + } + } + if (aLightName.IsEmpty()) + { + Message::SendFail() << "Syntax error at argument '" << anArg << "'"; + return 1; + } + ViewerTest::Display (aLightName, new AIS_LightSource (aLightCurr), false); + } + else if (anArgCase == "DEL" + || anArgCase == "DELETE" + || anArgCase == "-DEL" + || anArgCase == "-DELETE" + || anArgCase == "-REMOVE") { Handle(V3d_Light) aLightDel; if (++anArgIt >= theArgsNb) @@ -11081,6 +11150,11 @@ static int VLight (Draw_Interpretor& theDi, if (aLayer == Graphic3d_ZLayerId_UNKNOWN) { + if (Handle(AIS_LightSource) aLightSourceDel = findLightPrs (aLightDel, false)) + { + ViewerTest::GetAISContext()->Remove (aLightSourceDel, false); + GetMapOfAIS().UnBind2 (aLightDel->Name()); + } aViewer->DelLight (aLightDel); } } @@ -11102,31 +11176,48 @@ static int VLight (Draw_Interpretor& theDi, } aLightCurr->SetColor (aColor); } - else if (anArgCase.IsEqual ("POS") - || anArgCase.IsEqual ("POSITION") - || anArgCase.IsEqual ("-POS") - || anArgCase.IsEqual ("-POSITION")) + else if (anArgCase == "POS" + || anArgCase == "POSITION" + || anArgCase == "-POS" + || anArgCase == "-POSITION" + || anArgCase == "-PRSPOSITION" + || anArgCase == "-PRSPOS") { + gp_XYZ aPosXYZ; if ((anArgIt + 3) >= theArgsNb - || aLightCurr.IsNull() - || (aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL - && aLightCurr->Type() != Graphic3d_TOLS_SPOT)) + || !parseXYZ (theArgVec + anArgIt + 1, aPosXYZ) + || aLightCurr.IsNull()) { Message::SendFail() << "Syntax error at argument '" << anArg << "'"; return 1; } - anXYZ[0] = Atof (theArgVec[++anArgIt]); - anXYZ[1] = Atof (theArgVec[++anArgIt]); - anXYZ[2] = Atof (theArgVec[++anArgIt]); - aLightCurr->SetPosition (anXYZ[0], anXYZ[1], anXYZ[2]); + anArgIt += 3; + if (anArgCase == "-PRSPOSITION" + || anArgCase == "-PRSPOS") + { + aLightCurr->SetDisplayPosition (aPosXYZ); + } + else + { + if (aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL + && aLightCurr->Type() != Graphic3d_TOLS_SPOT) + { + Message::SendFail() << "Syntax error at argument '" << anArg << "'"; + return 1; + } + + aLightCurr->SetPosition (aPosXYZ); + } } else if (anArgCase.IsEqual ("DIR") || anArgCase.IsEqual ("DIRECTION") || anArgCase.IsEqual ("-DIR") || anArgCase.IsEqual ("-DIRECTION")) { + gp_XYZ aDirXYZ; if ((anArgIt + 3) >= theArgsNb + || !parseXYZ (theArgVec + anArgIt + 1, aDirXYZ) || aLightCurr.IsNull() || (aLightCurr->Type() != Graphic3d_TOLS_DIRECTIONAL && aLightCurr->Type() != Graphic3d_TOLS_SPOT)) @@ -11135,10 +11226,8 @@ static int VLight (Draw_Interpretor& theDi, return 1; } - anXYZ[0] = Atof (theArgVec[++anArgIt]); - anXYZ[1] = Atof (theArgVec[++anArgIt]); - anXYZ[2] = Atof (theArgVec[++anArgIt]); - aLightCurr->SetDirection (anXYZ[0], anXYZ[1], anXYZ[2]); + anArgIt += 3; + aLightCurr->SetDirection (gp_Dir (aDirXYZ)); } else if (anArgCase.IsEqual ("SM") || anArgCase.IsEqual ("SMOOTHNESS") @@ -11203,9 +11292,9 @@ static int VLight (Draw_Interpretor& theDi, Message::SendFail() << "Syntax error at argument '" << anArg << "'"; return 1; } - Standard_ShortReal anAngle = (Standard_ShortReal )Atof (theArgVec[anArgIt]); - aLightCurr->SetAngle (Standard_ShortReal (anAngle / 180.0 * M_PI)); + anAngle = (Standard_ShortReal (anAngle / 180.0 * M_PI)); + aLightCurr->SetAngle (anAngle); } else if (anArgCase.IsEqual ("CONSTATTEN") || anArgCase.IsEqual ("CONSTATTENUATION") @@ -11275,8 +11364,8 @@ static int VLight (Draw_Interpretor& theDi, Message::SendFail() << "Syntax error at argument '" << anArg << "'"; return 1; } - - aLightCurr->SetRange ((Standard_ShortReal)Atof (theArgVec[anArgIt])); + Standard_ShortReal aRange ((Standard_ShortReal)Atof (theArgVec[anArgIt])); + aLightCurr->SetRange (aRange); } else if (anArgCase.IsEqual ("HEAD") || anArgCase.IsEqual ("HEADLIGHT") @@ -11298,6 +11387,100 @@ static int VLight (Draw_Interpretor& theDi, } aLightCurr->SetHeadlight (isHeadLight); } + else if (anArgCase.IsEqual ("NAME") + || anArgCase.IsEqual ("-NAME")) + { + if ((anArgIt + 1) >= theArgsNb + || aLightCurr.IsNull()) + { + Message::SendFail() << "Syntax error at argument '" << anArg << "'"; + return 1; + } + aName = theArgVec[++anArgIt]; + aLightCurr->SetName (aName); + } + else if (anArgCase == "-SHOWZOOMABLE" + || anArgCase == "-PRSZOOMABLE" + || anArgCase == "-ZOOMABLE") + { + if (aLightCurr.IsNull()) + { + Message::SendFail() << "Syntax error at argument '" << anArg << "'"; + return 1; + } + + if (Handle(AIS_LightSource) aLightSource = findLightPrs (aLightCurr)) + { + const bool isZoomable = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt); + aLightSource->SetZoomable (isZoomable); + } + else + { + return 1; + } + } + else if (anArgCase == "-SHOWNAME" + || anArgCase == "-PRSNAME") + { + if (aLightCurr.IsNull()) + { + Message::SendFail() << "Syntax error at argument '" << anArg << "'"; + return 1; + } + + if (Handle(AIS_LightSource) aLightSource = findLightPrs (aLightCurr)) + { + const bool toDisplay = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt); + aLightSource->SetDisplayName (toDisplay); + } + else + { + return 1; + } + } + else if (anArgCase == "-SHOWRANGE" + || anArgCase == "-PRSRANGE") + { + if (aLightCurr.IsNull() + || (aLightCurr->Type() != Graphic3d_TOLS_SPOT + && aLightCurr->Type() != Graphic3d_TOLS_POSITIONAL)) + { + Message::SendFail() << "Syntax error at argument '" << anArg << "'"; + return 1; + } + + if (Handle(AIS_LightSource) aLightSource = findLightPrs (aLightCurr)) + { + const bool toDisplay = Draw::ParseOnOffIterator (theArgsNb, theArgVec, anArgIt); + aLightSource->SetDisplayRange (toDisplay); + } + else + { + return 1; + } + } + else if (anArgCase == "-SHOWSIZE" + || anArgCase == "-PRSSIZE") + { + Standard_Real aSize = 0.0; + if ((anArgIt + 1) >= theArgsNb + || !Draw::ParseReal (theArgVec[anArgIt + 1], aSize) + || aSize <= 0.0) + { + Message::SendFail() << "Syntax error at argument '" << anArg << "'"; + return 1; + } + + ++anArgIt; + if (Handle(AIS_LightSource) aLightSource = findLightPrs (aLightCurr)) + { + aLightSource->SetSize (aSize); + } + else + { + return 1; + } + } else if (anArgCase.IsEqual ("-CASTSHADOW") || anArgCase.IsEqual ("-CASTSHADOWS") || anArgCase.IsEqual ("-SHADOWS")) @@ -11324,6 +11507,48 @@ static int VLight (Draw_Interpretor& theDi, } addLight (aLightNew, aLayer, isGlobal); + + struct LightPrsSort + { + bool operator() (const Handle(AIS_LightSource)& theLeft, + const Handle(AIS_LightSource)& theRight) + { + return theLeft->Light()->GetId() < theRight->Light()->GetId(); + } + }; + + AIS_ListOfInteractive aPrsList; + ViewerTest::GetAISContext()->DisplayedObjects (AIS_KindOfInteractive_LightSource, -1, aPrsList); + if (!aPrsList.IsEmpty()) + { + // update light source presentations + std::vector aLightPrsVec; + for (AIS_ListOfInteractive::Iterator aPrsIter (aPrsList); aPrsIter.More(); aPrsIter.Next()) + { + if (Handle(AIS_LightSource) aLightPrs = Handle(AIS_LightSource)::DownCast (aPrsIter.Value())) + { + aLightPrsVec.push_back (aLightPrs); + } + } + + // sort objects by id as AIS_InteractiveContext stores them in unordered map + std::sort (aLightPrsVec.begin(), aLightPrsVec.end(), LightPrsSort()); + + Standard_Integer aTopStack = 0; + for (std::vector::iterator aPrsIter = aLightPrsVec.begin(); aPrsIter != aLightPrsVec.end(); ++aPrsIter) + { + Handle(AIS_LightSource) aLightPrs = *aPrsIter; + if (!aLightPrs->TransformPersistence().IsNull() + && aLightPrs->TransformPersistence()->IsTrihedronOr2d()) + { + const Standard_Integer aPrsSize = (Standard_Integer )aLightPrs->Size(); + aLightPrs->TransformPersistence()->SetOffset2d (Graphic3d_Vec2i (aTopStack + aPrsSize, aPrsSize)); + aTopStack += aPrsSize + aPrsSize / 2; + } + ViewerTest::GetAISContext()->Redisplay (aLightPrs, false); + ViewerTest::GetAISContext()->SetTransformPersistence (aLightPrs, aLightPrs->TransformPersistence()); + } + } return 0; } @@ -15111,7 +15336,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands) "tool to manage light sources, without arguments shows list of lights." "\n Main commands: " "\n '-clear' to clear lights" - "\n '-{def}aults' to load deafault lights" + "\n '-{def}aults' to load default lights" "\n '-add' to add any light source" "\n where is one of {amb}ient|directional|{spot}light|positional" "\n 'change' to edit light source with specified lightId" @@ -15130,7 +15355,13 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands) "\n -{spotexp}onent value" "\n -range value" "\n -local|-global" - "\n\n example: vlight -add positional -head 1 -pos 0 1 1 -color red" + "\n -name value" + "\n -display nameOfLight (display light source with specified nameOfLight or its name)" + "\n -showName {1|0} show/hide the name of light source; 1 by default" + "\n -showRange {1|0} show/hide the range of spot/positional light source; 1 by default" + "\n -prsZoomable {1|0} make light presentation zoomable/non-zoomable" + "\n -prsSize {Value} set light presentation size" + "\n\n example: vlight -add positional -head 1 -pos 0 1 1 -color red" "\n example: vlight -change 0 -direction 0 -1 0 -linearAttenuation 0.2", __FILE__, VLight, group); theCommands.Add("vpbrenv", diff --git a/tests/v3d/grids.list b/tests/v3d/grids.list index bd75d240f6..424fa131de 100755 --- a/tests/v3d/grids.list +++ b/tests/v3d/grids.list @@ -23,3 +23,4 @@ 024 colors 025 quadric 026 shadows +027 light_source diff --git a/tests/v3d/light_source/display_all b/tests/v3d/light_source/display_all new file mode 100644 index 0000000000..85573c3f16 --- /dev/null +++ b/tests/v3d/light_source/display_all @@ -0,0 +1,63 @@ +puts "=================================" +puts "0031704: Visualization - add an interactive object AIS_LightSource representing a light source" +puts "=================================" + +pload MODELING VISUALIZATION +vclear +vinit View1 -width 1280 -height 720 +vlight -clear +vbackground -color GRAY +vrenderparams -shadingModel PBR +box b 10 10 10 30 30 30 +vdisplay b -dispMode 1 +vaspects b -material Brass +vfit + +puts "=== Add light sources and display their presentations ===" +vlight -add ambient -color WHITE -name AMBIENT -display +vlight -add directional -dir 0 1 0 -name DIR -color GREEN -display +vlight -add spotlight -pos 50 25 25 -dir -1 0 0 -intensity 1000000000 -name SPOT -color RED -display +vlight -add positional -pos 25 25 50 -intensity 10000000000 -range 20 -name POSITIONAL -color BLUE -display + +vdump $imagedir/${casename}_def.png + +puts "=== Turn off light sources ===" +set mouse_pick_amb {105 97} +set mouse_pick_spot {897 508} +set mouse_pick_pos {640 62} +set mouse_pick_dir {330 536} +vselect {*}$mouse_pick_amb +vselect {*}$mouse_pick_spot +vselect {*}$mouse_pick_pos +vselect {*}$mouse_pick_dir +vdump $imagedir/${casename}_off.png + +set aColor_spot [vreadpixel 796 454 rgb name] +set aColor_pos [vreadpixel 630 177 rgb name] +if { "$aColor_spot" != "LIGHTSALMON3" } { puts "Error: expected color near the light spot is LIGHTSALMON3" } +if { "$aColor_pos" != "THISTLE4"} { puts "Error: expected color near the positional light is THISTLE4" } + +puts "=== Delete presentations of light sources ===" +vremove AMBIENT DIR SPOT POSITIONAL + +puts "=== Display all light sources ===" +vlight -change 0 -display +vlight -change 1 -display +vlight -change 2 -display -showRange 1 +vlight -change 3 -display -showRange 1 +vdump $imagedir/${casename}_on.png + +puts "=== Turn on light sources ===" +vselect {*}$mouse_pick_amb +vselect {*}$mouse_pick_spot +vselect {*}$mouse_pick_pos +vselect {*}$mouse_pick_dir +set aColor_spot [vreadpixel 796 454 rgb name] +set aColor_pos [vreadpixel 630 177 rgb name] +set aColor_dir [vreadpixel 453 453 rgb name] +if { "$aColor_spot" != "CORAL" } { puts "Error: expected color near the light spot is CORAL" } +if { "$aColor_pos" != "LIGHTSLATEBLUE"} { puts "Error: expected color near the positional light is LIGHTSLATEBLUE" } +if { "$aColor_dir" != "BURLYWOOD3" } { puts "Error: expected color near the directional light is BURLYWOOD3" } + +#vlight -clear +#vdump $imagedir/${casename}_cleared.png diff --git a/tests/v3d/light_source/headlight b/tests/v3d/light_source/headlight new file mode 100644 index 0000000000..2b4361cc13 --- /dev/null +++ b/tests/v3d/light_source/headlight @@ -0,0 +1,28 @@ +puts "=================================" +puts "0031704: Visualization - add an interactive object AIS_LightSource representing a light source" +puts "=================================" + +pload MODELING VISUALIZATION +vclear +vinit View1 +vlight -clear +vbackground -color GRAY +vrenderparams -shadingModel PHONG +vlight -add ambient -COLOR WHITE -intensity 0.1 +box b 10 10 10 30 30 30 +vdisplay b -dispMode 1 +vaspects b -material Brass +vfit + +puts "=== Check headlight option with spotlight ===" +vlight -add spotlight -dir 0 0 -1 -head 1 -intensity 1000000000 -color GREEN -display aSpotlight +set aColor1 [vreadpixel 200 200 rgb name] +if { "$aColor1" != "GREEN" } { puts "Error: expected color near the light is GREEN" } +vdump $imagedir/${casename}_spot.png + +puts "=== Check headlight option with positional light ===" +vlight -remove 1 +vlight -add positional -head 1 -color RED -display aPosLight +set aColor2 [vreadpixel 200 200 rgb name] +if { "$aColor2" != "RED" } { puts "Error: expected color near the light is RED" } +vdump $imagedir/${casename}_pos.png diff --git a/tests/v3d/light_source/manipulator b/tests/v3d/light_source/manipulator new file mode 100644 index 0000000000..eb932165a2 --- /dev/null +++ b/tests/v3d/light_source/manipulator @@ -0,0 +1,50 @@ +puts "===================================================" +puts "0031704: Visualization - add an interactive object AIS_LightSource representing a light source" +puts "===================================================" + +pload MODELING VISUALIZATION +vclear +vinit View1 +vlight -clear +vbackground -color GRAY +vrenderparams -shadingModel PHONG +vlight -add ambient -COLOR WHITE -intensity 0.1 +box b 0 0 0 30 30 30 +vdisplay b -dispMode 1 +vsetmaterial b Brass +vfit +vlight -add spotlight -pos 15 -10 15 -dir 0 1 0 -name aSpotLight -color RED -display + +puts "=== Attach manipulator ===" +vmanipulator m -attach aSpotLight -adjustPosition location +vdump $imagedir/${casename}_manip.png + +puts "=== Test manipulator - rotation ===" +vmanipulator m -followRotation 1 + +set mouse_pick_rotate {128 231} +set mouse_drag_rotate {98 200} + +vmoveto {*}$mouse_pick_rotate +vselect {*}$mouse_pick_rotate +vmanipulator m -startTransform {*}$mouse_pick_rotate +vmanipulator m -transform {*}$mouse_drag_rotate +vmanipulator m -stopTransform +vselect 0 0 +vmoveto {*}$mouse_drag_rotate +vdump $imagedir/${casename}_rot.png + +puts "=== Test manipulator - translation ===" +set mouse_pick_translate {87 315} +set mouse_drag_translate {167 358} + +vmoveto {*}$mouse_pick_translate +vselect {*}$mouse_pick_translate +vmanipulator m -startTransform {*}$mouse_pick_translate +vmanipulator m -transform {*}$mouse_drag_translate +vmanipulator m -stopTransform +vselect 0 0 +vmoveto {*}$mouse_drag_translate +vmanipulator m -detach +vremove aSpotLight +vdump $imagedir/${casename}_trans.png diff --git a/tests/v3d/raytrace/textures b/tests/v3d/raytrace/textures index b6d3518e1e..0cff9b38ad 100644 --- a/tests/v3d/raytrace/textures +++ b/tests/v3d/raytrace/textures @@ -73,6 +73,6 @@ vfit vlight -clear vlight -add ambient vlight -add directional -dir -0.577 -0.577 -0.577 -head 1 -vlight -add directional -dir 0.577, 0.577, 0.577 -head 0 +vlight -add directional -dir 0.577 0.577 0.577 -head 0 vrenderparams -raytrace -raydepth 3 -shadows on -reflections -fsaa