0028110: Configuration - specify Unicode charset instead of multibyte in project...
[occt.git] / src / ViewerTest / ViewerTest_ViewerCommands.cxx
index bd57553..b107406 100644 (file)
 // commercial license or contractual agreement.
 
 #include <OpenGl_GlCore20.hxx>
+
+#include <AIS_Animation.hxx>
+#include <AIS_AnimationCamera.hxx>
+#include <AIS_AnimationObject.hxx>
 #include <AIS_ColorScale.hxx>
 #include <AIS_Manipulator.hxx>
 #include <AIS_RubberBand.hxx>
@@ -187,6 +191,7 @@ int X_ButtonPress = 0; // Last ButtonPress position
 int Y_ButtonPress = 0;
 Standard_Boolean IsDragged = Standard_False;
 Standard_Boolean DragFirst = Standard_False;
+Standard_Boolean TheIsAnimating = Standard_False;
 
 
 Standard_EXPORT const Handle(AIS_RubberBand)& GetRubberBand()
@@ -242,15 +247,15 @@ static LRESULT WINAPI AdvViewerWindowProc(
 //purpose  :
 //==============================================================================
 
-const Handle(MMgt_TShared)& ViewerTest::WClass()
+const Handle(Standard_Transient)& ViewerTest::WClass()
 {
-  static Handle(MMgt_TShared) theWClass;
+  static Handle(Standard_Transient) theWClass;
 #if defined(_WIN32)
   if (theWClass.IsNull())
   {
     theWClass = new WNT_WClass ("GW3D_Class", (Standard_Address )AdvViewerWindowProc,
-      CS_VREDRAW | CS_HREDRAW, 0, 0,
-      ::LoadCursor (NULL, IDC_ARROW));
+                                CS_VREDRAW | CS_HREDRAW, 0, 0,
+                                ::LoadCursorW (NULL, IDC_ARROW));
   }
 #endif
   return theWClass;
@@ -446,8 +451,8 @@ void SetWindowTitle (const Handle(Aspect_Window)& theWindow,
                      Standard_CString theTitle)
 {
 #if defined(_WIN32)
-  SetWindowText ((HWND)Handle(WNT_Window)::DownCast(theWindow)->HWindow(),
-    theTitle);
+  const TCollection_ExtendedString theTitleW (theTitle);
+  SetWindowTextW ((HWND )Handle(WNT_Window)::DownCast(theWindow)->HWindow(), theTitleW.ToWideString());
 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
   SetCocoaWindowTitle (Handle(Cocoa_Window)::DownCast(theWindow), theTitle);
 #else
@@ -1569,6 +1574,12 @@ Standard_Boolean VT_ProcessButton1Press (Standard_Integer ,
                                          Standard_Boolean theToPick,
                                          Standard_Boolean theIsShift)
 {
+  if (TheIsAnimating)
+  {
+    TheIsAnimating = Standard_False;
+    return Standard_False;
+  }
+
   if (theToPick)
   {
     Standard_Real X, Y, Z;
@@ -1996,7 +2007,7 @@ static LRESULT WINAPI ViewerWindowProc( HWND hwnd,
   const Handle(V3d_View)& aView = ViewerTest::CurrentView();
   if (aView.IsNull())
   {
-    return DefWindowProc( hwnd, Msg, wParam, lParam );
+    return DefWindowProcW (hwnd, Msg, wParam, lParam);
   }
 
     PAINTSTRUCT    ps;
@@ -2164,14 +2175,11 @@ static LRESULT WINAPI ViewerWindowProc( HWND hwnd,
       break;
 
     default:
-      return( DefWindowProc( hwnd, Msg, wParam, lParam ));
+      return DefWindowProcW (hwnd, Msg, wParam, lParam);
     }
     return 0L;
 }
 
-
-
-
 //==============================================================================
 //function : ViewerMainLoop
 //purpose  : Get a Event on the view and dispatch it
@@ -2192,9 +2200,10 @@ int ViewerMainLoop(Standard_Integer argc, const char** argv)
 
     while ( Ppick == 1 ) {
       // Wait for a VT_ProcessButton1Press() to toggle pick to 1 or 0
-      if (GetMessage(&msg, NULL, 0, 0) ) {
-        TranslateMessage(&msg);
-        DispatchMessage(&msg);
+      if (GetMessageW (&msg, NULL, 0, 0))
+      {
+        TranslateMessage (&msg);
+        DispatchMessageW (&msg);
       }
     }
 
@@ -2497,33 +2506,42 @@ static void OSWindowSetup()
 
 //==============================================================================
 //function : VFit
-
-//purpose  : Fitall, no DRAW arguments
-//Draw arg : No args
+//purpose  :
 //==============================================================================
 
-static int VFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgc, const char** theArgv)
+static int VFit (Draw_Interpretor& /*theDi*/, Standard_Integer theArgNb, const char** theArgv)
 {
-  if (theArgc > 2)
+  const Handle(V3d_View) aView = ViewerTest::CurrentView();
+  if (aView.IsNull())
   {
-    std::cout << "Wrong number of arguments! Use: vfit [-selected]" << std::endl;
+    std::cout << "Error: no active viewer!\n";
+    return 1;
   }
 
-  const Handle(V3d_View) aView = ViewerTest::CurrentView();
-
-  if (theArgc == 2)
+  Standard_Boolean toFit = Standard_True;
+  ViewerTest_AutoUpdater anUpdateTool (Handle(AIS_InteractiveContext)(), aView);
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
   {
-    TCollection_AsciiString anArg (theArgv[1]);
+    TCollection_AsciiString anArg (theArgv[anArgIter]);
     anArg.LowerCase();
-    if (anArg == "-selected")
+    if (anUpdateTool.parseRedrawMode (anArg))
     {
-      ViewerTest::GetAISContext()->FitSelected (aView);
-      return 0;
+      continue;
+    }
+    else if (anArg == "-selected")
+    {
+      ViewerTest::GetAISContext()->FitSelected (aView, 0.01, Standard_False);
+      toFit = Standard_False;
+    }
+    else
+    {
+      std::cout << "Syntax error at '" << anArg << "'\n";
     }
   }
-  if (aView.IsNull() == Standard_False) {
 
-    aView->FitAll();
+  if (toFit)
+  {
+    aView->FitAll (0.01, Standard_False);
   }
   return 0;
 }
@@ -3391,11 +3409,10 @@ static int VExport(Draw_Interpretor& di, Standard_Integer argc, const char** arg
     return 1;
   }
 
+  Standard_DISABLE_DEPRECATION_WARNINGS
   try
   {
-  Standard_DISABLE_DEPRECATION_WARNINGS
     if (!V3dView->Export (argv[1], anExpFormat))
-  Standard_ENABLE_DEPRECATION_WARNINGS
     {
       di << "Error: export of image to " << aFormatStr << " failed!\n";
     }
@@ -3405,41 +3422,10 @@ static int VExport(Draw_Interpretor& di, Standard_Integer argc, const char** arg
     di << "Error: export of image to " << aFormatStr << " failed";
     di << " (exception: " << Standard_Failure::Caught()->GetMessageString() << ")";
   }
+  Standard_ENABLE_DEPRECATION_WARNINGS
   return 0;
 }
 
-//==============================================================================
-//function : VColorScale
-//purpose  : representation color scale
-//==============================================================================
-
-static Standard_Boolean checkColor (const TCollection_AsciiString& theRed,
-                                    const TCollection_AsciiString& theGreen,
-                                    const TCollection_AsciiString& theBlue,
-                                                    Standard_Real& theRedValue,
-                                                    Standard_Real& theGreenValue,
-                                                    Standard_Real& theBlueValue)
-{
-  if (!theRed.IsRealValue()
-   || !theGreen.IsRealValue()
-   || !theBlue.IsRealValue())
-  {
-    std::cout << "Error: RGB color values should be real!\n";
-    return Standard_True;
-  }
-  theRedValue = theRed    .RealValue();
-  theGreenValue = theGreen.RealValue();
-  theBlueValue = theBlue  .RealValue();
-  if (theRedValue < 0.0 || theRedValue > 1.0
-   || theGreenValue < 0.0 || theGreenValue > 1.0
-   || theBlueValue < 0.0 || theBlueValue > 1.0)
-  {
-    std::cout << "Error: RGB color values should be within range 0..1!\n";
-    return Standard_True;
-  }
-  return Standard_False;
-}
-
 static int VColorScale (Draw_Interpretor& theDI,
                         Standard_Integer  theArgNb,
                         const char**      theArgVec)
@@ -3457,57 +3443,35 @@ static int VColorScale (Draw_Interpretor& theDI,
     return 1;
   }
 
-  Handle(AIS_ColorScale) aCS;
-  // find object
-  Handle(AIS_InteractiveObject) anIObj;
+  Handle(AIS_ColorScale) aColorScale;
   if (GetMapOfAIS().IsBound2 (theArgVec[1]))
   {
-    aCS = Handle(AIS_ColorScale)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
-    if (aCS.IsNull())
+    // find existing object
+    aColorScale = Handle(AIS_ColorScale)::DownCast (GetMapOfAIS().Find2 (theArgVec[1]));
+    if (aColorScale.IsNull())
     {
       std::cout << "Error: object '" << theArgVec[1] << "'is already defined and is not a color scale!\n";
       return 1;
     }
   }
-  else
-  {
-    aCS = new AIS_ColorScale();
-    GetMapOfAIS().Bind (aCS,theArgVec[1]);
-  }
-
-  if (aCS->ZLayer() != Graphic3d_ZLayerId_TopOSD)
-  {
-    aCS->SetZLayer (Graphic3d_ZLayerId_TopOSD);
-  }
-  if (aCS->TransformPersistence().IsNull()
-   || aCS->TransformPersistence()->Mode() != Graphic3d_TMF_2d)
-  {
-    aContext->SetTransformPersistence (aCS, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
-  }
-
-  Standard_Real                   aMinRange    = aCS->GetMin();
-  Standard_Real                   aMaxRange    = aCS->GetMax();
-  Standard_Integer                aBreadth     = aCS->GetBreadth();
-  Standard_Integer                aHeight      = aCS->GetHeight();
-  Standard_Integer                aNbIntervals = aCS->GetNumberOfIntervals();
-  Standard_Integer                aTextHeight  = aCS->GetTextHeight();
-  Aspect_TypeOfColorScalePosition aLabPosition = aCS->GetLabelPosition();
-  Standard_Integer                aPosX = aCS->GetXPosition();
-  Standard_Integer                aPosY = aCS->GetYPosition();
-
-  ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
 
   if (theArgNb <= 2)
   {
+    if (aColorScale.IsNull())
+    {
+      std::cout << "Syntax error: colorscale with a given name does not exist.\n";
+      return 1;
+    }
+
     theDI << "Color scale parameters for '"<< theArgVec[1] << "':\n"
-          << "Min range: " << aMinRange << "\n"
-          << "Max range: " << aMaxRange << "\n"
-          << "Number of intervals: " << aNbIntervals << "\n"
-          << "Text height: " << aTextHeight << "\n"
-          << "Color scale position: " << aPosX <<" "<< aPosY<< "\n"
-          << "Color scale title: " << aCS->GetTitle() << "\n"
+          << "Min range: "            << aColorScale->GetMin() << "\n"
+          << "Max range: "            << aColorScale->GetMax() << "\n"
+          << "Number of intervals: "  << aColorScale->GetNumberOfIntervals() << "\n"
+          << "Text height: "          << aColorScale->GetTextHeight() << "\n"
+          << "Color scale position: " << aColorScale->GetXPosition() << " " << aColorScale->GetYPosition() << "\n"
+          << "Color scale title: "    << aColorScale->GetTitle() << "\n"
           << "Label position: ";
-    switch (aLabPosition)
+    switch (aColorScale->GetLabelPosition())
     {
       case Aspect_TOCSP_NONE:
         theDI << "None\n";
@@ -3525,6 +3489,14 @@ static int VColorScale (Draw_Interpretor& theDI,
     return 0;
   }
 
+  if (aColorScale.IsNull())
+  {
+    aColorScale = new AIS_ColorScale();
+    aColorScale->SetZLayer (Graphic3d_ZLayerId_TopOSD);
+    aContext->SetTransformPersistence (aColorScale, new Graphic3d_TransformPers (Graphic3d_TMF_2d, Aspect_TOTP_LEFT_LOWER));
+  }
+
+  ViewerTest_AutoUpdater anUpdateTool (aContext, aView);
   for (Standard_Integer anArgIter = 2; anArgIter < theArgNb; ++anArgIter)
   {
     Standard_CString        anArg = theArgVec[anArgIter];
@@ -3542,28 +3514,23 @@ static int VColorScale (Draw_Interpretor& theDI,
         return 1;
       }
 
-      TCollection_AsciiString anArg1 (theArgVec[++anArgIter]);
-      TCollection_AsciiString anArg2 (theArgVec[++anArgIter]);
-      TCollection_AsciiString anArg3 (theArgVec[++anArgIter]);
-      if (!anArg1.IsRealValue())
-      {
-        std::cout << "Error: the minRange value should be real!\n";
-        return 1;
-      }
-      else if (!anArg2.IsRealValue())
+      const TCollection_AsciiString aRangeMin    (theArgVec[++anArgIter]);
+      const TCollection_AsciiString aRangeMax    (theArgVec[++anArgIter]);
+      const TCollection_AsciiString aNbIntervals (theArgVec[++anArgIter]);
+      if (!aRangeMin.IsRealValue()
+       || !aRangeMax.IsRealValue())
       {
-        std::cout << "Error: the maxRange value should be real!\n";
+        std::cout << "Error: the range values should be real!\n";
         return 1;
       }
-      else if (!anArg3.IsIntegerValue())
+      else if (!aNbIntervals.IsIntegerValue())
       {
         std::cout << "Error: the number of intervals should be integer!\n";
         return 1;
       }
 
-      aMinRange    = anArg1.RealValue();
-      aMaxRange    = anArg2.RealValue();
-      aNbIntervals = anArg3.IntegerValue();
+      aColorScale->SetRange (aRangeMin.RealValue(), aRangeMax.RealValue());
+      aColorScale->SetNumberOfIntervals (aNbIntervals.IntegerValue());
     }
     else if (aFlag == "-font")
     {
@@ -3579,7 +3546,7 @@ static int VColorScale (Draw_Interpretor& theDI,
         return 1;
       }
 
-      aTextHeight = aFontArg.IntegerValue();
+      aColorScale->SetTextHeight (aFontArg.IntegerValue());
       anArgIter += 1;
     }
     else if (aFlag == "-textpos")
@@ -3589,8 +3556,10 @@ static int VColorScale (Draw_Interpretor& theDI,
         std::cout << "Error: wrong syntax at argument '" << anArg << "'!\n";
         return 1;
       }
+
       TCollection_AsciiString aTextPosArg(theArgVec[++anArgIter]);
       aTextPosArg.LowerCase();
+      Aspect_TypeOfColorScalePosition aLabPosition = Aspect_TOCSP_NONE;
       if (aTextPosArg == "none")
       {
         aLabPosition = Aspect_TOCSP_NONE;
@@ -3612,6 +3581,7 @@ static int VColorScale (Draw_Interpretor& theDI,
         std::cout << "Error: unknown position '" << aTextPosArg << "'!\n";
         return 1;
       }
+      aColorScale->SetLabelPosition (aLabPosition);
     }
     else if (aFlag == "-logarithmic"
           || aFlag == "-log")
@@ -3621,13 +3591,71 @@ static int VColorScale (Draw_Interpretor& theDI,
         std::cout << "Error: wrong syntax at argument '" << anArg << "'!\n";
         return 1;
       }
+
       Standard_Boolean IsLog;
       if (!ViewerTest::ParseOnOff(theArgVec[++anArgIter], IsLog))
       {
         std::cout << "Error: wrong syntax at argument '" << anArg << "'!\n";
         return 1;
       }
-      aCS->SetLogarithmic (IsLog);
+      aColorScale->SetLogarithmic (IsLog);
+    }
+    else if (aFlag == "-huerange"
+          || aFlag == "-hue")
+    {
+      if (anArgIter + 2 >= theArgNb)
+      {
+        std::cout << "Error: wrong syntax at argument '" << anArg << "'!\n";
+        return 1;
+      }
+
+      const Standard_Real aHueMin = Draw::Atof (theArgVec[++anArgIter]);
+      const Standard_Real aHueMax = Draw::Atof (theArgVec[++anArgIter]);
+      aColorScale->SetHueRange (aHueMin, aHueMax);
+    }
+    else if (aFlag == "-colorrange")
+    {
+      Quantity_Color aColorMin, aColorMax;
+      Standard_Integer aNbParsed1 = ViewerTest::ParseColor (theArgNb  - (anArgIter + 1),
+                                                            theArgVec + (anArgIter + 1),
+                                                            aColorMin);
+      anArgIter += aNbParsed1;
+      Standard_Integer aNbParsed2 = ViewerTest::ParseColor (theArgNb  - (anArgIter + 1),
+                                                            theArgVec + (anArgIter + 1),
+                                                            aColorMax);
+      anArgIter += aNbParsed2;
+      if (aNbParsed1 == 0
+       || aNbParsed2 == 0)
+      {
+        std::cerr << "Error: wrong syntax at '" << anArg << "'\n";
+        return 1;
+      }
+
+      aColorScale->SetColorRange (aColorMin, aColorMax);
+    }
+    else if (aFlag == "-reversed"
+          || aFlag == "-inverted"
+          || aFlag == "-topdown"
+          || aFlag == "-bottomup")
+    {
+      Standard_Boolean toEnable = Standard_True;
+      if (anArgIter + 1 < theArgNb
+       && ViewerTest::ParseOnOff(theArgVec[anArgIter + 1], toEnable))
+      {
+        ++anArgIter;
+      }
+      aColorScale->SetReversed ((aFlag == "-topdown") ? !toEnable : toEnable);
+    }
+    else if (aFlag == "-smooth"
+          || aFlag == "-smoothtransition")
+    {
+      Standard_Boolean toEnable = Standard_True;
+      if (anArgIter + 1 < theArgNb
+       && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
+      {
+        ++anArgIter;
+      }
+      aColorScale->SetSmoothTransition (toEnable);
     }
     else if (aFlag == "-xy")
     {
@@ -3637,20 +3665,20 @@ static int VColorScale (Draw_Interpretor& theDI,
         return 1;
       }
 
-      TCollection_AsciiString aX (theArgVec[++anArgIter]);
-      TCollection_AsciiString aY (theArgVec[++anArgIter]);
-      if (!aX.IsIntegerValue()
-       || !aY.IsIntegerValue())
+      const TCollection_AsciiString anX (theArgVec[++anArgIter]);
+      const TCollection_AsciiString anY (theArgVec[++anArgIter]);
+      if (!anX.IsIntegerValue()
+       || !anY.IsIntegerValue())
       {
         std::cout << "Error: coordinates should be integer values!\n";
         return 1;
       }
 
-      aPosX = aX.IntegerValue();
-      aPosY = aY.IntegerValue();
+      aColorScale->SetPosition (anX.IntegerValue(), anY.IntegerValue());
     }
     else if (aFlag == "-width"
-          || aFlag == "-w")
+          || aFlag == "-w"
+          || aFlag == "-breadth")
     {
       if (anArgIter + 1 >= theArgNb)
       {
@@ -3658,14 +3686,13 @@ static int VColorScale (Draw_Interpretor& theDI,
         return 1;
       }
 
-      TCollection_AsciiString aW (theArgVec[++anArgIter]);
-      if (!aW.IsIntegerValue())
+      const TCollection_AsciiString aBreadth (theArgVec[++anArgIter]);
+      if (!aBreadth.IsIntegerValue())
       {
         std::cout << "Error: a width should be an integer value!\n";
         return 1;
       }
-
-      aBreadth = aW.IntegerValue();
+      aColorScale->SetBreadth (aBreadth.IntegerValue());
     }
     else if (aFlag == "-height"
           || aFlag == "-h")
@@ -3676,75 +3703,56 @@ static int VColorScale (Draw_Interpretor& theDI,
         return 1;
       }
 
-      TCollection_AsciiString aH (theArgVec[++anArgIter]);
-      if (!aH.IsIntegerValue())
+      const TCollection_AsciiString aHeight (theArgVec[++anArgIter]);
+      if (!aHeight.IsIntegerValue())
       {
         std::cout << "Error: a width should be an integer value!\n";
         return 1;
       }
-
-      aHeight = aH.IntegerValue();
+      aColorScale->SetHeight (aHeight.IntegerValue());
     }
     else if (aFlag == "-color")
     {
-      if (aCS->GetColorType() != Aspect_TOCSD_USER)
+      if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
       {
         std::cout << "Error: wrong color type! Call -colors before to set user-specified colors!\n";
         return 1;
       }
-
-      Quantity_NameOfColor aColorName;
-      if (anArgIter + 4 >= theArgNb)
+      else if (anArgIter + 2 >= theArgNb)
       {
-        if (anArgIter + 2 >= theArgNb)
-        {
-          std::cout << "Error: wrong syntax at argument '" << anArg << "'!\n";
-          return 1;
-        }
-        else if (!Quantity_Color::ColorFromName (theArgVec[anArgIter + 2], aColorName))
-        {
-          std::cout << "Error: wrong color name: '" << theArgVec[anArgIter + 2] << "' !\n";
-          return 1;
-        }
+        std::cout << "Error: wrong syntax at argument '" << anArg << "'!\n";
+        return 1;
       }
 
-      TCollection_AsciiString anInd (theArgVec[anArgIter + 1]);
+      const TCollection_AsciiString anInd (theArgVec[++anArgIter]);
       if (!anInd.IsIntegerValue())
       {
         std::cout << "Error: Index value should be integer!\n";
         return 1;
       }
-
-      Standard_Integer anIndex = anInd.IntegerValue();
-      if (anIndex <= 0 || anIndex > aNbIntervals)
+      const Standard_Integer anIndex = anInd.IntegerValue();
+      if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals())
       {
-        std::cout << "Error: Index value should be within range 1.." << aNbIntervals <<"!\n";
+        std::cout << "Error: Index value should be within range 1.." << aColorScale->GetNumberOfIntervals() <<"!\n";
         return 1;
       }
 
-      if (Quantity_Color::ColorFromName (theArgVec[anArgIter + 2], aColorName))
-      {
-        aCS->SetIntervalColor (Quantity_Color (aColorName), anIndex);
-        aCS->SetColorType (Aspect_TOCSD_USER);
-        anArgIter += 2;
-        continue;
-      }
-
-      TCollection_AsciiString aRed   (theArgVec[anArgIter + 2]);
-      TCollection_AsciiString aGreen (theArgVec[anArgIter + 3]);
-      TCollection_AsciiString aBlue  (theArgVec[anArgIter + 4]);
-      Standard_Real aRedValue,aGreenValue, aBlueValue;
-      if(checkColor (aRed, aGreen, aBlue, aRedValue, aGreenValue, aBlueValue))
+      Quantity_Color aColor;
+      Standard_Integer aNbParsed = ViewerTest::ParseColor (theArgNb  - (anArgIter + 1),
+                                                           theArgVec + (anArgIter + 1),
+                                                           aColor);
+      if (aNbParsed == 0)
       {
+        std::cerr << "Error: wrong syntax at '" << anArg << "'\n";
         return 1;
       }
-      aCS->SetIntervalColor (Quantity_Color (aRedValue, aGreenValue, aBlueValue, Quantity_TOC_RGB), anIndex);
-      aCS->SetColorType (Aspect_TOCSD_USER);
-      anArgIter += 4;
+      aColorScale->SetIntervalColor (aColor, anIndex);
+      aColorScale->SetColorType (Aspect_TOCSD_USER);
+      anArgIter += aNbParsed;
     }
     else if (aFlag == "-label")
     {
-      if (aCS->GetColorType() != Aspect_TOCSD_USER)
+      if (aColorScale->GetColorType() != Aspect_TOCSD_USER)
       {
         std::cout << "Error: wrong label type! Call -labels before to set user-specified labels!\n";
         return 1;
@@ -3756,90 +3764,115 @@ static int VColorScale (Draw_Interpretor& theDI,
       }
 
       Standard_Integer anIndex = Draw::Atoi (theArgVec[anArgIter + 1]);
-      if (anIndex <= 0 || anIndex > aNbIntervals+1)
+      if (anIndex <= 0 || anIndex > aColorScale->GetNumberOfIntervals() + 1)
       {
-        std::cout << "Error: Index value should be within range 1.." << aNbIntervals+1 <<"!\n";
+        std::cout << "Error: Index value should be within range 1.." << aColorScale->GetNumberOfIntervals() + 1 <<"!\n";
         return 1;
       }
 
       TCollection_ExtendedString aText (theArgVec[anArgIter + 2]);
-      aCS->SetLabel     (aText, anIndex);
-      aCS->SetLabelType (Aspect_TOCSD_USER);
+      aColorScale->SetLabel     (aText, anIndex);
+      aColorScale->SetLabelType (Aspect_TOCSD_USER);
       anArgIter += 2;
     }
-    else if (aFlag == "-colors")
+    else if (aFlag == "-labelat"
+          || aFlag == "-labat"
+          || aFlag == "-labelatborder"
+          || aFlag == "-labatborder"
+          || aFlag == "-labelatcenter"
+          || aFlag == "-labatcenter")
     {
-      Aspect_SequenceOfColor aSeq;
-      if (anArgIter + aNbIntervals + 1 > theArgNb)
-      {
-        std::cout << "Error: not enough arguments! You should provide color names or RGB color values for every interval of the "
-                  << aNbIntervals << " intervals\n";
-        return 1;
-      }
-
-      Standard_Integer aColorIter = anArgIter + 1;
-      while (aColorIter < theArgNb)
+      Standard_Boolean toEnable = Standard_True;
+      if (aFlag == "-labelat"
+       || aFlag == "-labat")
       {
-        if (theArgVec[aColorIter][0] == '-')
-        {
-          break;
-        }
-
-        else if (theArgVec[aColorIter][0] >= 97
-              && theArgVec[aColorIter][0] <= 122)
+        Standard_Integer aLabAtBorder = -1;
+        if (++anArgIter >= theArgNb)
         {
-          Quantity_NameOfColor aColorName;
-          if (!Quantity_Color::ColorFromName (theArgVec[aColorIter], aColorName))
+          TCollection_AsciiString anAtBorder (theArgVec[anArgIter]);
+          anAtBorder.LowerCase();
+          if (anAtBorder == "border")
           {
-            std::cout << "Error: wrong color name: " << theArgVec[aColorIter] << " !\n";
-            return 1;
+            aLabAtBorder = 1;
           }
-          aSeq.Append (Quantity_Color (aColorName));
-          aColorIter++;
-          anArgIter++;
-        }
-        else
-        {
-          TCollection_AsciiString aRed   (theArgVec[aColorIter]);
-          TCollection_AsciiString aGreen (theArgVec[aColorIter + 1]);
-          TCollection_AsciiString aBlue  (theArgVec[aColorIter + 2]);
-          Standard_Real aRedValue,aGreenValue, aBlueValue;
-          if (checkColor (aRed, aGreen, aBlue, aRedValue, aGreenValue, aBlueValue))
+          else if (anAtBorder == "center")
           {
-            return 1;
+            aLabAtBorder = 0;
           }
-          aSeq.Append (Quantity_Color (aRedValue, aGreenValue, aBlueValue, Quantity_TOC_RGB));
-          aColorIter += 3;
-          anArgIter += 3;
         }
+        if (aLabAtBorder == -1)
+        {
+          std::cout << "Syntax error at argument '" << anArg << "'!\n";
+          return 1;
+        }
+        toEnable = (aLabAtBorder == 1);
+      }
+      else if (anArgIter + 1 < theArgNb
+            && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
+      {
+        ++anArgIter;
+      }
+      aColorScale->SetLabelAtBorder (aFlag == "-labelatcenter"
+                                  || aFlag == "-labatcenter"
+                                   ? !toEnable
+                                   :  toEnable);
+    }
+    else if (aFlag == "-colors")
+    {
+      Aspect_SequenceOfColor aSeq;
+      for (;;)
+      {
+        Quantity_Color aColor;
+        Standard_Integer aNbParsed = ViewerTest::ParseColor (theArgNb  - (anArgIter + 1),
+                                                             theArgVec + (anArgIter + 1),
+                                                             aColor);
+        if (aNbParsed == 0)
+        {
+          break;
+        }
+        anArgIter += aNbParsed;
+        aSeq.Append (aColor);
       }
-      if (aSeq.Length() < aNbIntervals)
+      if (aSeq.Length() != aColorScale->GetNumberOfIntervals())
       {
         std::cout << "Error: not enough arguments! You should provide color names or RGB color values for every interval of the "
-                  << aNbIntervals << " intervals\n";
+                  << aColorScale->GetNumberOfIntervals() << " intervals\n";
         return 1;
       }
 
-      aCS->SetColors    (aSeq);
-      aCS->SetColorType (Aspect_TOCSD_USER);
+      aColorScale->SetColors    (aSeq);
+      aColorScale->SetColorType (Aspect_TOCSD_USER);
     }
-    else if (aFlag == "-labels")
+    else if (aFlag == "-labels"
+          || aFlag == "-freelabels")
     {
-      if (anArgIter + aNbIntervals + 1 >= theArgNb)
+      if (anArgIter + 1 >= theArgNb)
+      {
+        std::cout << "Syntax error at argument '" << anArg << "'!\n";
+        return 1;
+      }
+
+      Standard_Integer aNbLabels = aColorScale->IsLabelAtBorder()
+                                 ? aColorScale->GetNumberOfIntervals() + 1
+                                 : aColorScale->GetNumberOfIntervals();
+      if (aFlag == "-freelabels")
+      {
+        ++anArgIter;
+        aNbLabels = Draw::Atoi (theArgVec[anArgIter]);
+      }
+      if (anArgIter + aNbLabels >= theArgNb)
       {
-        std::cout << "Error: not enough arguments! You should provide " << (aNbIntervals + 1)
-                  << " text labels for " << aNbIntervals << " intervals.\n";
+        std::cout << "Error: not enough arguments! " << aNbLabels << " text labels are expected.\n";
         return 1;
       }
 
       TColStd_SequenceOfExtendedString aSeq;
-      for (int aLabelIter = anArgIter + 1; aLabelIter <= anArgIter + aNbIntervals + 1; aLabelIter += 1)
+      for (Standard_Integer aLabelIter = 0; aLabelIter < aNbLabels; ++aLabelIter)
       {
-        aSeq.Append (TCollection_ExtendedString (theArgVec[aLabelIter]));
+        aSeq.Append (TCollection_ExtendedString (theArgVec[++anArgIter]));
       }
-      aCS->SetLabels (aSeq);
-      aCS->SetLabelType (Aspect_TOCSD_USER);
-      anArgIter += aSeq.Length();
+      aColorScale->SetLabels (aSeq);
+      aColorScale->SetLabelType (Aspect_TOCSD_USER);
     }
     else if (aFlag == "-title")
     {
@@ -3854,29 +3887,31 @@ static int VColorScale (Draw_Interpretor& theDI,
       {
         TCollection_AsciiString aSecondArg (theArgVec[anArgIter + 2]);
         aSecondArg.LowerCase();
+      Standard_DISABLE_DEPRECATION_WARNINGS
         if (aSecondArg == "none")
         {
-          aCS->SetTitlePosition (Aspect_TOCSP_NONE);
+          aColorScale->SetTitlePosition (Aspect_TOCSP_NONE);
           isTwoArgs = Standard_True;
         }
         else if (aSecondArg == "left")
         {
-          aCS->SetTitlePosition (Aspect_TOCSP_LEFT);
+          aColorScale->SetTitlePosition (Aspect_TOCSP_LEFT);
           isTwoArgs = Standard_True;
         }
         else if (aSecondArg == "right")
         {
-          aCS->SetTitlePosition (Aspect_TOCSP_RIGHT);
+          aColorScale->SetTitlePosition (Aspect_TOCSP_RIGHT);
           isTwoArgs = Standard_True;
         }
         else if (aSecondArg == "center")
         {
-          aCS->SetTitlePosition (Aspect_TOCSP_CENTER);
+          aColorScale->SetTitlePosition (Aspect_TOCSP_CENTER);
           isTwoArgs = Standard_True;
         }
+      Standard_ENABLE_DEPRECATION_WARNINGS
       }
 
-      aCS->SetTitle (theArgVec[anArgIter + 1]);
+      aColorScale->SetTitle (theArgVec[anArgIter + 1]);
       if (isTwoArgs)
       {
         anArgIter += 1;
@@ -3886,17 +3921,15 @@ static int VColorScale (Draw_Interpretor& theDI,
     else if (aFlag == "-demoversion"
           || aFlag == "-demo")
     {
-      aPosX        = 0;
-      aPosY        = 0;
-      aTextHeight  = 16;
-      aMinRange    = 0.0;
-      aMaxRange    = 100;
-      aNbIntervals = 10;
-      aBreadth     = 0;
-      aHeight      = 0;
-      aLabPosition = Aspect_TOCSP_RIGHT;
-      aCS->SetColorType (Aspect_TOCSD_AUTO);
-      aCS->SetLabelType (Aspect_TOCSD_AUTO);
+      aColorScale->SetPosition (0, 0);
+      aColorScale->SetTextHeight (16);
+      aColorScale->SetRange (0.0, 100.0);
+      aColorScale->SetNumberOfIntervals (10);
+      aColorScale->SetBreadth (0);
+      aColorScale->SetHeight  (0);
+      aColorScale->SetLabelPosition (Aspect_TOCSP_RIGHT);
+      aColorScale->SetColorType (Aspect_TOCSD_AUTO);
+      aColorScale->SetLabelType (Aspect_TOCSD_AUTO);
     }
     else if (aFlag == "-findcolor")
     {
@@ -3915,7 +3948,7 @@ static int VColorScale (Draw_Interpretor& theDI,
       }
 
       Quantity_Color aColor;
-      aCS->FindColor (anArg1.RealValue(), aColor);
+      aColorScale->FindColor (anArg1.RealValue(), aColor);
       theDI << Quantity_Color::StringName (aColor.Name());
       return 0;
     }
@@ -3925,29 +3958,19 @@ static int VColorScale (Draw_Interpretor& theDI,
       return 1;
     }
   }
-  if (!aBreadth || !aHeight)
+
+  Standard_Integer aWinWidth = 0, aWinHeight = 0;
+  aView->Window()->Size (aWinWidth, aWinHeight);
+  if (aColorScale->GetBreadth() == 0)
   {
-    Standard_Integer aWinWidth, aWinHeight;
-    aView->Window()->Size (aWinWidth, aWinHeight);
-    if (!aBreadth)
-    {
-      aBreadth = aWinWidth;
-    }
-    if (!aHeight)
-    {
-      aHeight = aWinHeight;
-    }
+    aColorScale->SetBreadth (aWinWidth);
   }
-  aCS->SetSize              (aBreadth, aHeight);
-  aCS->SetPosition          (aPosX, aPosY);
-  aCS->SetTextHeight        (aTextHeight);
-  aCS->SetRange             (aMinRange, aMaxRange);
-  aCS->SetNumberOfIntervals (aNbIntervals);
-  aCS->SetLabelPosition     (aLabPosition);
-//  aCS->SetColor             (aView->BackgroundColor().Invert());
-  aCS->SetToUpdate();
-  aContext->Display (aCS);
-
+  if (aColorScale->GetHeight() == 0)
+  {
+    aColorScale->SetHeight (aWinHeight);
+  }
+  aColorScale->SetToUpdate();
+  ViewerTest::Display (theArgVec[1], aColorScale, Standard_False, Standard_True);
   return 0;
 }
 
@@ -4391,210 +4414,377 @@ static int VTile (Draw_Interpretor& theDI,
   return 0;
 }
 
+//! Format ZLayer ID.
+inline const char* formZLayerId (const Standard_Integer theLayerId)
+{
+  switch (theLayerId)
+  {
+    case Graphic3d_ZLayerId_UNKNOWN: return "[INVALID]";
+    case Graphic3d_ZLayerId_Default: return "[DEFAULT]";
+    case Graphic3d_ZLayerId_Top:     return "[TOP]";
+    case Graphic3d_ZLayerId_Topmost: return "[TOPMOST]";
+    case Graphic3d_ZLayerId_TopOSD:  return "[OVERLAY]";
+    case Graphic3d_ZLayerId_BotOSD:  return "[UNDERLAY]";
+  }
+  return "";
+}
+
+//! Print the ZLayer information.
+inline void printZLayerInfo (Draw_Interpretor& theDI,
+                             const Graphic3d_ZLayerSettings& theLayer)
+{
+  if (!theLayer.Name().IsEmpty())
+  {
+    theDI << "  Name: " << theLayer.Name() << "\n";
+  }
+  if (theLayer.IsImmediate())
+  {
+    theDI << "  Immediate: TRUE\n";
+  }
+  theDI << "  Origin: " << theLayer.Origin().X() << " " << theLayer.Origin().Y() << " " << theLayer.Origin().Z() << "\n";
+  theDI << "  Depth test:   "          << (theLayer.ToEnableDepthTest() ? "enabled" : "disabled") << "\n";
+  theDI << "  Depth write:  "          << (theLayer.ToEnableDepthWrite() ? "enabled" : "disabled") << "\n";
+  theDI << "  Depth buffer clearing: " << (theLayer.ToClearDepth() ? "enabled" : "disabled") << "\n";
+  if (theLayer.PolygonOffset().Mode != Aspect_POM_None)
+  {
+    theDI << "  Depth offset: " << theLayer.PolygonOffset().Factor << " " << theLayer.PolygonOffset().Units << "\n";
+  }
+}
+
 //==============================================================================
 //function : VZLayer
 //purpose  : Test z layer operations for v3d viewer
 //==============================================================================
-static int VZLayer (Draw_Interpretor& di, Standard_Integer argc, const char** argv)
+static int VZLayer (Draw_Interpretor& theDI,
+                    Standard_Integer  theArgNb,
+                    const char**      theArgVec)
 {
-  Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext ();
+  Handle(AIS_InteractiveContext) aContextAIS = ViewerTest::GetAISContext();
   if (aContextAIS.IsNull())
   {
-    di << "Call vinit before!\n";
-    return 1;
-  }
-  else if (argc < 2)
-  {
-    di << di.PrintHelp (argv[0]);
+    std::cout << "No active viewer!\n";
     return 1;
   }
 
   const Handle(V3d_Viewer)& aViewer = aContextAIS->CurrentViewer();
-  if (aViewer.IsNull())
+  if (theArgNb < 2)
   {
-    di << "No active viewer!\n";
+    TColStd_SequenceOfInteger aLayers;
+    aViewer->GetAllZLayers (aLayers);
+    for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
+    {
+      theDI << "ZLayer " << aLayeriter.Value() << " " << formZLayerId (aLayeriter.Value()) << "\n";
+      Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
+      printZLayerInfo (theDI, aSettings);
+    }
     return 1;
   }
 
-  // perform operation
-  TCollection_AsciiString anOp = TCollection_AsciiString (argv[1]);
-  if (anOp == "add")
+  Standard_Integer anArgIter = 1;
+  Standard_Integer aLayerId = Graphic3d_ZLayerId_UNKNOWN;
+  ViewerTest_AutoUpdater anUpdateTool (aContextAIS, ViewerTest::CurrentView());
+  if (anUpdateTool.parseRedrawMode (theArgVec[anArgIter]))
   {
-    Standard_Integer aNewId;
-    if (!aViewer->AddZLayer (aNewId))
-    {
-      di << "Impossible to add new z layer!\n";
-      return 1;
-    }
+    ++anArgIter;
+  }
 
-    di << "New z layer added with index: " << aNewId << "\n";
+  TCollection_AsciiString aFirstArg (theArgVec[anArgIter]);
+  if (aFirstArg.IsIntegerValue())
+  {
+    ++anArgIter;
+    aLayerId = aFirstArg.IntegerValue();
   }
-  else if (anOp == "del")
+  else
   {
-    if (argc < 3)
-    {
-      di << "Please also provide as argument id of z layer to remove\n";
-      return 1;
-    }
-
-    Standard_Integer aDelId = Draw::Atoi (argv[2]);
-    if (!aViewer->RemoveZLayer (aDelId))
+    aFirstArg.LowerCase();
+    if (aFirstArg == "default"
+     || aFirstArg == "def")
     {
-      di << "Impossible to remove the z layer or invalid id!\n";
-      return 1;
+      aLayerId = Graphic3d_ZLayerId_Default;
+      ++anArgIter;
     }
-
-    for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anObjIter (GetMapOfAIS());
-         anObjIter.More(); anObjIter.Next())
+    else if (aFirstArg == "top")
     {
-      Handle(PrsMgr_PresentableObject) aPrs = Handle(PrsMgr_PresentableObject)::DownCast (anObjIter.Key1());
-      if (aPrs.IsNull()
-       || aPrs->ZLayer() != aDelId)
-      {
-        continue;
-      }
-      aPrs->SetZLayer (Graphic3d_ZLayerId_Default);
+      aLayerId = Graphic3d_ZLayerId_Top;
+      ++anArgIter;
     }
-
-    di << "Z layer " << aDelId << " has been removed\n";
-  }
-  else if (anOp == "get")
-  {
-    TColStd_SequenceOfInteger anIds;
-    aViewer->GetAllZLayers (anIds);
-    for (Standard_Integer aSeqIdx = 1; aSeqIdx <= anIds.Length(); aSeqIdx++)
+    else if (aFirstArg == "topmost")
     {
-      di << anIds.Value (aSeqIdx) << " ";
+      aLayerId = Graphic3d_ZLayerId_Topmost;
+      ++anArgIter;
     }
-
-    di << "\n";
-  }
-  else if (anOp == "settings")
-  {
-    if (argc < 3)
+    else if (aFirstArg == "overlay"
+          || aFirstArg == "toposd")
     {
-      di << "Please also provide an id\n";
-      return 1;
+      aLayerId = Graphic3d_ZLayerId_TopOSD;
+      ++anArgIter;
     }
-
-    Standard_Integer anId = Draw::Atoi (argv[2]);
-    Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (anId);
-
-    di << "Depth test - " << (aSettings.IsSettingEnabled (Graphic3d_ZLayerDepthTest) ? "enabled" : "disabled") << "\n";
-    di << "Depth write - " << (aSettings.IsSettingEnabled (Graphic3d_ZLayerDepthWrite) ? "enabled" : "disabled") << "\n";
-    di << "Depth buffer clearing - " << (aSettings.IsSettingEnabled (Graphic3d_ZLayerDepthClear) ? "enabled" : "disabled") << "\n";
-    di << "Depth offset - " << (aSettings.IsSettingEnabled (Graphic3d_ZLayerDepthOffset) ? "enabled" : "disabled") << "\n";
-
-  }
-  else if (anOp == "enable")
-  {
-    if (argc < 3)
+    else if (aFirstArg == "underlay"
+          || aFirstArg == "botosd")
     {
-      di << "Please also provide an option to enable\n";
-      return 1;
+      aLayerId = Graphic3d_ZLayerId_BotOSD;
+      ++anArgIter;
     }
-
-    if (argc < 4)
+    else
     {
-      di << "Please also provide a layer id\n";
-      return 1;
+      TColStd_SequenceOfInteger aLayers;
+      aViewer->GetAllZLayers (aLayers);
+      for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
+      {
+        Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayeriter.Value());
+        if (TCollection_AsciiString::IsSameString (aSettings.Name(), aFirstArg, Standard_False))
+        {
+          aLayerId = aLayeriter.Value();
+          ++anArgIter;
+          break;
+        }
+      }
     }
+  }
 
-    TCollection_AsciiString aSubOp = TCollection_AsciiString (argv[2]);
-    Standard_Integer anId = Draw::Atoi (argv[3]);
-    Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (anId);
-
-    if (aSubOp == "depthtest" || aSubOp == "test")
-    {
-      aSettings.EnableSetting (Graphic3d_ZLayerDepthTest);
-    }
-    else if (aSubOp == "depthwrite" || aSubOp == "write")
+  for (; anArgIter < theArgNb; ++anArgIter)
+  {
+    // perform operation
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    if (anUpdateTool.parseRedrawMode (anArg))
     {
-      aSettings.EnableSetting (Graphic3d_ZLayerDepthWrite);
+      //
     }
-    else if (aSubOp == "depthclear" || aSubOp == "clear")
+    else if (anArg == "-add"
+          || anArg == "add")
     {
-      aSettings.EnableSetting (Graphic3d_ZLayerDepthClear);
+      aLayerId = Graphic3d_ZLayerId_UNKNOWN;
+      if (!aViewer->AddZLayer (aLayerId))
+      {
+        std::cout << "Error: can not add a new z layer!\n";
+        return 0;
+      }
+
+      theDI << aLayerId;
     }
-    else if (aSubOp == "depthoffset" || aSubOp == "offset")
+    else if (anArg == "-del"
+          || anArg == "-delete"
+          || anArg == "del")
     {
-      if (argc < 6)
+      if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
       {
-        di << "Please also provide a factor and units values for depth offset\n";
-        di << "Format is: vzlayer enable offset [factor] [units] [layerId]\n";
-        return 1;
+        if (++anArgIter >= theArgNb)
+        {
+          std::cout << "Syntax error: id of z layer to remove is missing\n";
+          return 1;
+        }
+
+        aLayerId = Draw::Atoi (theArgVec[anArgIter]);
       }
 
-      Standard_ShortReal aFactor = static_cast<Standard_ShortReal> (Draw::Atof (argv[3]));
-      Standard_ShortReal aUnits  = static_cast<Standard_ShortReal> (Draw::Atof (argv[4]));
-      anId = Draw::Atoi (argv[5]);
-      aSettings = aViewer->ZLayerSettings (anId);
+      if (aLayerId == Graphic3d_ZLayerId_UNKNOWN
+       || aLayerId == Graphic3d_ZLayerId_Default
+       || aLayerId == Graphic3d_ZLayerId_Top
+       || aLayerId == Graphic3d_ZLayerId_Topmost
+       || aLayerId == Graphic3d_ZLayerId_TopOSD
+       || aLayerId == Graphic3d_ZLayerId_BotOSD)
+      {
+        std::cout << "Syntax error: standard Z layer can not be removed\n";
+        return 1;
+      }
 
-      aSettings.DepthOffsetFactor = aFactor;
-      aSettings.DepthOffsetUnits  = aUnits;
+      // move all object displayed in removing layer to default layer
+      for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anObjIter (GetMapOfAIS());
+           anObjIter.More(); anObjIter.Next())
+      {
+        Handle(PrsMgr_PresentableObject) aPrs = Handle(PrsMgr_PresentableObject)::DownCast (anObjIter.Key1());
+        if (aPrs.IsNull()
+         || aPrs->ZLayer() != aLayerId)
+        {
+          continue;
+        }
+        aPrs->SetZLayer (Graphic3d_ZLayerId_Default);
+      }
 
-      aSettings.EnableSetting (Graphic3d_ZLayerDepthOffset);
-    }
-    else if (aSubOp == "positiveoffset" || aSubOp == "poffset")
-    {
-      aSettings.SetDepthOffsetPositive();
-    }
-    else if (aSubOp == "negativeoffset" || aSubOp == "noffset")
-    {
-      aSettings.SetDepthOffsetNegative();
+      if (!aViewer->RemoveZLayer (aLayerId))
+      {
+        std::cout << "Z layer can not be removed!\n";
+      }
+      else
+      {
+        theDI << aLayerId << " ";
+      }
     }
-    else if (aSubOp == "textureenv")
+    else if (anArg == "-get"
+          || anArg == "get")
     {
-      aSettings.UseEnvironmentTexture = true;
-    }
+      TColStd_SequenceOfInteger aLayers;
+      aViewer->GetAllZLayers (aLayers);
+      for (TColStd_SequenceOfInteger::Iterator aLayeriter (aLayers); aLayeriter.More(); aLayeriter.Next())
+      {
+        theDI << aLayeriter.Value() << " ";
+      }
 
-    aViewer->SetZLayerSettings (anId, aSettings);
-  }
-  else if (anOp == "disable")
-  {
-    if (argc < 3)
-    {
-      di << "Please also provide an option to disable\n";
-      return 1;
+      theDI << "\n";
     }
-
-    if (argc < 4)
+    else if (anArg == "-name")
     {
-      di << "Please also provide a layer id\n";
-      return 1;
-    }
+      if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
+      {
+        std::cout << "Syntax error: id of Z layer is missing\n";
+        return 1;
+      }
 
-    TCollection_AsciiString aSubOp = TCollection_AsciiString (argv[2]);
-    Standard_Integer anId = Draw::Atoi (argv[3]);
-    Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (anId);
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Syntax error: name is missing\n";
+        return 1;
+      }
 
-    if (aSubOp == "depthtest" || aSubOp == "test")
-    {
-      aSettings.DisableSetting (Graphic3d_ZLayerDepthTest);
+      Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
+      aSettings.SetName (theArgVec[anArgIter]);
+      aViewer->SetZLayerSettings (aLayerId, aSettings);
     }
-    else if (aSubOp == "depthwrite" || aSubOp == "write")
+    else if (anArg == "-origin")
     {
-      aSettings.DisableSetting (Graphic3d_ZLayerDepthWrite);
+      if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
+      {
+        std::cout << "Syntax error: id of Z layer is missing\n";
+        return 1;
+      }
+
+      if (anArgIter + 2 >= theArgNb)
+      {
+        std::cout << "Syntax error: origin coordinates are missing\n";
+        return 1;
+      }
+
+      Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
+      gp_XYZ anOrigin;
+      anOrigin.SetX (Draw::Atof (theArgVec[anArgIter + 1]));
+      anOrigin.SetY (Draw::Atof (theArgVec[anArgIter + 2]));
+      anOrigin.SetZ (0.0);
+      if (anArgIter + 3 < theArgNb)
+      {
+        anOrigin.SetZ (Draw::Atof (theArgVec[anArgIter + 3]));
+        anArgIter += 3;
+      }
+      else
+      {
+        anArgIter += 2;
+      }
+      aSettings.SetOrigin (anOrigin);
+      aViewer->SetZLayerSettings (aLayerId, aSettings);
     }
-    else if (aSubOp == "depthclear" || aSubOp == "clear")
+    else if (anArg == "-settings"
+          || anArg == "settings")
     {
-      aSettings.DisableSetting (Graphic3d_ZLayerDepthClear);
+      if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
+      {
+        if (++anArgIter >= theArgNb)
+        {
+          std::cout << "Syntax error: id of Z layer is missing\n";
+          return 1;
+        }
+
+        aLayerId = Draw::Atoi (theArgVec[anArgIter]);
+      }
+
+      Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
+      printZLayerInfo (theDI, aSettings);
     }
-    else if (aSubOp == "depthoffset" || aSubOp == "offset")
+    else if (anArg == "-enable"
+          || anArg == "enable"
+          || anArg == "-disable"
+          || anArg == "disable")
     {
-      aSettings.DisableSetting (Graphic3d_ZLayerDepthOffset);
+      const Standard_Boolean toEnable = anArg == "-enable"
+                                     || anArg == "enable";
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Syntax error: option name is missing\n";
+        return 1;
+      }
+
+      TCollection_AsciiString aSubOp (theArgVec[anArgIter]);
+      aSubOp.LowerCase();
+      if (aLayerId == Graphic3d_ZLayerId_UNKNOWN)
+      {
+        if (++anArgIter >= theArgNb)
+        {
+          std::cout << "Syntax error: id of Z layer is missing\n";
+          return 1;
+        }
+
+        aLayerId = Draw::Atoi (theArgVec[anArgIter]);
+      }
+
+      Graphic3d_ZLayerSettings aSettings = aViewer->ZLayerSettings (aLayerId);
+      if (aSubOp == "depthtest"
+       || aSubOp == "test")
+      {
+        aSettings.SetEnableDepthTest (toEnable);
+      }
+      else if (aSubOp == "depthwrite"
+            || aSubOp == "write")
+      {
+        aSettings.SetEnableDepthWrite (toEnable);
+      }
+      else if (aSubOp == "depthclear"
+            || aSubOp == "clear")
+      {
+        aSettings.SetClearDepth (toEnable);
+      }
+      else if (aSubOp == "depthoffset"
+            || aSubOp == "offset")
+      {
+        Graphic3d_PolygonOffset aParams;
+        aParams.Mode = toEnable ? Aspect_POM_Fill : Aspect_POM_None;
+        if (toEnable)
+        {
+          if (anArgIter + 2 >= theArgNb)
+          {
+            std::cout << "Syntax error: factor and units values for depth offset are missing\n";
+            return 1;
+          }
+
+          aParams.Factor = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
+          aParams.Units  = static_cast<Standard_ShortReal> (Draw::Atof (theArgVec[++anArgIter]));
+        }
+        aSettings.SetPolygonOffset (aParams);
+      }
+      else if (aSubOp == "positiveoffset"
+            || aSubOp == "poffset")
+      {
+        if (toEnable)
+        {
+          aSettings.SetDepthOffsetPositive();
+        }
+        else
+        {
+          aSettings.SetPolygonOffset (Graphic3d_PolygonOffset());
+        }
+      }
+      else if (aSubOp == "negativeoffset"
+            || aSubOp == "noffset")
+      {
+        if (toEnable)
+        {
+          aSettings.SetDepthOffsetNegative();
+        }
+        else
+        {
+          aSettings.SetPolygonOffset(Graphic3d_PolygonOffset());
+        }
+      }
+      else if (aSubOp == "textureenv")
+      {
+        aSettings.SetEnvironmentTexture (toEnable);
+      }
+
+      aViewer->SetZLayerSettings (aLayerId, aSettings);
     }
-    else if (aSubOp == "textureenv")
+    else
     {
-      aSettings.UseEnvironmentTexture = false;
+      std::cout << "Syntax error: unknown option " << theArgVec[anArgIter] << "\n";
+      return 1;
     }
-
-    aViewer->SetZLayerSettings (anId, aSettings);
-  }
-  else
-  {
-    di << "Invalid operation, please use { add / del / get / settings / enable / disable}\n";
-    return 1;
   }
 
   return 0;
@@ -4699,17 +4889,21 @@ static int VLayerLine(Draw_Interpretor& di, Standard_Integer argc, const char**
   Standard_Real X2 = Draw::Atof(argv[3]);
   Standard_Real Y2 = Draw::Atof(argv[4]);
 
-  Standard_Real    aWidth = 0.5;
-  Standard_Integer aType  = 0;
-  Standard_Real    aTransparency = 1.0;
+  Standard_Real aWidth = 0.5;
+  Standard_Real aTransparency = 1.0;
 
   // has width
   if (argc > 5)
     aWidth = Draw::Atof(argv[5]);
 
-  // has type
-  if (argc > 6)
-     aType = (Standard_Integer) Draw::Atoi(argv[6]);
+  // select appropriate line type
+  Aspect_TypeOfLine aLineType = Aspect_TOL_SOLID;
+  if (argc > 6
+  && !ViewerTest::ParseLineType (argv[6], aLineType))
+  {
+    std::cout << "Syntax error: unknown line type '" << argv[6] << "'\n";
+    return 1;
+  }
 
   // has transparency
   if (argc > 7)
@@ -4719,26 +4913,6 @@ static int VLayerLine(Draw_Interpretor& di, Standard_Integer argc, const char**
       aTransparency = 1.0;
   }
 
-  // select appropriate line type
-  Aspect_TypeOfLine aLineType;
-  switch (aType)
-  {
-    case 1:
-      aLineType = Aspect_TOL_DASH;
-    break;
-
-    case 2:
-      aLineType = Aspect_TOL_DOT;
-    break;
-
-    case 3:
-      aLineType = Aspect_TOL_DOTDASH;
-    break;
-
-    default:
-      aLineType = Aspect_TOL_SOLID;
-  }
-
   static Handle (V3d_LineItem) aLine;
   if (!aLine.IsNull())
   {
@@ -5549,7 +5723,7 @@ static int VReadPixel (Draw_Interpretor& theDI,
     return 1;
   }
 
-  Image_PixMap::ImgFormat aFormat     = Image_PixMap::IsBigEndianHost() ? Image_PixMap::ImgRGBA : Image_PixMap::ImgBGRA;
+  Image_PixMap::ImgFormat aFormat     = Image_PixMap::ImgRGBA;
   Graphic3d_BufferType    aBufferType = Graphic3d_BT_RGBA;
 
   Standard_Integer aWidth, aHeight;
@@ -5569,12 +5743,12 @@ static int VReadPixel (Draw_Interpretor& theDI,
     const char* aParam = theArgVec[anIter];
     if ( strcasecmp( aParam, "rgb" ) == 0 )
     {
-      aFormat     = Image_PixMap::IsBigEndianHost() ? Image_PixMap::ImgRGB : Image_PixMap::ImgBGR;
+      aFormat     = Image_PixMap::ImgRGB;
       aBufferType = Graphic3d_BT_RGB;
     }
     else if ( strcasecmp( aParam, "hls" ) == 0 )
     {
-      aFormat     = Image_PixMap::IsBigEndianHost() ? Image_PixMap::ImgRGB : Image_PixMap::ImgBGR;
+      aFormat     = Image_PixMap::ImgRGB;
       aBufferType = Graphic3d_BT_RGB;
       toShowHls   = Standard_True;
     }
@@ -5585,7 +5759,7 @@ static int VReadPixel (Draw_Interpretor& theDI,
     }
     else if ( strcasecmp( aParam, "rgba" ) == 0 )
     {
-      aFormat     = Image_PixMap::IsBigEndianHost() ? Image_PixMap::ImgRGBA : Image_PixMap::ImgBGRA;
+      aFormat     = Image_PixMap::ImgRGBA;
       aBufferType = Graphic3d_BT_RGBA;
     }
     else if ( strcasecmp( aParam, "rgbaf" ) == 0 )
@@ -5814,206 +5988,926 @@ static Standard_Integer VMoveTo (Draw_Interpretor& di,
   return 0;
 }
 
+namespace
+{
+  //! Global map storing all animations registered in ViewerTest.
+  static NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)> ViewerTest_AnimationTimelineMap;
+
+  //! The animation calling the Draw Harness command.
+  class ViewerTest_AnimationProc : public AIS_Animation
+  {
+  public:
+
+    //! Main constructor.
+    ViewerTest_AnimationProc (const TCollection_AsciiString& theAnimationName,
+                              Draw_Interpretor* theDI,
+                              const TCollection_AsciiString& theCommand)
+    : AIS_Animation (theAnimationName),
+      myDrawInter(theDI),
+      myCommand  (theCommand)
+    {
+      //
+    }
+
+  protected:
+
+    //! Evaluate the command.
+    virtual void update (const AIS_AnimationProgress& theProgress) Standard_OVERRIDE
+    {
+      TCollection_AsciiString aCmd = myCommand;
+      replace (aCmd, "%pts",             TCollection_AsciiString(theProgress.Pts));
+      replace (aCmd, "%localpts",        TCollection_AsciiString(theProgress.LocalPts));
+      replace (aCmd, "%ptslocal",        TCollection_AsciiString(theProgress.LocalPts));
+      replace (aCmd, "%normalized",      TCollection_AsciiString(theProgress.LocalNormalized));
+      replace (aCmd, "%localnormalized", TCollection_AsciiString(theProgress.LocalNormalized));
+      myDrawInter->Eval (aCmd.ToCString());
+    }
+
+    //! Find the keyword in the command and replace it with value.
+    //! @return the position of the keyword to pass value
+    void replace (TCollection_AsciiString&       theCmd,
+                  const TCollection_AsciiString& theKey,
+                  const TCollection_AsciiString& theVal)
+    {
+      TCollection_AsciiString aCmd (theCmd);
+      aCmd.LowerCase();
+      const Standard_Integer aPos = aCmd.Search (theKey);
+      if (aPos == -1)
+      {
+        return;
+      }
+
+      TCollection_AsciiString aPart1, aPart2;
+      Standard_Integer aPart1To = aPos - 1;
+      if (aPart1To >= 1
+       && aPart1To <= theCmd.Length())
+      {
+        aPart1 = theCmd.SubString (1, aPart1To);
+      }
+
+      Standard_Integer aPart2From = aPos + theKey.Length();
+      if (aPart2From >= 1
+       && aPart2From <= theCmd.Length())
+      {
+        aPart2 = theCmd.SubString (aPart2From, theCmd.Length());
+      }
+
+      theCmd = aPart1 + theVal + aPart2;
+    }
+
+  protected:
+
+    Draw_Interpretor*       myDrawInter;
+    TCollection_AsciiString myCommand;
+
+  };
+
+  //! Replace the animation with the new one.
+  static void replaceAnimation (const Handle(AIS_Animation)& theParentAnimation,
+                                Handle(AIS_Animation)&       theAnimation,
+                                const Handle(AIS_Animation)& theAnimationNew)
+  {
+    theAnimationNew->CopyFrom (theAnimation);
+    if (!theParentAnimation.IsNull())
+    {
+      theParentAnimation->Replace (theAnimation, theAnimationNew);
+    }
+    else
+    {
+      ViewerTest_AnimationTimelineMap.UnBind (theAnimationNew->Name());
+      ViewerTest_AnimationTimelineMap.Bind   (theAnimationNew->Name(), theAnimationNew);
+    }
+    theAnimation = theAnimationNew;
+  }
+
+  //! Parse the point.
+  static Standard_Boolean parseXYZ (const char** theArgVec, gp_XYZ& thePnt)
+  {
+    const TCollection_AsciiString anXYZ[3] = { theArgVec[0], theArgVec[1], theArgVec[2] };
+    if (!anXYZ[0].IsRealValue()
+     || !anXYZ[1].IsRealValue()
+     || !anXYZ[2].IsRealValue())
+    {
+      return Standard_False;
+    }
+
+    thePnt.SetCoord (anXYZ[0].RealValue(), anXYZ[1].RealValue(), anXYZ[2].RealValue());
+    return Standard_True;
+  }
+
+  //! Parse the quaternion.
+  static Standard_Boolean parseQuaternion (const char** theArgVec, gp_Quaternion& theQRot)
+  {
+    const TCollection_AsciiString anXYZW[4] = {theArgVec[0], theArgVec[1], theArgVec[2], theArgVec[3]};
+    if (!anXYZW[0].IsRealValue()
+     || !anXYZW[1].IsRealValue()
+     || !anXYZW[2].IsRealValue()
+     || !anXYZW[3].IsRealValue())
+    {
+      return Standard_False;
+    }
+
+    theQRot.Set (anXYZW[0].RealValue(), anXYZW[1].RealValue(), anXYZW[2].RealValue(), anXYZW[3].RealValue());
+    return Standard_True;
+  }
+
+}
+
 //=================================================================================================
 //function : VViewParams
 //purpose  : Gets or sets AIS View characteristics
 //=================================================================================================
 static int VViewParams (Draw_Interpretor& theDi, Standard_Integer theArgsNb, const char** theArgVec)
 {
-  Handle(V3d_View) anAISView = ViewerTest::CurrentView();
-  if (anAISView.IsNull())
+  Handle(V3d_View) aView = ViewerTest::CurrentView();
+  if (aView.IsNull())
   {
     std::cout << theArgVec[0] << ": please initialize or activate view.\n";
     return 1;
   }
 
+  Standard_Boolean toSetProj     = Standard_False;
+  Standard_Boolean toSetUp       = Standard_False;
+  Standard_Boolean toSetAt       = Standard_False;
+  Standard_Boolean toSetEye      = Standard_False;
+  Standard_Boolean toSetScale    = Standard_False;
+  Standard_Boolean toSetSize     = Standard_False;
+  Standard_Boolean toSetCenter2d = Standard_False;
+  Quantity_Factor  aViewScale = aView->Scale();
+  Quantity_Length  aViewSize  = 1.0;
+  Graphic3d_Vec2i  aCenter2d;
+  gp_XYZ aViewProj, aViewUp, aViewAt, aViewEye;
+  aView->Proj (aViewProj.ChangeCoord (1), aViewProj.ChangeCoord (2), aViewProj.ChangeCoord (3));
+  aView->Up   (aViewUp  .ChangeCoord (1), aViewUp  .ChangeCoord (2), aViewUp  .ChangeCoord (3));
+  aView->At   (aViewAt  .ChangeCoord (1), aViewAt  .ChangeCoord (2), aViewAt  .ChangeCoord (3));
+  aView->Eye  (aViewEye .ChangeCoord (1), aViewEye .ChangeCoord (2), aViewEye .ChangeCoord (3));
   if (theArgsNb == 1)
   {
     // print all of the available view parameters
-    Quantity_Factor anAISViewScale = anAISView->Scale();
-
-    Standard_Real anAISViewProjX = 0.0;
-    Standard_Real anAISViewProjY = 0.0;
-    Standard_Real anAISViewProjZ = 0.0;
-    anAISView->Proj (anAISViewProjX, anAISViewProjY, anAISViewProjZ);
-
-    Standard_Real anAISViewUpX = 0.0;
-    Standard_Real anAISViewUpY = 0.0;
-    Standard_Real anAISViewUpZ = 0.0;
-    anAISView->Up (anAISViewUpX, anAISViewUpY, anAISViewUpZ);
-
-    Standard_Real anAISViewAtX = 0.0;
-    Standard_Real anAISViewAtY = 0.0;
-    Standard_Real anAISViewAtZ = 0.0;
-    anAISView->At (anAISViewAtX, anAISViewAtY, anAISViewAtZ);
-
-    Standard_Real anAISViewEyeX = 0.0;
-    Standard_Real anAISViewEyeY = 0.0;
-    Standard_Real anAISViewEyeZ = 0.0;
-    anAISView->Eye (anAISViewEyeX, anAISViewEyeY, anAISViewEyeZ);
-
-    theDi << "Scale of current view: " << anAISViewScale << "\n";
-    theDi << "Proj on X : " << anAISViewProjX << "; on Y: " << anAISViewProjY << "; on Z: " << anAISViewProjZ << "\n";
-    theDi << "Up on X : " << anAISViewUpX << "; on Y: " << anAISViewUpY << "; on Z: " << anAISViewUpZ << "\n";
-    theDi << "At on X : " << anAISViewAtX << "; on Y: " << anAISViewAtY << "; on Z: " << anAISViewAtZ << "\n";
-    theDi << "Eye on X : " << anAISViewEyeX << "; on Y: " << anAISViewEyeY << "; on Z: " << anAISViewEyeZ << "\n";
+    char aText[4096];
+    Sprintf (aText,
+             "Scale: %g\n"
+             "Proj:  %12g %12g %12g\n"
+             "Up:    %12g %12g %12g\n"
+             "At:    %12g %12g %12g\n"
+             "Eye:   %12g %12g %12g\n",
+              aViewScale,
+              aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
+              aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
+              aViewAt.X(),   aViewAt.Y(),   aViewAt.Z(),
+              aViewEye.X(),  aViewEye.Y(),  aViewEye.Z());
+    theDi << aText;
     return 0;
   }
 
-  // -------------------------
-  //  Parse options and values
-  // -------------------------
-
-  NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)> aMapOfKeysByValues;
-  TCollection_AsciiString aParseKey;
-  for (Standard_Integer anArgIt = 1; anArgIt < theArgsNb; ++anArgIt)
+  ViewerTest_AutoUpdater anUpdateTool (ViewerTest::GetAISContext(), aView);
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
   {
-    TCollection_AsciiString anArg (theArgVec [anArgIt]);
-
-    if (anArg.Value (1) == '-' && !anArg.IsRealValue())
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    if (anUpdateTool.parseRedrawMode (anArg))
     {
-      aParseKey = anArg;
-      aParseKey.Remove (1);
-      aParseKey.UpperCase();
-      aMapOfKeysByValues.Bind (aParseKey, new TColStd_HSequenceOfAsciiString);
       continue;
     }
+    else if (anArg == "-cmd"
+          || anArg == "-command"
+          || anArg == "-args")
+    {
+      char aText[4096];
+      Sprintf (aText,
+               "-scale %g "
+               "-proj %g %g %g "
+               "-up %g %g %g "
+               "-at %g %g %g\n",
+                aViewScale,
+                aViewProj.X(), aViewProj.Y(), aViewProj.Z(),
+                aViewUp.X(),   aViewUp.Y(),   aViewUp.Z(),
+                aViewAt.X(),   aViewAt.Y(),   aViewAt.Z());
+      theDi << aText;
+    }
+    else if (anArg == "-scale"
+          || anArg == "-size")
+    {
+      if (anArgIter + 1 < theArgsNb
+       && *theArgVec[anArgIter + 1] != '-')
+      {
+        const TCollection_AsciiString aValueArg (theArgVec[anArgIter + 1]);
+        if (aValueArg.IsRealValue())
+        {
+          ++anArgIter;
+          if (anArg == "-scale")
+          {
+            toSetScale = Standard_True;
+            aViewScale = aValueArg.RealValue();
+          }
+          else if (anArg == "-size")
+          {
+            toSetSize = Standard_True;
+            aViewSize = aValueArg.RealValue();
+          }
+          continue;
+        }
+      }
+      if (anArg == "-scale")
+      {
+        theDi << "Scale: " << aView->Scale() << "\n";
+      }
+      else if (anArg == "-size")
+      {
+        Graphic3d_Vec2d aSizeXY;
+        aView->Size (aSizeXY.x(), aSizeXY.y());
+        theDi << "Size: " << aSizeXY.x() << " " << aSizeXY.y() << "\n";
+      }
+    }
+    else if (anArg == "-eye"
+          || anArg == "-at"
+          || anArg == "-up"
+          || anArg == "-proj")
+    {
+      if (anArgIter + 3 < theArgsNb)
+      {
+        gp_XYZ anXYZ;
+        if (parseXYZ (theArgVec + anArgIter + 1, anXYZ))
+        {
+          anArgIter += 3;
+          if (anArg == "-eye")
+          {
+            toSetEye = Standard_True;
+            aViewEye = anXYZ;
+          }
+          else if (anArg == "-at")
+          {
+            toSetAt = Standard_True;
+            aViewAt = anXYZ;
+          }
+          else if (anArg == "-up")
+          {
+            toSetUp = Standard_True;
+            aViewUp = anXYZ;
+          }
+          else if (anArg == "-proj")
+          {
+            toSetProj = Standard_True;
+            aViewProj = anXYZ;
+          }
+          continue;
+        }
+      }
 
-    if (aParseKey.IsEmpty())
+      if (anArg == "-eye")
+      {
+        theDi << "Eye:  " << aViewEye.X() << " " << aViewEye.Y() << " " << aViewEye.Z() << "\n";
+      }
+      else if (anArg == "-at")
+      {
+        theDi << "At:   " << aViewAt.X() << " " << aViewAt.Y() << " " << aViewAt.Z() << "\n";
+      }
+      else if (anArg == "-up")
+      {
+        theDi << "Up:   " << aViewUp.X() << " " << aViewUp.Y() << " " << aViewUp.Z() << "\n";
+      }
+      else if (anArg == "-proj")
+      {
+        theDi << "Proj: " << aViewProj.X() << " " << aViewProj.Y() << " " << aViewProj.Z() << "\n";
+      }
+    }
+    else if (anArg == "-center")
+    {
+      if (anArgIter + 2 < theArgsNb)
+      {
+        const TCollection_AsciiString anX (theArgVec[anArgIter + 1]);
+        const TCollection_AsciiString anY (theArgVec[anArgIter + 2]);
+        if (anX.IsIntegerValue()
+         && anY.IsIntegerValue())
+        {
+          toSetCenter2d = Standard_True;
+          aCenter2d = Graphic3d_Vec2i (anX.IntegerValue(), anY.IntegerValue());
+        }
+      }
+    }
+    else
     {
-      std::cout << theArgVec[0] << ": values should be passed with key.\n";
-      std::cout << "Type help for more information.\n";
+      std::cout << "Syntax error at '" << anArg << "'\n";
       return 1;
     }
+  }
 
-    aMapOfKeysByValues(aParseKey)->Append (anArg);
+  // change view parameters in proper order
+  if (toSetScale)
+  {
+    aView->SetScale (aViewScale);
+  }
+  if (toSetSize)
+  {
+    aView->SetSize (aViewSize);
+  }
+  if (toSetEye)
+  {
+    aView->SetEye (aViewEye.X(), aViewEye.Y(), aViewEye.Z());
+  }
+  if (toSetAt)
+  {
+    aView->SetAt (aViewAt.X(), aViewAt.Y(), aViewAt.Z());
+  }
+  if (toSetProj)
+  {
+    aView->SetProj (aViewProj.X(), aViewProj.Y(), aViewProj.Z());
+  }
+  if (toSetUp)
+  {
+    aView->SetUp (aViewUp.X(), aViewUp.Y(), aViewUp.Z());
+  }
+  if (toSetCenter2d)
+  {
+    aView->SetCenter (aCenter2d.x(), aCenter2d.y());
   }
 
-  // ---------------------------------------------
-  //  Change or print parameters, order plays role
-  // ---------------------------------------------
+  return 0;
+}
 
-  // Check arguments for validity
-  NCollection_DataMap<TCollection_AsciiString, Handle(TColStd_HSequenceOfAsciiString)>::Iterator aMapIt (aMapOfKeysByValues);
-  for (; aMapIt.More(); aMapIt.Next())
+//==============================================================================
+//function : VAnimation
+//purpose  :
+//==============================================================================
+static Standard_Integer VAnimation (Draw_Interpretor& theDI,
+                                    Standard_Integer  theArgNb,
+                                    const char**      theArgVec)
+{
+  Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
+  if (theArgNb < 2)
   {
-    const TCollection_AsciiString& aKey = aMapIt.Key();
-    const Handle(TColStd_HSequenceOfAsciiString)& aValues = aMapIt.Value();
-
-    if (!(aKey.IsEqual ("SCALE")  && (aValues->Length() == 1 || aValues->IsEmpty()))
-     && !(aKey.IsEqual ("SIZE")   && (aValues->Length() == 1 || aValues->IsEmpty()))
-     && !(aKey.IsEqual ("EYE")    && (aValues->Length() == 3 || aValues->IsEmpty()))
-     && !(aKey.IsEqual ("AT")     && (aValues->Length() == 3 || aValues->IsEmpty()))
-     && !(aKey.IsEqual ("UP")     && (aValues->Length() == 3 || aValues->IsEmpty()))
-     && !(aKey.IsEqual ("PROJ")   && (aValues->Length() == 3 || aValues->IsEmpty()))
-     && !(aKey.IsEqual ("CENTER") &&  aValues->Length() == 2))
-    {
-      TCollection_AsciiString aLowerKey;
-      aLowerKey  = "-";
-      aLowerKey += aKey;
-      aLowerKey.LowerCase();
-      std::cout << theArgVec[0] << ": " << aLowerKey << " is unknown option, or number of arguments is invalid.\n";
-      std::cout << "Type help for more information.\n";
-      return 1;
+    for (NCollection_DataMap<TCollection_AsciiString, Handle(AIS_Animation)>::Iterator
+         anAnimIter (ViewerTest_AnimationTimelineMap); anAnimIter.More(); anAnimIter.Next())
+    {
+      theDI << anAnimIter.Key() << " " << anAnimIter.Value()->Duration() << " sec\n";
     }
+    return 0;
+  }
+  if (aCtx.IsNull())
+  {
+    std::cout << "Error: no active view\n";
+    return 1;
   }
 
-  Handle(TColStd_HSequenceOfAsciiString) aValues;
+  Standard_Integer anArgIter = 1;
+  TCollection_AsciiString aNameArg (theArgVec[anArgIter++]);
+  if (aNameArg.IsEmpty())
+  {
+    std::cout << "Syntax error: animation name is not defined.\n";
+    return 1;
+  }
 
-  // Change view parameters in proper order
-  if (aMapOfKeysByValues.Find ("SCALE", aValues))
+  TCollection_AsciiString aNameArgLower = aNameArg;
+  aNameArgLower.LowerCase();
+  if (aNameArgLower == "-reset"
+   || aNameArgLower == "-clear")
   {
-    if (aValues->IsEmpty())
+    ViewerTest_AnimationTimelineMap.Clear();
+    return 0;
+  }
+  else if (aNameArg.Value (1) == '-')
+  {
+    std::cout << "Syntax error: invalid animation name '" << aNameArg  << "'.\n";
+    return 1;
+  }
+
+  const char* aNameSplitter = "/";
+  Standard_Integer aSplitPos = aNameArg.Search (aNameSplitter);
+  if (aSplitPos == -1)
+  {
+    aNameSplitter = ".";
+    aSplitPos = aNameArg.Search (aNameSplitter);
+  }
+
+  // find existing or create a new animation by specified name within syntax "parent.child".
+  Handle(AIS_Animation) aRootAnimation, aParentAnimation, anAnimation;
+  for (; !aNameArg.IsEmpty();)
+  {
+    TCollection_AsciiString aNameParent;
+    if (aSplitPos != -1)
     {
-      theDi << "Scale: " << anAISView->Scale() << "\n";
+      if (aSplitPos == aNameArg.Length())
+      {
+        std::cout << "Syntax error: animation name is not defined.\n";
+        return 1;
+      }
+
+      aNameParent = aNameArg.SubString (            1, aSplitPos - 1);
+      aNameArg    = aNameArg.SubString (aSplitPos + 1, aNameArg.Length());
+
+      aSplitPos = aNameArg.Search (aNameSplitter);
     }
     else
     {
-      anAISView->SetScale (aValues->Value(1).RealValue());
+      aNameParent = aNameArg;
+      aNameArg.Clear();
     }
-  }
-  if (aMapOfKeysByValues.Find ("SIZE", aValues))
-  {
-    if (aValues->IsEmpty())
+
+    if (anAnimation.IsNull())
     {
-      Standard_Real aSizeX = 0.0;
-      Standard_Real aSizeY = 0.0;
-      anAISView->Size (aSizeX, aSizeY);
-      theDi << "Size X: " << aSizeX << " Y: " << aSizeY << "\n";
+      if (!ViewerTest_AnimationTimelineMap.Find (aNameParent, anAnimation))
+      {
+        anAnimation = new AIS_Animation (aNameParent);
+        ViewerTest_AnimationTimelineMap.Bind (aNameParent, anAnimation);
+      }
+      aRootAnimation = anAnimation;
     }
     else
     {
-      anAISView->SetSize (aValues->Value(1).RealValue());
+      aParentAnimation = anAnimation;
+      anAnimation = aParentAnimation->Find (aNameParent);
+      if (anAnimation.IsNull())
+      {
+        anAnimation = new AIS_Animation (aNameParent);
+        aParentAnimation->Add (anAnimation);
+      }
     }
   }
-  if (aMapOfKeysByValues.Find ("EYE", aValues))
+
+  if (anArgIter >= theArgNb)
   {
-    if (aValues->IsEmpty())
+    // just print the list of children
+    for (NCollection_Sequence<Handle(AIS_Animation)>::Iterator anAnimIter (anAnimation->Children()); anAnimIter.More(); anAnimIter.Next())
     {
-      Standard_Real anEyeX = 0.0;
-      Standard_Real anEyeY = 0.0;
-      Standard_Real anEyeZ = 0.0;
-      anAISView->Eye (anEyeX, anEyeY, anEyeZ);
-      theDi << "Eye X: " << anEyeX << " Y: " << anEyeY << " Z: " << anEyeZ << "\n";
+      theDI << anAnimIter.Value()->Name() << " " << anAnimIter.Value()->Duration() << " sec\n";
+    }
+    return 0;
+  }
+
+  // animation parameters
+  Standard_Boolean toPlay = Standard_False;
+  Standard_Real aPlaySpeed     = 1.0;
+  Standard_Real aPlayStartTime = anAnimation->StartPts();
+  Standard_Real aPlayDuration  = anAnimation->Duration();
+  Standard_Integer aFpsNum     = 0;
+  Standard_Integer aFpsDen     = 1;
+  Standard_Boolean isFreeCamera = Standard_False;
+  Standard_Boolean isLockLoop   = Standard_False;
+  Handle(V3d_View) aView = ViewerTest::CurrentView();
+  for (; anArgIter < theArgNb; ++anArgIter)
+  {
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    // general options
+    if (anArg == "-reset"
+     || anArg == "-clear")
+    {
+      anAnimation->Clear();
+    }
+    else if (anArg == "-remove"
+          || anArg == "-del"
+          || anArg == "-delete")
+    {
+      if (!aParentAnimation.IsNull())
+      {
+        ViewerTest_AnimationTimelineMap.UnBind (anAnimation->Name());
+      }
+      else
+      {
+        aParentAnimation->Remove (anAnimation);
+      }
+    }
+    // playback options
+    else if (anArg == "-play")
+    {
+      toPlay = Standard_True;
+      if (++anArgIter < theArgNb)
+      {
+        if (*theArgVec[anArgIter] == '-')
+        {
+          --anArgIter;
+          continue;
+        }
+        aPlayStartTime = Draw::Atof (theArgVec[anArgIter]);
+
+        if (++anArgIter < theArgNb)
+        {
+          if (*theArgVec[anArgIter] == '-')
+          {
+            --anArgIter;
+            continue;
+          }
+          aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
+        }
+      }
+    }
+    else if (anArg == "-resume")
+    {
+      toPlay = Standard_True;
+      aPlayStartTime = anAnimation->ElapsedTime();
+      if (++anArgIter < theArgNb)
+      {
+        if (*theArgVec[anArgIter] == '-')
+        {
+          --anArgIter;
+          continue;
+        }
+
+        aPlayDuration = Draw::Atof (theArgVec[anArgIter]);
+      }
+    }
+    else if (anArg == "-playspeed"
+          || anArg == "-speed")
+    {
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+      aPlaySpeed = Draw::Atof (theArgVec[anArgIter]);
+    }
+    else if (anArg == "-lock"
+          || anArg == "-lockloop"
+          || anArg == "-playlockloop")
+    {
+      isLockLoop = Standard_True;
+    }
+    else if (anArg == "-freecamera"
+          || anArg == "-playfreecamera"
+          || anArg == "-freelook")
+    {
+      isFreeCamera = Standard_True;
+    }
+    else if (anArg == "-fps")
+    {
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+
+      TCollection_AsciiString aFpsArg (theArgVec[anArgIter]);
+      Standard_Integer aSplitIndex = aFpsArg.FirstLocationInSet ("/", 1, aFpsArg.Length());
+      if (aSplitIndex == 0)
+      {
+        aFpsNum = aFpsArg.IntegerValue();
+      }
+      else
+      {
+        const TCollection_AsciiString aDenStr = aFpsArg.Split (aSplitIndex);
+        aFpsArg.Split (aFpsArg.Length() - 1);
+        const TCollection_AsciiString aNumStr = aFpsArg;
+        aFpsNum = aNumStr.IntegerValue();
+        aFpsDen = aDenStr.IntegerValue();
+        if (aFpsDen < 1)
+        {
+          std::cout << "Syntax error at " << anArg << ".\n";
+          return 1;
+        }
+      }
+    }
+    // animation definition options
+    else if (anArg == "-start"
+          || anArg == "-starttime"
+          || anArg == "-startpts")
+    {
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+
+      anAnimation->SetStartPts (Draw::Atof (theArgVec[anArgIter]));
+      aRootAnimation->UpdateTotalDuration();
+    }
+    else if (anArg == "-end"
+          || anArg == "-endtime"
+          || anArg == "-endpts")
+    {
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+
+      anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]) - anAnimation->StartPts());
+      aRootAnimation->UpdateTotalDuration();
+    }
+    else if (anArg == "-dur"
+          || anArg == "-duration")
+    {
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+
+      anAnimation->SetOwnDuration (Draw::Atof (theArgVec[anArgIter]));
+      aRootAnimation->UpdateTotalDuration();
+    }
+    else if (anArg == "-command"
+          || anArg == "-cmd"
+          || anArg == "-invoke"
+          || anArg == "-eval"
+          || anArg == "-proc")
+    {
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+
+      Handle(ViewerTest_AnimationProc) aCmdAnimation = new ViewerTest_AnimationProc (anAnimation->Name(), &theDI, theArgVec[anArgIter]);
+      replaceAnimation (aParentAnimation, anAnimation, aCmdAnimation);
+    }
+    else if (anArg == "-objecttrsf"
+          || anArg == "-objectransformation"
+          || anArg == "-objtransformation"
+          || anArg == "-objtrsf"
+          || anArg == "-object"
+          || anArg == "-obj")
+    {
+      if (++anArgIter >= theArgNb)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+
+      TCollection_AsciiString anObjName (theArgVec[anArgIter]);
+      const ViewerTest_DoubleMapOfInteractiveAndName& aMapOfAIS = GetMapOfAIS();
+      if (!aMapOfAIS.IsBound2 (anObjName))
+      {
+        std::cout << "Syntax error: wrong object name at " << anArg << "\n";
+        return 1;
+      }
+
+      Handle(AIS_InteractiveObject) anObject = Handle(AIS_InteractiveObject)::DownCast (aMapOfAIS.Find2 (anObjName));
+      gp_Trsf       aTrsfs   [2] = { anObject->LocalTransformation(), anObject->LocalTransformation() };
+      gp_Quaternion aRotQuats[2] = { aTrsfs[0].GetRotation(),         aTrsfs[1].GetRotation() };
+      gp_XYZ        aLocPnts [2] = { aTrsfs[0].TranslationPart(),     aTrsfs[1].TranslationPart() };
+      Standard_Real aScales  [2] = { aTrsfs[0].ScaleFactor(),         aTrsfs[1].ScaleFactor() };
+      Standard_Boolean isTrsfSet = Standard_False;
+      Standard_Integer aTrsfArgIter = anArgIter + 1;
+      for (; aTrsfArgIter < theArgNb; ++aTrsfArgIter)
+      {
+        TCollection_AsciiString aTrsfArg (theArgVec[aTrsfArgIter]);
+        aTrsfArg.LowerCase();
+        const Standard_Integer anIndex = aTrsfArg.EndsWith ("1") ? 0 : 1;
+        if (aTrsfArg.StartsWith ("-rotation")
+         || aTrsfArg.StartsWith ("-rot"))
+        {
+          isTrsfSet = Standard_True;
+          if (aTrsfArgIter + 4 >= theArgNb
+          || !parseQuaternion (theArgVec + aTrsfArgIter + 1, aRotQuats[anIndex]))
+          {
+            std::cout << "Syntax error at " << aTrsfArg << ".\n";
+            return 1;
+          }
+          aTrsfArgIter += 4;
+        }
+        else if (aTrsfArg.StartsWith ("-location")
+              || aTrsfArg.StartsWith ("-loc"))
+        {
+          isTrsfSet = Standard_True;
+          if (aTrsfArgIter + 3 >= theArgNb
+          || !parseXYZ (theArgVec + aTrsfArgIter + 1, aLocPnts[anIndex]))
+          {
+            std::cout << "Syntax error at " << aTrsfArg << ".\n";
+            return 1;
+          }
+          aTrsfArgIter += 3;
+        }
+        else if (aTrsfArg.StartsWith ("-scale"))
+        {
+          isTrsfSet = Standard_True;
+          if (++aTrsfArgIter >= theArgNb)
+          {
+            std::cout << "Syntax error at " << aTrsfArg << ".\n";
+            return 1;
+          }
+
+          const TCollection_AsciiString aScaleStr (theArgVec[aTrsfArgIter]);
+          if (!aScaleStr.IsRealValue())
+          {
+            std::cout << "Syntax error at " << aTrsfArg << ".\n";
+            return 1;
+          }
+          aScales[anIndex] = aScaleStr.RealValue();
+        }
+        else
+        {
+          anArgIter = aTrsfArgIter - 1;
+          break;
+        }
+      }
+      if (!isTrsfSet)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+      else if (aTrsfArgIter >= theArgNb)
+      {
+        anArgIter = theArgNb;
+      }
+
+      aTrsfs[0].SetRotation        (aRotQuats[0]);
+      aTrsfs[1].SetRotation        (aRotQuats[1]);
+      aTrsfs[0].SetTranslationPart (aLocPnts[0]);
+      aTrsfs[1].SetTranslationPart (aLocPnts[1]);
+      aTrsfs[0].SetScaleFactor     (aScales[0]);
+      aTrsfs[1].SetScaleFactor     (aScales[1]);
+
+      Handle(AIS_AnimationObject) anObjAnimation = new AIS_AnimationObject (anAnimation->Name(), aCtx, anObject, aTrsfs[0], aTrsfs[1]);
+      replaceAnimation (aParentAnimation, anAnimation, anObjAnimation);
+    }
+    else if (anArg == "-viewtrsf"
+          || anArg == "-view")
+    {
+      Handle(AIS_AnimationCamera) aCamAnimation = Handle(AIS_AnimationCamera)::DownCast (anAnimation);
+      if (aCamAnimation.IsNull())
+      {
+        aCamAnimation = new AIS_AnimationCamera (anAnimation->Name(), aView);
+        replaceAnimation (aParentAnimation, anAnimation, aCamAnimation);
+      }
+
+      Handle(Graphic3d_Camera) aCams[2] =
+      {
+        new Graphic3d_Camera (aCamAnimation->View()->Camera()),
+        new Graphic3d_Camera (aCamAnimation->View()->Camera())
+      };
+
+      Standard_Boolean isTrsfSet = Standard_False;
+      Standard_Integer aViewArgIter = anArgIter + 1;
+      for (; aViewArgIter < theArgNb; ++aViewArgIter)
+      {
+        TCollection_AsciiString aViewArg (theArgVec[aViewArgIter]);
+        aViewArg.LowerCase();
+        const Standard_Integer anIndex = aViewArg.EndsWith("1") ? 0 : 1;
+        if (aViewArg.StartsWith ("-scale"))
+        {
+          isTrsfSet = Standard_True;
+          if (++aViewArgIter >= theArgNb)
+          {
+            std::cout << "Syntax error at " << anArg << ".\n";
+            return 1;
+          }
+
+          const TCollection_AsciiString aScaleStr (theArgVec[aViewArgIter]);
+          if (!aScaleStr.IsRealValue())
+          {
+            std::cout << "Syntax error at " << aViewArg << ".\n";
+            return 1;
+          }
+          Standard_Real aScale = aScaleStr.RealValue();
+          aScale = aCamAnimation->View()->DefaultCamera()->Scale() / aScale;
+          aCams[anIndex]->SetScale (aScale);
+        }
+        else if (aViewArg.StartsWith ("-eye")
+              || aViewArg.StartsWith ("-center")
+              || aViewArg.StartsWith ("-at")
+              || aViewArg.StartsWith ("-up"))
+        {
+          isTrsfSet = Standard_True;
+          gp_XYZ anXYZ;
+          if (aViewArgIter + 3 >= theArgNb
+          || !parseXYZ (theArgVec + aViewArgIter + 1, anXYZ))
+          {
+            std::cout << "Syntax error at " << aViewArg << ".\n";
+            return 1;
+          }
+          aViewArgIter += 3;
+
+          if (aViewArg.StartsWith ("-eye"))
+          {
+            aCams[anIndex]->SetEye (anXYZ);
+          }
+          else if (aViewArg.StartsWith ("-center")
+                || aViewArg.StartsWith ("-at"))
+          {
+            aCams[anIndex]->SetCenter (anXYZ);
+          }
+          else if (aViewArg.StartsWith ("-up"))
+          {
+            aCams[anIndex]->SetUp (anXYZ);
+          }
+        }
+        else
+        {
+          anArgIter = aViewArgIter - 1;
+          break;
+        }
+      }
+      if (!isTrsfSet)
+      {
+        std::cout << "Syntax error at " << anArg << ".\n";
+        return 1;
+      }
+      else if (aViewArgIter >= theArgNb)
+      {
+        anArgIter = theArgNb;
+      }
+
+      aCamAnimation->SetCameraStart(aCams[0]);
+      aCamAnimation->SetCameraEnd  (aCams[1]);
     }
     else
     {
-      anAISView->SetEye (aValues->Value(1).RealValue(), aValues->Value(2).RealValue(), aValues->Value(3).RealValue());
+      std::cout << "Syntax error at " << anArg << ".\n";
+      return 1;
     }
   }
-  if (aMapOfKeysByValues.Find ("AT", aValues))
+
+  if (!toPlay)
   {
-    if (aValues->IsEmpty())
-    {
-      Standard_Real anAtX = 0.0;
-      Standard_Real anAtY = 0.0;
-      Standard_Real anAtZ = 0.0;
-      anAISView->At (anAtX, anAtY, anAtZ);
-      theDi << "At X: " << anAtX << " Y: " << anAtY << " Z: " << anAtZ << "\n";
-    }
-    else
-    {
-      anAISView->SetAt (aValues->Value(1).RealValue(), aValues->Value(2).RealValue(), aValues->Value(3).RealValue());
-    }
+    return 0;
   }
-  if (aMapOfKeysByValues.Find ("PROJ", aValues))
+
+  // Start animation timeline and process frame updating.
+  TheIsAnimating = Standard_True;
+  const Standard_Boolean wasImmediateUpdate = aView->SetImmediateUpdate (Standard_False);
+  Handle(Graphic3d_Camera) aCameraBack = new Graphic3d_Camera (aView->Camera());
+  anAnimation->StartTimer (aPlayStartTime, aPlaySpeed, Standard_True, aPlayDuration <= 0.0);
+  if (isFreeCamera)
   {
-    if (aValues->IsEmpty())
-    {
-      Standard_Real aProjX = 0.0;
-      Standard_Real aProjY = 0.0;
-      Standard_Real aProjZ = 0.0;
-      anAISView->Proj (aProjX, aProjY, aProjZ);
-      theDi << "Proj X: " << aProjX << " Y: " << aProjY << " Z: " << aProjZ << "\n";
-    }
-    else
-    {
-      anAISView->SetProj (aValues->Value(1).RealValue(), aValues->Value(2).RealValue(), aValues->Value(3).RealValue());
-    }
+    aView->Camera()->Copy (aCameraBack);
   }
-  if (aMapOfKeysByValues.Find ("UP", aValues))
+
+  const Standard_Real anUpperPts = aPlayStartTime + aPlayDuration;
+  if (aFpsNum <= 0)
   {
-    if (aValues->IsEmpty())
+    while (!anAnimation->IsStopped())
+    {
+      aCameraBack->Copy (aView->Camera());
+      const Standard_Real aPts = anAnimation->UpdateTimer();
+      if (isFreeCamera)
+      {
+        aView->Camera()->Copy (aCameraBack);
+      }
+
+      if (aPts >= anUpperPts)
+      {
+        anAnimation->Pause();
+        break;
+      }
+
+      if (aView->IsInvalidated())
+      {
+        aView->Redraw();
+      }
+      else
+      {
+        aView->RedrawImmediate();
+      }
+
+      if (!isLockLoop)
+      {
+        // handle user events
+        theDI.Eval ("after 1 set waiter 1");
+        theDI.Eval ("vwait waiter");
+      }
+      if (!TheIsAnimating)
+      {
+        anAnimation->Pause();
+        theDI << aPts;
+        break;
+      }
+    }
+
+    if (aView->IsInvalidated())
     {
-      Standard_Real anUpX = 0.0;
-      Standard_Real anUpY = 0.0;
-      Standard_Real anUpZ = 0.0;
-      anAISView->Up (anUpX, anUpY, anUpZ);
-      theDi << "Up X: " << anUpX << " Y: " << anUpY << " Z: " << anUpZ << "\n";
+      aView->Redraw();
     }
     else
     {
-      anAISView->SetUp (aValues->Value(1).RealValue(), aValues->Value(2).RealValue(), aValues->Value(3).RealValue());
+      aView->RedrawImmediate();
     }
   }
-  if (aMapOfKeysByValues.Find ("CENTER", aValues))
+  else
   {
-    anAISView->SetCenter (aValues->Value(1).IntegerValue(), aValues->Value(2).IntegerValue());
+    OSD_Timer aPerfTimer;
+    aPerfTimer.Start();
+
+    // Manage frame-rated animation here
+    Standard_Real aPts = aPlayStartTime;
+    int64_t aNbFrames = 0;
+    for (; aPts <= anUpperPts;)
+    {
+      const Standard_Real aRecPts = aPlaySpeed * ((Standard_Real(aFpsDen) / Standard_Real(aFpsNum)) * Standard_Real(aNbFrames));
+      aPts = aPlayStartTime + aRecPts;
+      ++aNbFrames;
+      if (!anAnimation->Update (aPts))
+      {
+        break;
+      }
+
+      aView->Redraw();
+    }
+
+    aPerfTimer.Stop();
+    anAnimation->Stop();
+    const Standard_Real aRecFps = Standard_Real(aNbFrames) / aPerfTimer.ElapsedTime();
+    theDI << "Average FPS: " << aRecFps << "\n"
+          << "Nb. Frames: "  << Standard_Real(aNbFrames);
+
+    aView->Redraw();
   }
 
+  aView->SetImmediateUpdate (wasImmediateUpdate);
+  TheIsAnimating = Standard_False;
   return 0;
 }
 
+
 //=======================================================================
 //function : VChangeSelected
 //purpose  : Adds the shape to selection or remove one from it
@@ -6093,7 +6987,7 @@ static Standard_Integer VPurgeDisplay (Draw_Interpretor& di,
     di << "use 'vinit' command before " << argv[0] << "\n";
     return 1;
   }
-  aContext->CloseAllContexts(Standard_False);
+
   di << aContext->PurgeDisplay() << "\n";
   return 0;
 }
@@ -8170,16 +9064,17 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
       case Graphic3d_RM_RAYTRACING:    theDI << "raytrace ";      break;
     }
     theDI << "\n";
-    theDI << "msaa:         " <<  aParams.NbMsaaSamples                               << "\n";
-    theDI << "rayDepth:     " <<  aParams.RaytracingDepth                             << "\n";
-    theDI << "fsaa:         " << (aParams.IsAntialiasingEnabled       ? "on" : "off") << "\n";
-    theDI << "shadows:      " << (aParams.IsShadowEnabled             ? "on" : "off") << "\n";
-    theDI << "reflections:  " << (aParams.IsReflectionEnabled         ? "on" : "off") << "\n";
-    theDI << "gleam:        " << (aParams.IsTransparentShadowEnabled  ? "on" : "off") << "\n";
-    theDI << "GI:           " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
-    theDI << "blocked RNG:  " << (aParams.CoherentPathTracingMode     ? "on" : "off") << "\n";
-    theDI << "iss:          " << (aParams.AdaptiveScreenSampling      ? "on" : "off") << "\n";
-    theDI << "iss debug:    " << (aParams.ShowSamplingTiles           ? "on" : "off") << "\n";
+    theDI << "msaa:           " <<  aParams.NbMsaaSamples                               << "\n";
+    theDI << "rayDepth:       " <<  aParams.RaytracingDepth                             << "\n";
+    theDI << "fsaa:           " << (aParams.IsAntialiasingEnabled       ? "on" : "off") << "\n";
+    theDI << "shadows:        " << (aParams.IsShadowEnabled             ? "on" : "off") << "\n";
+    theDI << "reflections:    " << (aParams.IsReflectionEnabled         ? "on" : "off") << "\n";
+    theDI << "gleam:          " << (aParams.IsTransparentShadowEnabled  ? "on" : "off") << "\n";
+    theDI << "GI:             " << (aParams.IsGlobalIlluminationEnabled ? "on" : "off") << "\n";
+    theDI << "blocked RNG:    " << (aParams.CoherentPathTracingMode     ? "on" : "off") << "\n";
+    theDI << "iss:            " << (aParams.AdaptiveScreenSampling      ? "on" : "off") << "\n";
+    theDI << "iss debug:      " << (aParams.ShowSamplingTiles           ? "on" : "off") << "\n";
+    theDI << "two-sided BSDF: " << (aParams.TwoSidedBsdfModels          ? "on" : "off") << "\n";
     theDI << "shadingModel: ";
     switch (aView->ShadingModel())
     {
@@ -8453,6 +9348,22 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI,
       }
       aParams.UseEnvironmentMapBackground = toEnable;
     }
+    else if (aFlag == "-twoside")
+    {
+      if (toPrint)
+      {
+        theDI << (aParams.TwoSidedBsdfModels ? "on" : "off") << " ";
+        continue;
+      }
+
+      Standard_Boolean toEnable = Standard_True;
+      if (++anArgIter < theArgNb
+        && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
+      {
+        --anArgIter;
+      }
+      aParams.TwoSidedBsdfModels = toEnable;
+    }
     else if (aFlag == "-shademodel"
           || aFlag == "-shadingmodel"
           || aFlag == "-shading")
@@ -8576,7 +9487,7 @@ static Standard_Integer VProgressiveMode (Draw_Interpretor& /*theDI*/,
     Standard_Boolean toExit = Standard_False;
 
     MSG aMsg;
-    while (PeekMessage (&aMsg, NULL, 0, 0, PM_REMOVE))
+    while (PeekMessageW (&aMsg, NULL, 0, 0, PM_REMOVE))
     {
       if (aMsg.message == WM_KEYDOWN && (aMsg.wParam == 0x0d || aMsg.wParam == 0x1b))
       {
@@ -8584,7 +9495,7 @@ static Standard_Integer VProgressiveMode (Draw_Interpretor& /*theDI*/,
       }
 
       TranslateMessage (&aMsg);
-      DispatchMessage  (&aMsg);
+      DispatchMessageW (&aMsg);
     }
 
     if (toExit)
@@ -9044,43 +9955,6 @@ static int VManipulator (Draw_Interpretor& theDi,
   return 0;
 }
 
-//===============================================================================================
-//function : parseColor
-//purpose  :
-//===============================================================================================
-static Standard_Boolean parseColor (ViewerTest_CmdParser& theParser,
-                                    const std::string&    theOptionName,
-                                    Quantity_Color&       theColor)
-{
-  std::string aColorArg = theParser.Arg (theOptionName, 0);
-  if (std::isdigit (aColorArg[0]))
-  {
-    Graphic3d_Vec3d aColor = theParser.ArgVec3d (theOptionName);
-    if (aColor.x() < 0.0 || aColor.x() > 1.0
-      || aColor.y() < 0.0 || aColor.y() > 1.0
-      || aColor.z() < 0.0 || aColor.z() > 1.0)
-    {
-      std::cerr << "Error: RGB color values should be within range 0..1!\n";
-      return Standard_False;
-    }
-    theColor.SetValues (aColor.x(), aColor.y(), aColor.z(), Quantity_TOC_RGB);
-  }
-  else
-  {
-    Quantity_NameOfColor aName = Quantity_NOC_BLACK;
-    if (!Quantity_Color::ColorFromName (aColorArg.c_str(), aName))
-    {
-      std::cerr << "Name: " << theParser.Arg (theOptionName, 0)
-                << " does not correspond to any color in Quantity_NameOfColor!"
-                << std::endl;
-      return Standard_False;
-    }
-    theColor.SetValues (aName);
-  }
-
-  return Standard_True;
-}
-
 //===============================================================================================
 //function : VSelectionProperties
 //purpose  :
@@ -9096,78 +9970,368 @@ static int VSelectionProperties (Draw_Interpretor& theDi,
     return 1;
   }
 
-  ViewerTest_CmdParser aCmd;
+  Standard_Boolean toPrint  = theArgsNb == 1;
+  Standard_Boolean toRedraw = Standard_False;
+  Standard_Integer anArgIter = 1;
+  Prs3d_TypeOfHighlight aType = Prs3d_TypeOfHighlight_None;
+  if (anArgIter < theArgsNb)
+  {
+    TCollection_AsciiString anArgFirst (theArgVec[anArgIter]);
+    anArgFirst.LowerCase();
+    ++anArgIter;
+    if (anArgFirst == "dynhighlight"
+     || anArgFirst == "dynhilight"
+     || anArgFirst == "dynamichighlight"
+     || anArgFirst == "dynamichilight")
+    {
+      aType = Prs3d_TypeOfHighlight_Dynamic;
+    }
+    else if (anArgFirst == "localdynhighlight"
+          || anArgFirst == "localdynhilight"
+          || anArgFirst == "localdynamichighlight"
+          || anArgFirst == "localdynamichilight")
+    {
+      aType = Prs3d_TypeOfHighlight_LocalDynamic;
+    }
+    else if (anArgFirst == "selhighlight"
+          || anArgFirst == "selhilight"
+          || anArgFirst == "selectedhighlight"
+          || anArgFirst == "selectedhilight")
+    {
+      aType = Prs3d_TypeOfHighlight_Selected;
+    }
+    else if (anArgFirst == "localselhighlight"
+          || anArgFirst == "localselhilight"
+          || anArgFirst == "localselectedhighlight"
+          || anArgFirst == "localselectedhilight")
+    {
+      aType = Prs3d_TypeOfHighlight_LocalSelected;
+    }
+    else
+    {
+      --anArgIter;
+    }
+  }
+  for (; anArgIter < theArgsNb; ++anArgIter)
+  {
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    if (anArg == "-help")
+    {
+      theDi.PrintHelp (theArgVec[0]);
+      return 0;
+    }
+    else if (anArg == "-print")
+    {
+      toPrint = Standard_True;
+    }
+    else if (anArg == "-autoactivate")
+    {
+      Standard_Boolean toEnable = Standard_True;
+      if (anArgIter + 1 < theArgsNb
+       && ViewerTest::ParseOnOff (theArgVec[anArgIter + 1], toEnable))
+      {
+        ++anArgIter;
+      }
+      aCtx->SetAutoActivateSelection (toEnable);
+    }
+    else if (anArg == "-pixtol"
+          && anArgIter + 1 < theArgsNb)
+    {
+      aCtx->SetPixelTolerance (Draw::Atoi (theArgVec[++anArgIter]));
+    }
+    else if ((anArg == "-mode"
+           || anArg == "-dispmode")
+          && anArgIter + 1 < theArgsNb)
+    {
+      if (aType == Prs3d_TypeOfHighlight_None)
+      {
+        std::cout << "Syntax error: type of highlighting is undefined\n";
+        return 1;
+      }
+
+      const Standard_Integer aDispMode = Draw::Atoi (theArgVec[++anArgIter]);
+      const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
+      aStyle->SetDisplayMode (aDispMode);
+      toRedraw = Standard_True;
+    }
+    else if (anArg == "-layer"
+          && anArgIter + 1 < theArgsNb)
+    {
+      if (aType == Prs3d_TypeOfHighlight_None)
+      {
+        std::cout << "Syntax error: type of highlighting is undefined\n";
+        return 1;
+      }
 
-  aCmd.AddOption ("autoActivate");
-  aCmd.AddOption ("pixTol");
+      const Standard_Integer aNewLayer = Draw::Atoi (theArgVec[++anArgIter]);
+      if (aNewLayer != Graphic3d_ZLayerId_UNKNOWN)
+      {
+        TColStd_SequenceOfInteger aLayers;
+        aCtx->CurrentViewer()->GetAllZLayers (aLayers);
+        if (std::find (aLayers.begin(), aLayers.end(), aNewLayer) == aLayers.end())
+        {
+          std::cout << "Syntax error: Layer " << aNewLayer << " is undefined\n";
+          return 1;
+        }
+      }
 
-  aCmd.AddOption ("selColor");
-  aCmd.AddOption ("hiColor");
-  aCmd.AddOption ("selTransp");
-  aCmd.AddOption ("hiTransp");
+      const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
+      aStyle->SetZLayer (aNewLayer);
+      toRedraw = Standard_True;
+    }
+    else if (anArg == "-hicolor"
+          || anArg == "-selcolor"
+          || anArg == "-color")
+    {
+      if (anArg.StartsWith ("-hi"))
+      {
+        aType = Prs3d_TypeOfHighlight_Dynamic;
+      }
+      else if (anArg.StartsWith ("-sel"))
+      {
+        aType = Prs3d_TypeOfHighlight_Selected;
+      }
+      else if (aType == Prs3d_TypeOfHighlight_None)
+      {
+        std::cout << "Syntax error: type of highlighting is undefined\n";
+        return 1;
+      }
 
-  aCmd.AddOption ("print");
+      Quantity_Color aColor;
+      Standard_Integer aNbParsed = ViewerTest::ParseColor (theArgsNb - anArgIter - 1,
+                                                           theArgVec + anArgIter + 1,
+                                                           aColor);
+      if (aNbParsed == 0)
+      {
+        std::cout << "Syntax error: need more arguments.\n";
+        return 1;
+      }
+      anArgIter += aNbParsed;
 
-  aCmd.Parse (theArgsNb, theArgVec);
+      const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
+      aStyle->SetColor (aColor);
+      toRedraw = Standard_True;
+    }
+    else if ((anArg == "-transp"
+           || anArg == "-transparency"
+           || anArg == "-hitransp"
+           || anArg == "-seltransp"
+           || anArg == "-hitransplocal"
+           || anArg == "-seltransplocal")
+          && anArgIter + 1 < theArgsNb)
+    {
+      if (anArg.StartsWith ("-hi"))
+      {
+        aType = Prs3d_TypeOfHighlight_Dynamic;
+      }
+      else if (anArg.StartsWith ("-sel"))
+      {
+        aType = Prs3d_TypeOfHighlight_Selected;
+      }
+      else if (aType == Prs3d_TypeOfHighlight_None)
+      {
+        std::cout << "Syntax error: type of highlighting is undefined\n";
+        return 1;
+      }
 
-  if (aCmd.HasOption ("help"))
+      const Standard_Real aTransp = Draw::Atof (theArgVec[++anArgIter]);
+      const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
+      aStyle->SetTransparency ((Standard_ShortReal )aTransp);
+      toRedraw = Standard_True;
+    }
+    else if ((anArg == "-mat"
+           || anArg == "-material")
+          && anArgIter + 1 < theArgsNb)
+    {
+      if (aType == Prs3d_TypeOfHighlight_None)
+      {
+        std::cout << "Syntax error: type of highlighting is undefined\n";
+        return 1;
+      }
+
+      const Handle(Prs3d_Drawer)& aStyle = aCtx->HighlightStyle (aType);
+      Graphic3d_NameOfMaterial aMatName = Graphic3d_MaterialAspect::MaterialFromName (theArgVec[anArgIter + 1]);
+      if (aMatName != Graphic3d_NOM_DEFAULT)
+      {
+        ++anArgIter;
+        Handle(Graphic3d_AspectFillArea3d) anAspect = new Graphic3d_AspectFillArea3d();
+        *anAspect = *aCtx->DefaultDrawer()->ShadingAspect()->Aspect();
+        Graphic3d_MaterialAspect aMat (aMatName);
+        aMat.SetColor (aStyle->Color());
+        aMat.SetTransparency (aStyle->Transparency());
+        anAspect->SetFrontMaterial (aMat);
+        anAspect->SetInteriorColor (aStyle->Color());
+        aStyle->SetBasicFillAreaAspect (anAspect);
+      }
+      else
+      {
+        aStyle->SetBasicFillAreaAspect (Handle(Graphic3d_AspectFillArea3d)());
+      }
+      toRedraw = Standard_True;
+    }
+    else
+    {
+      std::cout << "Syntax error at '" << theArgVec[anArgIter] << "'\n";
+    }
+  }
+
+  if (toPrint)
   {
-    theDi.PrintHelp (theArgVec[0]);
-    return 0;
+    const Handle(Prs3d_Drawer)& aHiStyle  = aCtx->HighlightStyle();
+    const Handle(Prs3d_Drawer)& aSelStyle = aCtx->SelectionStyle();
+    theDi << "Auto-activation                : " << (aCtx->GetAutoActivateSelection() ? "On" : "Off") << "\n";
+    theDi << "Selection pixel tolerance      : " << aCtx->MainSelector()->PixelTolerance() << "\n";
+    theDi << "Selection color                : " << Quantity_Color::StringName (aSelStyle->Color().Name()) << "\n";
+    theDi << "Dynamic highlight color        : " << Quantity_Color::StringName (aHiStyle->Color().Name()) << "\n";
+    theDi << "Selection transparency         : " << aSelStyle->Transparency() << "\n";
+    theDi << "Dynamic highlight transparency : " << aHiStyle->Transparency() << "\n";
+    theDi << "Selection mode                 : " << aSelStyle->DisplayMode() << "\n";
+    theDi << "Dynamic highlight mode         : " << aHiStyle->DisplayMode() << "\n";
+    theDi << "Selection layer                : " << aSelStyle->ZLayer() << "\n";
+    theDi << "Dynamic layer                  : " << aHiStyle->ZLayer() << "\n";
   }
 
-  if (aCmd.HasOption ("autoActivate", 1, Standard_False))
+  if (aCtx->NbSelected() != 0 && toRedraw)
   {
-    aCtx->SetAutoActivateSelection (aCmd.ArgBool ("autoActivate"));
+    aCtx->HilightSelected (Standard_True);
   }
-  if (aCmd.HasOption ("pixTol", 1, Standard_False))
+
+  return 0;
+}
+
+//===============================================================================================
+//function : VDumpSelectionImage
+//purpose  :
+//===============================================================================================
+static int VDumpSelectionImage (Draw_Interpretor& /*theDi*/,
+                                Standard_Integer  theArgsNb,
+                                const char**      theArgVec)
+{
+  if (theArgsNb < 2)
   {
-    aCtx->SetPixelTolerance (aCmd.ArgInt ("pixTol"));
+    std::cout << "Syntax error: wrong number arguments for '" << theArgVec[0] << "'\n";
+    return 1;
   }
 
-  Handle(Graphic3d_HighlightStyle)& aHiStyle = aCtx->ChangeHighlightStyle();
-  Handle(Graphic3d_HighlightStyle)& aSelStyle = aCtx->ChangeSelectionStyle();
-  Standard_Boolean toRedraw = Standard_False;
-  if (aCmd.HasOption ("selColor"))
+  const Handle(AIS_InteractiveContext)& aContext = ViewerTest::GetAISContext();
+  if (aContext.IsNull())
   {
-    Quantity_Color aNewColor;
-    if (!parseColor (aCmd, "selColor", aNewColor))
-      return 1;
-    aSelStyle->SetColor (aNewColor);
-    toRedraw = Standard_True;
+    std::cout << "Error: no active view.\n";
+    return 1;
   }
-  if (aCmd.HasOption ("hiColor"))
+
+  TCollection_AsciiString aFile;
+  StdSelect_TypeOfSelectionImage aType = StdSelect_TypeOfSelectionImage_NormalizedDepth;
+  Image_PixMap::ImgFormat anImgFormat = Image_PixMap::ImgBGR;
+  Standard_Integer aPickedIndex = 1;
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
   {
-    Quantity_Color aNewColor;
-    if (!parseColor (aCmd, "hiColor", aNewColor))
+    TCollection_AsciiString aParam (theArgVec[anArgIter]);
+    aParam.LowerCase();
+    if (aParam == "-type")
+    {
+      if (++anArgIter >= theArgsNb)
+      {
+        std::cout << "Syntax error: wrong number parameters of flag '-depth'.\n";
+        return 1;
+      }
+
+      TCollection_AsciiString aValue (theArgVec[anArgIter]);
+      aValue.LowerCase();
+      if (aValue == "depth"
+       || aValue == "normdepth"
+       || aValue == "normalizeddepth")
+      {
+        aType       = StdSelect_TypeOfSelectionImage_NormalizedDepth;
+        anImgFormat = Image_PixMap::ImgGrayF;
+      }
+      if (aValue == "depthinverted"
+       || aValue == "normdepthinverted"
+       || aValue == "normalizeddepthinverted"
+       || aValue == "inverted")
+      {
+        aType       = StdSelect_TypeOfSelectionImage_NormalizedDepthInverted;
+        anImgFormat = Image_PixMap::ImgGrayF;
+      }
+      else if (aValue == "unnormdepth"
+            || aValue == "unnormalizeddepth")
+      {
+        aType       = StdSelect_TypeOfSelectionImage_UnnormalizedDepth;
+        anImgFormat = Image_PixMap::ImgGrayF;
+      }
+      else if (aValue == "objectcolor"
+            || aValue == "object"
+            || aValue == "color")
+      {
+        aType = StdSelect_TypeOfSelectionImage_ColoredDetectedObject;
+      }
+      else if (aValue == "entitycolor"
+            || aValue == "entity")
+      {
+        aType = StdSelect_TypeOfSelectionImage_ColoredEntity;
+      }
+      else if (aValue == "ownercolor"
+            || aValue == "owner")
+      {
+        aType = StdSelect_TypeOfSelectionImage_ColoredOwner;
+      }
+      else if (aValue == "selectionmodecolor"
+            || aValue == "selectionmode"
+            || aValue == "selmodecolor"
+            || aValue == "selmode")
+      {
+        aType = StdSelect_TypeOfSelectionImage_ColoredSelectionMode;
+      }
+    }
+    else if (aParam == "-picked"
+          || aParam == "-pickeddepth"
+          || aParam == "-pickedindex")
+    {
+      if (++anArgIter >= theArgsNb)
+      {
+        std::cout << "Syntax error: wrong number parameters at '" << aParam << "'.\n";
+        return 1;
+      }
+
+      aPickedIndex = Draw::Atoi (theArgVec[anArgIter]);
+    }
+    else if (aFile.IsEmpty())
+    {
+      aFile = theArgVec[anArgIter];
+    }
+    else
+    {
+      std::cout << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'.\n";
       return 1;
-    aHiStyle->SetColor (aNewColor);
+    }
   }
-  if (aCmd.HasOption ("selTransp"))
+  if (aFile.IsEmpty())
   {
-    aSelStyle->SetTransparency (aCmd.ArgFloat ("selTransp"));
-    toRedraw = Standard_True;
+    std::cout << "Syntax error: image file name is missing.\n";
+    return 1;
   }
-  if (aCmd.HasOption ("hiTransp"))
+
+  const Handle(V3d_View)& aView = ViewerTest::CurrentView();
+  Standard_Integer aWidth = 0, aHeight = 0;
+  aView->Window()->Size (aWidth, aHeight);
+
+  Image_AlienPixMap aPixMap;
+  if (!aPixMap.InitZero (anImgFormat, aWidth, aHeight))
   {
-    aHiStyle->SetTransparency (aCmd.ArgFloat ("hiTransp"));
+    std::cout << "Error: can't allocate image.\n";
+    return 1;
   }
-
-  if (aCmd.HasOption ("print") || theArgsNb == 1)
+  if (!aContext->MainSelector()->ToPixMap (aPixMap, aView, aType, aPickedIndex))
   {
-    theDi << "Auto-activation                : " << (aCtx->GetAutoActivateSelection() ? "On" : "Off") << "\n";
-    theDi << "Selection pixel tolerance      : " << aCtx->MainSelector()->PixelTolerance() << "\n";
-    theDi << "Selection color                : " << Quantity_Color::StringName (aCtx->SelectionStyle()->Color().Name()) << "\n";
-    theDi << "Dynamic highlight color        : " << Quantity_Color::StringName (aCtx->HighlightStyle()->Color().Name()) << "\n";
-    theDi << "Selection transparency         : " << aCtx->SelectionStyle()->Transparency() << "\n";
-    theDi << "Dynamic highlight transparency : " << aCtx->HighlightStyle()->Transparency() << "\n";
+    std::cout << "Error: can't generate selection image.\n";
+    return 1;
   }
-
-  if (aCtx->NbSelected() != 0 && toRedraw)
+  if (!aPixMap.Save (aFile))
   {
-    aCtx->HilightSelected (Standard_True);
+    std::cout << "Error: can't save selection image.\n";
+    return 0;
   }
-
   return 0;
 }
 
@@ -9244,8 +10408,8 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
   theCommands.Add("vpick" ,
     "vpick           : vpick X Y Z [shape subshape] ( all variables as string )",
     VPick,group);
-  theCommands.Add("vfit"    ,
-    "vfit or <F> [-selected]"
+  theCommands.Add("vfit",
+    "vfit or <F> [-selected] [-noupdate]"
     "\n\t\t: [-selected] fits the scene according to bounding box of currently selected objects",
     __FILE__,VFit,group);
   theCommands.Add ("vfitarea",
@@ -9315,22 +10479,35 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     " : notice that EMF format requires patched gl2ps",
     __FILE__,VExport,group);
   theCommands.Add("vcolorscale",
-    "vcolorscale     : vcolorscale name [-range RangeMin = 0 RangeMax = 100 Intervals = 10 -font HeightFont = 16  -textpos "
-    "Position = left -xy X = 0 Y = 0] [-noupdate|-update]: draw color scale\n"
-    "-demo/-demoversion draw a demoversion of color scale.\n"
-    "-show/display display color scale.\n"
-    "-hide/erase erase color scale.\n"
-    "Please note that -show/-hide option must be the first argument!\n"
-    "-color Index R G B: set color for indexed interval\n"
-    "-color Index ColorName: set color for indexed interval\n"
-    "-colors R G B R G B ...: set colors for all intervals\n"
-    "-colors ColorName1 ColorName2 ...: set colors for all intervals\n"
-    "-colors supports both color names and rgb values in one call\n"
-    "-label Index Text: set label for indexed interval\n"
-    "-labels Text Text Text ...: set labels for all intervals\n"
-    "-title Title [Position]: set the title for color scale with certain position. Default position = center;\n"
-    "Available text positions: left, right, center, none;\n",
-    __FILE__,VColorScale,group);
+    "vcolorscale name [-noupdate|-update] [-demo]"
+    "\n\t\t:       [-range RangeMin=0 RangeMax=1 NbIntervals=10]"
+    "\n\t\t:       [-font HeightFont=20]"
+    "\n\t\t:       [-logarithmic {on|off}=off] [-reversed {on|off}=off]"
+    "\n\t\t:       [-smoothTransition {on|off}=off]"
+    "\n\t\t:       [-hueRange MinAngle=230 MaxAngle=0]"
+    "\n\t\t:       [-colorRange MinColor=BLUE1 MaxColor=RED]"
+    "\n\t\t:       [-textpos {left|right|center|none}=right]"
+    "\n\t\t:       [-labelAtBorder {on|off}=on]"
+    "\n\t\t:       [-colors Color1 Color2 ...] [-color Index Color]"
+    "\n\t\t:       [-labels Label1 Label2 ...] [-label Index Label]"
+    "\n\t\t:       [-freeLabels NbOfLabels Label1 Label2 ...]"
+    "\n\t\t:       [-xy Left=0 Bottom=0]"
+    "\n\t\t:  -demo     - displays a color scale with demonstratio values"
+    "\n\t\t:  -colors   - set colors for all intervals"
+    "\n\t\t:  -color    - set color for specific interval"
+    "\n\t\t:  -textpos  - horizontal label position relative to color scale bar"
+    "\n\t\t:  -labelAtBorder - vertical label position relative to color interval;"
+    "\n\t\t:              at border means the value inbetween neighbor intervals,"
+    "\n\t\t:              at center means the center value within current interval"
+    "\n\t\t:  -labels   - set labels for all intervals"
+    "\n\t\t:  -freeLabels - same as -labels but does not require"
+    "\n\t\t:              matching the number of intervals"
+    "\n\t\t:  -label    - set label for specific interval"
+    "\n\t\t:  -title    - set title"
+    "\n\t\t:  -reversed - setup smooth color transition between intervals"
+    "\n\t\t:  -smoothTransition - swap colorscale direction"
+    "\n\t\t:  -hueRange - set hue angles corresponding to minimum and maximum values"
+    __FILE__, VColorScale, group);
   theCommands.Add("vgraduatedtrihedron",
     "vgraduatedtrihedron : -on/-off [-xname Name] [-yname Name] [-zname Name] [-arrowlength Value]\n"
     "\t[-namefont Name] [-valuesfont Name]\n"
@@ -9364,22 +10541,17 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "\n\t\t:  -upperLeft tile offset as upper left corner",
     __FILE__, VTile, group);
   theCommands.Add("vzlayer",
-    "vzlayer add/del/get/settings/enable/disable [id]\n"
-    " add - add new z layer to viewer and print its id\n"
-    " del - del z layer by its id\n"
-    " get - print sequence of z layers in increasing order of their overlay level\n"
-    " settings - print status of z layer settings\n"
-    " enable ([depth]test/[depth]write/[depth]clear/[depth]offset) \n    enables given setting for the z layer\n"
-    " enable (p[ositive]offset/n[egative]offset) \n    enables given setting for the z layer\n"
-    " enable textureenv \n    enables environment texture mapping\n"
-    " disable ([depth]test/[depth]write/[depth]clear/[depth]offset) \n    disables given setting for the z layer\n"
-    " disable textureenv \n    disables environment texture mapping\n"
-    "\nWhere id is the layer identificator\n"
-    "\nExamples:\n"
-    "   vzlayer add\n"
-    "   vzlayer enable poffset 1\n"
-    "   vzlayer disable depthtest 1\n"
-    "   vzlayer del 1\n",
+              "vzlayer [layerId]"
+      "\n\t\t:         [-add|-delete|-get|-settings]"
+      "\n\t\t:         [-enable|-disable {depthTest|depthWrite|depthClear|depthoffset}]"
+      "\n\t\t:         [-enable|-disable {positiveOffset|negativeOffset|textureenv}]"
+      "\n\t\t: ZLayer list management:"
+      "\n\t\t:   -add      add new z layer to viewer and print its id"
+      "\n\t\t:   -delete   delete z layer"
+      "\n\t\t:   -get      print sequence of z layers"
+      "\n\t\t:   -settings print status of z layer settings"
+      "\n\t\t:   -disable  disables given setting"
+      "\n\t\t:   -enable   enables  given setting",
     __FILE__,VZLayer,group);
   theCommands.Add("vlayerline",
     "vlayerline : vlayerline x1 y1 x2 y2 [linewidth=0.5] [linetype=0] [transparency=1.0]",
@@ -9500,22 +10672,73 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "vmoveto x y"
     "- emulates cursor movement to pixel postion (x,y)",
     __FILE__, VMoveTo, group);
-  theCommands.Add ("vviewparams", "vviewparams usage:\n"
-    "- vviewparams\n"
-    "- vviewparams [-scale [s]] [-eye [x y z]] [-at [x y z]] [-up [x y z]]\n"
-    "              [-proj [x y z]] [-center x y] [-size sx]\n"
-    "-   Gets or sets current view parameters.\n"
-    "-   If called without arguments, all view parameters are printed.\n"
-    "-   The options are:\n"
-    "      -scale [s]    : prints or sets viewport relative scale.\n"
-    "      -eye [x y z]  : prints or sets eye location.\n"
-    "      -at [x y z]   : prints or sets center of look.\n"
-    "      -up [x y z]   : prints or sets direction of up vector.\n"
-    "      -proj [x y z] : prints or sets direction of look.\n"
-    "      -center x y   : sets location of center of the screen in pixels.\n"
-    "      -size [sx]    : prints viewport projection width and height sizes\n"
-    "                    : or changes the size of its maximum dimension.\n",
+  theCommands.Add ("vviewparams",
+              "vviewparams [-args] [-scale [s]]"
+      "\n\t\t:             [-eye [x y z]] [-at [x y z]] [-up [x y z]]"
+      "\n\t\t:             [-proj [x y z]] [-center x y] [-size sx]"
+      "\n\t\t: Manage current view parameters or prints all"
+      "\n\t\t: current values when called without argument."
+      "\n\t\t:   -scale [s]    prints or sets viewport relative scale"
+      "\n\t\t:   -eye  [x y z] prints or sets eye location"
+      "\n\t\t:   -at   [x y z] prints or sets center of look"
+      "\n\t\t:   -up   [x y z] prints or sets direction of up vector"
+      "\n\t\t:   -proj [x y z] prints or sets direction of look"
+      "\n\t\t:   -center x y   sets location of center of the screen in pixels"
+      "\n\t\t:   -size [sx]    prints viewport projection width and height sizes"
+      "\n\t\t:                 or changes the size of its maximum dimension"
+      "\n\t\t:   -args         prints vviewparams arguments for restoring current view",
     __FILE__, VViewParams, group);
+
+  theCommands.Add("vanimation", "Alias for vanim",
+    __FILE__, VAnimation, group);
+
+  theCommands.Add("vanim",
+            "List existing animations:"
+    "\n\t\t:  vanim"
+    "\n\t\t: Animation playback:"
+    "\n\t\t:  vanim name -play|-resume [playFrom [playDuration]]"
+    "\n\t\t:            [-speed Coeff] [-freeLook] [-lockLoop]"
+    "\n\t\t:   -speed    playback speed (1.0 is normal speed)"
+    "\n\t\t:   -freeLook skip camera animations"
+    "\n\t\t:   -lockLoop disable any interactions"
+    "\n\t\t:"
+    "\n\t\t: Animation definition:"
+    "\n\t\t:  vanim Name/sub/name [-clear] [-delete]"
+    "\n\t\t:        [start TimeSec] [duration TimeSec]"
+    "\n\t\t:"
+    "\n\t\t: Animation name defined in path-style (anim/name or anim.name)"
+    "\n\t\t: specifies nested animations."
+    "\n\t\t: There is no syntax to explicitly add new animation,"
+    "\n\t\t: and all non-existing animations within the name will be"
+    "\n\t\t: implicitly created on first use (including parents)."
+    "\n\t\t:"
+    "\n\t\t: Each animation might define the SINGLE action (see below),"
+    "\n\t\t: like camera transition, object transformation or custom callback."
+    "\n\t\t: Child animations can be used for defining concurrent actions."
+    "\n\t\t:"
+    "\n\t\t: Camera animation:"
+    "\n\t\t:  vanim name -view [-eye1 X Y Z] [-eye2 X Y Z]"
+    "\n\t\t:                   [-at1  X Y Z] [-at2  X Y Z]"
+    "\n\t\t:                   [-up1  X Y Z] [-up2  X Y Z]"
+    "\n\t\t:                   [-scale1 Scale] [-scale2 Scale]"
+    "\n\t\t:   -eyeX   camera Eye positions pair (start and end)"
+    "\n\t\t:   -atX    camera Center positions pair"
+    "\n\t\t:   -upX    camera Up directions pair"
+    "\n\t\t:   -scaleX camera Scale factors pair"
+    "\n\t\t: Object animation:"
+    "\n\t\t:  vanim name -object [-loc1 X Y Z] [-loc2 X Y Z]"
+    "\n\t\t:                     [-rot1 QX QY QZ QW] [-rot2 QX QY QZ QW]"
+    "\n\t\t:                     [-scale1 Scale] [-scale2 Scale]"
+    "\n\t\t:   -locX   object Location points pair (translation)"
+    "\n\t\t:   -rotX   object Orientations pair (quaternions)"
+    "\n\t\t:   -scaleX object Scale factors pair (quaternions)"
+    "\n\t\t: Custom callback:"
+    "\n\t\t:  vanim name -invoke \"Command Arg1 Arg2 %Pts %LocalPts %Normalized ArgN\""
+    "\n\t\t:   %Pts        overall animation presentation timestamp"
+    "\n\t\t:   %LocalPts   local animation timestamp"
+    "\n\t\t:   %Normalized local animation normalized value in range 0..1"
+    __FILE__, VAnimation, group);
+
   theCommands.Add("vchangeselected",
     "vchangeselected shape"
     "- adds to shape to selection or remove one from it",
@@ -9680,6 +10903,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "\n      '-gi           on|off'  Enables/disables global illumination effects"
     "\n      '-brng         on|off'  Enables/disables blocked RNG (fast coherent PT)"
     "\n      '-env          on|off'  Enables/disables environment map background"
+    "\n      '-twoside      on|off'  Enables/disables two-sided BSDF models (PT mode)"
     "\n      '-iss          on|off'  Enables/disables adaptive screen sampling (PT mode)"
     "\n      '-issd         on|off'  Shows screen sampling distribution in ISS mode"
     "\n      '-rebuildGlsl  on|off'  Rebuild Ray-Tracing GLSL programs (for debugging)"
@@ -9731,17 +10955,29 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     __FILE__, VManipulator, group);
 
   theCommands.Add("vselprops",
-    "\n    vselprops [options]"
+    "\n    vselprops [dynHighlight|localDynHighlight|selHighlight|localSelHighlight] [options]"
     "\n    Customizes selection and dynamic highlight parameters for the whole interactive context:"
     "\n    -autoActivate {0|1}     : disables|enables default computation and activation of global selection mode"
     "\n    -pixTol    value        : sets up pixel tolerance"
-    "\n    -selColor  {name|r g b} : sets selection color"
-    "\n    -hiColor   {name|r g b} : sets dynamic highlight color"
-    "\n    -selTransp value        : sets transparency coefficient for selection"
-    "\n    -hiTransp  value        : sets transparency coefficient for dynamic highlight"
+    "\n    -dispMode  dispMode     : sets display mode for highlighting"
+    "\n    -layer     ZLayer       : sets ZLayer for highlighting"
+    "\n    -color     {name|r g b} : sets highlight color"
+    "\n    -transp    value        : sets transparency coefficient for highlight"
+    "\n    -material  material     : sets highlight material"
     "\n    -print                  : prints current state of all mentioned parameters",
     __FILE__, VSelectionProperties, group);
 
+  theCommands.Add ("vseldump",
+                   "vseldump file -type {depth|unnormDepth|object|owner|selMode|entity}=depth -pickedIndex Index=1"
+                   "\n\t\t: Generate an image based on detection results:"
+                   "\n\t\t:   depth       normalized depth values"
+                   "\n\t\t:   unnormDepth unnormalized depth values"
+                   "\n\t\t:   object      color of detected object"
+                   "\n\t\t:   owner       color of detected owner"
+                   "\n\t\t:   selMode     color of selection mode"
+                   "\n\t\t:   entity      color of etected entity",
+                   __FILE__, VDumpSelectionImage, group);
+
 #if defined(_WIN32)
   theCommands.Add("vprogressive",
     "vprogressive",