0031704: Visualization - add an interactive object AIS_LightSource representing a...
authormkrylova <mkrylova@opencascade.com>
Tue, 8 Sep 2020 14:50:28 +0000 (17:50 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 11 Feb 2021 17:06:14 +0000 (20:06 +0300)
Added new class AIS_LightSource representing a light source presentation.

Graphic3d_TMF_CameraPers - added new mode to Graphic3d_TransformPers
defining 3D point relative to camera Eye position

16 files changed:
src/AIS/AIS_KindOfInteractive.hxx
src/AIS/AIS_LightSource.cxx [new file with mode: 0644]
src/AIS/AIS_LightSource.hxx [new file with mode: 0644]
src/AIS/FILES
src/Graphic3d/Graphic3d_CLight.cxx
src/Graphic3d/Graphic3d_CLight.hxx
src/Graphic3d/Graphic3d_TransModeFlags.hxx
src/Graphic3d/Graphic3d_TransformPers.hxx
src/OpenGl/OpenGl_Structure.cxx
src/Prs3d/Prs3d_ToolQuadric.hxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx
tests/v3d/grids.list
tests/v3d/light_source/display_all [new file with mode: 0644]
tests/v3d/light_source/headlight [new file with mode: 0644]
tests/v3d/light_source/manipulator [new file with mode: 0644]
tests/v3d/raytrace/textures

index 7151a05..b2e7726 100644 (file)
@@ -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 (file)
index 0000000..f5112fa
--- /dev/null
@@ -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 <AIS_LightSource.hxx>
+
+#include <AIS_InteractiveContext.hxx>
+#include <Graphic3d_ArrayOfPoints.hxx>
+#include <Graphic3d_ArrayOfSegments.hxx>
+#include <Graphic3d_ArrayOfTriangles.hxx>
+#include <Graphic3d_CView.hxx>
+#include <Graphic3d_Group.hxx>
+#include <Prs3d_ArrowAspect.hxx>
+#include <Prs3d_PointAspect.hxx>
+#include <Prs3d_Text.hxx>
+#include <Prs3d_ToolCylinder.hxx>
+#include <Prs3d_ToolSphere.hxx>
+#include <Select3D_SensitivePoint.hxx>
+#include <V3d_View.hxx>
+
+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<AIS_LightSource*>(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 (file)
index 0000000..27b0bda
--- /dev/null
@@ -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 <AIS_InteractiveObject.hxx>
+#include <Graphic3d_CLight.hxx>
+#include <SelectMgr_EntityOwner.hxx>
+
+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
index 3720f13..6c0ef38 100644 (file)
@@ -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
index 182cbe0..228c6a6 100644 (file)
@@ -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;
 }
index 12fbd73..cb44777 100644 (file)
@@ -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).  
index 550851f..ae5f8f8 100644 (file)
@@ -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
 };
index 7bd40ed..743b841 100644 (file)
@@ -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.
index ac9e12d..1b4af03 100644 (file)
@@ -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
index a041919..b5e8f65 100644 (file)
@@ -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;
 
index 3380256..a99bcfd 100644 (file)
@@ -22,6 +22,7 @@
 #include <AIS_CameraFrustum.hxx>
 #include <AIS_ColorScale.hxx>
 #include <AIS_InteractiveContext.hxx>
+#include <AIS_LightSource.hxx>
 #include <AIS_ListOfInteractive.hxx>
 #include <AIS_ListIteratorOfListOfInteractive.hxx>
 #include <AIS_Manipulator.hxx>
@@ -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<Handle(AIS_LightSource)> 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<Handle(AIS_LightSource)>::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' <type> to add any light source"
     "\n          where <type> is one of {amb}ient|directional|{spot}light|positional"
     "\n      'change' <lightId> 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",
index bd75d24..424fa13 100755 (executable)
@@ -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 (file)
index 0000000..85573c3
--- /dev/null
@@ -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 (file)
index 0000000..2b4361c
--- /dev/null
@@ -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 (file)
index 0000000..eb93216
--- /dev/null
@@ -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
index b6d3518..0cff9b3 100644 (file)
@@ -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