0030930: Draw Harness, ViewerTest - add commands vlistcolors and vlistmaterials listi...
[occt.git] / src / ViewerTest / ViewerTest_OpenGlCommands.cxx
index 738ccc6..b6d41ec 100644 (file)
 #include <Graphic3d_Group.hxx>
 #include <Graphic3d_ShaderObject.hxx>
 #include <Graphic3d_ShaderProgram.hxx>
-#include <OpenGl_AspectFace.hxx>
-#include <OpenGl_AspectLine.hxx>
-#include <OpenGl_AspectMarker.hxx>
-#include <OpenGl_AspectText.hxx>
+#include <Image_AlienPixMap.hxx>
+#include <OpenGl_Aspects.hxx>
 #include <OpenGl_Context.hxx>
 #include <OpenGl_Element.hxx>
 #include <OpenGl_GlCore20.hxx>
 #include <OpenGl_GraphicDriver.hxx>
+#include <OpenGl_ShaderManager.hxx>
 #include <OpenGl_Workspace.hxx>
 #include <OSD_Environment.hxx>
 #include <OSD_File.hxx>
 #include <Prs3d_Drawer.hxx>
 #include <Prs3d_Presentation.hxx>
 #include <Prs3d_Root.hxx>
+#include <Prs3d_LineAspect.hxx>
 #include <Prs3d_ShadingAspect.hxx>
 #include <Select3D_SensitiveCurve.hxx>
 #include <SelectMgr_EntityOwner.hxx>
 #include <TCollection_AsciiString.hxx>
 #include <V3d_View.hxx>
 #include <V3d_Viewer.hxx>
-#include <Visual3d_View.hxx>
 #include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
 #include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
+#include <OpenGl_Group.hxx>
+#include <OSD_OpenFile.hxx>
 
 extern Standard_Boolean VDisplayAISObject (const TCollection_AsciiString& theName,
                                            const Handle(AIS_InteractiveObject)& theAISObj,
@@ -63,7 +64,7 @@ class VUserDrawObj : public AIS_InteractiveObject
 {
 public:
     // CASCADE RTTI
-    DEFINE_STANDARD_RTTI(VUserDrawObj, AIS_InteractiveObject);
+    DEFINE_STANDARD_RTTI_INLINE(VUserDrawObj,AIS_InteractiveObject);
 
     VUserDrawObj()
     {
@@ -82,17 +83,9 @@ public:
     Handle(VUserDrawObj) myIObj;
 
   public:
-    Element (const Handle(VUserDrawObj)& theIObj,
-             Graphic3d_BndBox4f* theBounds)
-    : myIObj( theIObj )
-    {
-      if (!myIObj.IsNull())
-        myIObj->GetBounds(theBounds);
-    }
+    Element (const Handle(VUserDrawObj)& theIObj) : myIObj (theIObj) {}
 
-    virtual ~Element ()
-    {
-    }
+    virtual ~Element() {}
 
     virtual void Render (const Handle(OpenGl_Workspace)& theWorkspace) const
     {
@@ -113,28 +106,36 @@ private:
     // Virtual methods implementation
     void Compute (const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
                   const Handle(Prs3d_Presentation)& thePresentation,
-                  const Standard_Integer theMode);
+                  const Standard_Integer theMode) Standard_OVERRIDE;
 
     void ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
-                           const Standard_Integer theMode);
+                           const Standard_Integer theMode) Standard_OVERRIDE;
 
     // Called by VUserDrawElement
     void Render(const Handle(OpenGl_Workspace)& theWorkspace) const;
-    void GetBounds(Graphic3d_BndBox4f* theBounds);
 
+private:
     GLfloat myCoords[6];
-
     friend class Element;
 };
 
-void VUserDrawObj::Compute(const Handle(PrsMgr_PresentationManager3d)& /*thePresentationManager*/,
-                           const Handle(Prs3d_Presentation)& thePresentation,
+void VUserDrawObj::Compute(const Handle(PrsMgr_PresentationManager3d)& thePrsMgr,
+                           const Handle(Prs3d_Presentation)& thePrs,
                            const Standard_Integer /*theMode*/)
 {
-  thePresentation->Clear();
-
-  Handle(Graphic3d_Group) aGrp = Prs3d_Root::CurrentGroup(thePresentation);
-  aGrp->UserDraw(this, Standard_True, Standard_True);
+  thePrs->Clear();
+
+  Graphic3d_Vec4 aBndMin (myCoords[0], myCoords[1], myCoords[2], 1.0f);
+  Graphic3d_Vec4 aBndMax (myCoords[3], myCoords[4], myCoords[5], 1.0f);
+  Handle(OpenGl_Group) aGroup = Handle(OpenGl_Group)::DownCast (thePrs->NewGroup());
+  aGroup->SetMinMaxValues (aBndMin.x(), aBndMin.y(), aBndMin.z(),
+                           aBndMax.x(), aBndMax.y(), aBndMax.z());
+  aGroup->SetGroupPrimitivesAspect (myDrawer->LineAspect()->Aspect());
+  VUserDrawObj::Element* anElem = new VUserDrawObj::Element (this);
+  aGroup->AddElement(anElem);
+
+  // invalidate bounding box of the scene
+  thePrsMgr->StructureManager()->Update();
 }
 
 void VUserDrawObj::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
@@ -151,64 +152,39 @@ void VUserDrawObj::ComputeSelection (const Handle(SelectMgr_Selection)& theSelec
   theSelection->Add(aSensitive);
 }
 
-void VUserDrawObj::GetBounds(Graphic3d_BndBox4f* theBounds)
-{
-  if (theBounds)
-  {
-    Graphic3d_Vec4 aMinPt (myCoords[0], myCoords[1], myCoords[2], 1.0f);
-    Graphic3d_Vec4 aMaxPt (myCoords[3], myCoords[4], myCoords[5], 1.0f);
-    if (!theBounds->IsValid())
-    {
-      theBounds->Combine (Graphic3d_BndBox4f (aMinPt, aMaxPt));
-    }
-    else
-    {
-      theBounds->CornerMin() = aMinPt;
-      theBounds->CornerMax() = aMaxPt;
-    }
-  }
-}
-
 void VUserDrawObj::Render(const Handle(OpenGl_Workspace)& theWorkspace) const
 {
+  const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
+
   // To test linking against OpenGl_Workspace and all aspect classes
-  const OpenGl_AspectLine* aLA = theWorkspace->AspectLine(0);
-  const OpenGl_AspectMarker* aMA = theWorkspace->AspectMarker(0);
-  aMA->Type();
-  const OpenGl_AspectText* aTA = theWorkspace->AspectText(0);
-  aTA->FontName();
-  TEL_COLOUR aColor = theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT ?
-    *(theWorkspace->HighlightColor) : aLA->Color();
+  const OpenGl_Aspects* aMA = theWorkspace->Aspects();
+  aMA->Aspect()->MarkerType();
+  OpenGl_Vec4 aColor = theWorkspace->InteriorColor();
 
-  // To test OpenGl_Window
-  //Handle(OpenGl_Context) aCtx = theWorkspace->GetGlContext();
+  aCtx->ShaderManager()->BindLineProgram (Handle(OpenGl_TextureSet)(), Aspect_TOL_SOLID,
+                                          Graphic3d_TOSM_UNLIT, Graphic3d_AlphaMode_Opaque, false,
+                                          Handle(OpenGl_ShaderProgram)());
+  aCtx->SetColor4fv (aColor);
+
+  const OpenGl_Vec3 aVertArray[4] =
+  {
+    OpenGl_Vec3(myCoords[0], myCoords[1], myCoords[2]),
+    OpenGl_Vec3(myCoords[3], myCoords[4], myCoords[2]),
+    OpenGl_Vec3(myCoords[3], myCoords[4], myCoords[5]),
+    OpenGl_Vec3(myCoords[0], myCoords[1], myCoords[5]),
+  };
+  Handle(OpenGl_VertexBuffer) aVertBuffer = new OpenGl_VertexBuffer();
+  aVertBuffer->Init (aCtx, 3, 4, aVertArray[0].GetData());
 
   // Finally draw something to make sure UserDraw really works
-  glPushAttrib(GL_ENABLE_BIT);
-  glDisable(GL_LIGHTING);
-  glColor4fv(aColor.rgb);
-  glBegin(GL_LINE_LOOP);
-  glVertex3f(myCoords[0], myCoords[1], myCoords[2]);
-  glVertex3f(myCoords[3], myCoords[4], myCoords[2]);
-  glVertex3f(myCoords[3], myCoords[4], myCoords[5]);
-  glVertex3f(myCoords[0], myCoords[1], myCoords[5]);
-  glEnd();
-  glPopAttrib();
+  aVertBuffer->BindAttribute  (aCtx, Graphic3d_TOA_POS);
+  glDrawArrays(GL_LINE_LOOP, 0, aVertBuffer->GetElemsNb());
+  aVertBuffer->UnbindAttribute(aCtx, Graphic3d_TOA_POS);
+  aVertBuffer->Release (aCtx.get());
 }
 
 } // end of anonymous namespace
 
-OpenGl_Element* VUserDrawCallback(const CALL_DEF_USERDRAW * theUserDraw)
-{
-  Handle(VUserDrawObj) anIObj = (VUserDrawObj*)theUserDraw->Data;
-  if (anIObj.IsNull())
-  {
-    std::cout << "VUserDrawCallback error: null object passed, the custom scene element will not be rendered" << std::endl;
-  }
-
-  return new VUserDrawObj::Element(anIObj, theUserDraw->Bounds);
-}
-
 static Standard_Integer VUserDraw (Draw_Interpretor& di,
                                     Standard_Integer argc,
                                     const char ** argv)
@@ -236,9 +212,6 @@ static Standard_Integer VUserDraw (Draw_Interpretor& di,
   TCollection_AsciiString aName (argv[1]);
   VDisplayAISObject(aName, Handle(AIS_InteractiveObject)());
 
-  // register the custom element factory function
-  aDriver->UserDrawCallback() = VUserDrawCallback;
-
   Handle(VUserDrawObj) anIObj = new VUserDrawObj();
   VDisplayAISObject(aName, anIObj);
 
@@ -254,6 +227,7 @@ static int VFeedback (Draw_Interpretor& theDI,
                       Standard_Integer  /*theArgNb*/,
                       const char**      /*theArgVec*/)
 {
+#if !defined(GL_ES_VERSION_2_0)
   // get the active view
   Handle(V3d_View) aView = ViewerTest::CurrentView();
   if (aView.IsNull())
@@ -395,6 +369,11 @@ static int VFeedback (Draw_Interpretor& theDI,
           << "Buffer size GL_3D_COLOR: " << aLen3D_rgba * double(sizeof(GLfloat)) / double(1024 * 1024) << " MiB\n";
     return 0;
   }
+#else
+  (void )theDI;
+  std::cout << "Command is unsupported on current platform.\n";
+  return 1;
+#endif
 }
 
 //==============================================================================
@@ -428,11 +407,25 @@ static int VImmediateFront (Draw_Interpretor& /*theDI*/,
     return 1;
   }
 
-  Graphic3d_CView* aCView = (Graphic3d_CView* )(ViewerTest::CurrentView()->View()->CView());
-  aDriver->SetImmediateModeDrawToFront (*aCView, atoi(theArgVec[1]) != 0);
+  ViewerTest::CurrentView()->View()->SetImmediateModeDrawToFront (atoi(theArgVec[1]) != 0);
+
   return 0;
 }
 
+//! Search the info from the key.
+inline TCollection_AsciiString searchInfo (const TColStd_IndexedDataMapOfStringString& theDict,
+                                           const TCollection_AsciiString& theKey)
+{
+  for (TColStd_IndexedDataMapOfStringString::Iterator anIter (theDict); anIter.More(); anIter.Next())
+  {
+    if (TCollection_AsciiString::IsSameString (anIter.Key(), theKey, Standard_False))
+    {
+      return anIter.Value();
+    }
+  }
+  return TCollection_AsciiString();
+}
+
 //==============================================================================
 //function : VGlInfo
 //purpose  :
@@ -450,53 +443,76 @@ static int VGlInfo (Draw_Interpretor& theDI,
     return 1;
   }
 
-  if (theArgNb <= 1)
+  Standard_Integer anArgIter = 1;
+  Graphic3d_DiagnosticInfo anInfoLevel = Graphic3d_DiagnosticInfo_Basic;
+  if (theArgNb == 2)
   {
-    Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aView->View()->GraphicDriver());
-    if (aDriver.IsNull())
+    TCollection_AsciiString aName (theArgVec[1]);
+    aName.LowerCase();
+    if (aName == "-short")
     {
-      std::cerr << "Error: view does not use OpenGL.\n";
-      return 1;
+      ++anArgIter;
+      anInfoLevel = Graphic3d_DiagnosticInfo_Short;
     }
-    Handle(OpenGl_Context) aCtx = aDriver->GetSharedContext();
-    Standard_CString aDebugInfo = !aCtx.IsNull() && aCtx->IsDebugContext()
-                                ? "  GLdebug     =  ON\n"
-                                : "";
+    else if (aName == "-basic")
+    {
+      ++anArgIter;
+      anInfoLevel = Graphic3d_DiagnosticInfo_Basic;
+    }
+    else if (aName == "-complete"
+          || aName == "-full")
+    {
+      ++anArgIter;
+      anInfoLevel = Graphic3d_DiagnosticInfo_Complete;
+    }
+  }
+
+  TColStd_IndexedDataMapOfStringString aDict;
+  if (anArgIter >= theArgNb)
+  {
+    aView->DiagnosticInformation (aDict, anInfoLevel);
+    TCollection_AsciiString aText;
+    for (TColStd_IndexedDataMapOfStringString::Iterator aValueIter (aDict); aValueIter.More(); aValueIter.Next())
+    {
+      if (!aText.IsEmpty())
+      {
+        aText += "\n";
+      }
+      aText += TCollection_AsciiString("  ") + aValueIter.Key() + ": " + aValueIter.Value();
+    }
+
     theDI << "OpenGL info:\n"
-          << "  GLvendor    = '" << (const char* )glGetString(GL_VENDOR)   << "'\n"
-          << "  GLdevice    = '" << (const char* )glGetString(GL_RENDERER) << "'\n"
-          << "  GLversion   = '" << (const char* )glGetString(GL_VERSION)  << "'\n"
-          << "  GLSLversion = '" << (const char* )glGetString(GL_SHADING_LANGUAGE_VERSION) << "'\n"
-          << aDebugInfo;
+          << aText;
     return 0;
   }
 
   const Standard_Boolean isList = theArgNb >= 3;
-  for (Standard_Integer anIter = 1; anIter < theArgNb; ++anIter)
+  aView->DiagnosticInformation (aDict, Graphic3d_DiagnosticInfo_Complete);
+  for (; anArgIter < theArgNb; ++anArgIter)
   {
-    TCollection_AsciiString aName (theArgVec[anIter]);
+    TCollection_AsciiString aName (theArgVec[anArgIter]);
     aName.UpperCase();
-    const char* aValue = NULL;
+    TCollection_AsciiString aValue;
     if (aName.Search ("VENDOR") != -1)
     {
-      aValue = (const char* )glGetString (GL_VENDOR);
+      aValue = searchInfo (aDict, "GLvendor");
     }
     else if (aName.Search ("RENDERER") != -1)
     {
-      aValue = (const char* )glGetString (GL_RENDERER);
+      aValue = searchInfo (aDict, "GLdevice");
     }
     else if (aName.Search ("SHADING_LANGUAGE_VERSION") != -1
           || aName.Search ("GLSL") != -1)
     {
-      aValue = (const char* )glGetString (GL_SHADING_LANGUAGE_VERSION);
+      aValue = searchInfo (aDict, "GLSLversion");
     }
     else if (aName.Search ("VERSION") != -1)
     {
-      aValue = (const char* )glGetString (GL_VERSION);
+      aValue = searchInfo (aDict, "GLversion");
     }
     else if (aName.Search ("EXTENSIONS") != -1)
     {
-      aValue = (const char* )glGetString (GL_EXTENSIONS);
+      aValue = searchInfo (aDict, "GLextensions");
     }
     else
     {
@@ -517,104 +533,813 @@ static int VGlInfo (Draw_Interpretor& theDI,
   return 0;
 }
 
+//! Parse shader type argument.
+static bool parseShaderTypeArg (Graphic3d_TypeOfShaderObject& theType,
+                                const TCollection_AsciiString& theArg)
+{
+  if (theArg == "-vertex"
+   || theArg == "-vert")
+  {
+    theType = Graphic3d_TOS_VERTEX;
+  }
+  else if (theArg == "-tessevaluation"
+        || theArg == "-tesseval"
+        || theArg == "-evaluation"
+        || theArg == "-eval")
+  {
+    theType = Graphic3d_TOS_TESS_EVALUATION;
+  }
+  else if (theArg == "-tesscontrol"
+        || theArg == "-tessctrl"
+        || theArg == "-control"
+        || theArg == "-ctrl")
+  {
+    theType = Graphic3d_TOS_TESS_CONTROL;
+  }
+  else if (theArg == "-geometry"
+        || theArg == "-geom")
+  {
+    theType = Graphic3d_TOS_GEOMETRY;
+  }
+  else if (theArg == "-fragment"
+        || theArg == "-frag")
+  {
+    theType = Graphic3d_TOS_FRAGMENT;
+  }
+  else if (theArg == "-compute"
+        || theArg == "-comp")
+  {
+    theType = Graphic3d_TOS_COMPUTE;
+  }
+  else
+  {
+    return false;
+  }
+  return true;
+}
 
 //==============================================================================
 //function : VShaderProg
 //purpose  : Sets the pair of vertex and fragment shaders for the object
 //==============================================================================
-static Standard_Integer VShaderProg (Draw_Interpretor& /*theDI*/,
+static Standard_Integer VShaderProg (Draw_Interpretor& theDI,
                                      Standard_Integer  theArgNb,
                                      const char**      theArgVec)
 {
   Handle(AIS_InteractiveContext) aCtx = ViewerTest::GetAISContext();
   if (aCtx.IsNull())
   {
-    std::cerr << "Use 'vinit' command before " << theArgVec[0] << "\n";
+    std::cout << "Error: no active view.\n";
     return 1;
   }
   else if (theArgNb < 2)
   {
-    std::cerr << theArgVec[0] << " syntax error: lack of arguments\n";
+    std::cout << "Syntax error: lack of arguments\n";
     return 1;
   }
 
-  TCollection_AsciiString aLastArg (theArgVec[theArgNb - 1]);
-  aLastArg.UpperCase();
-  const Standard_Boolean toTurnOff = aLastArg == "OFF";
-  Standard_Integer       anArgsNb  = theArgNb - 1;
-  Handle(Graphic3d_ShaderProgram) aProgram;
-  if (!toTurnOff
-   && aLastArg == "PHONG")
+  bool isExplicitShaderType = false;
+  Handle(Graphic3d_ShaderProgram) aProgram = new Graphic3d_ShaderProgram();
+  NCollection_Sequence<Handle(AIS_InteractiveObject)> aPrsList;
+  Graphic3d_GroupAspect aGroupAspect = Graphic3d_ASPECT_FILL_AREA;
+  bool isSetGroupAspect = false;
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
   {
-    aProgram = new Graphic3d_ShaderProgram (Graphic3d_ShaderProgram::ShaderName_Phong);
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    Graphic3d_TypeOfShaderObject aShaderTypeArg = Graphic3d_TypeOfShaderObject(-1);
+    if (!aProgram.IsNull()
+      && anArg == "-uniform"
+      && anArgIter + 2 < theArgNb)
+    {
+      TCollection_AsciiString aName = theArgVec[++anArgIter];
+      aProgram->PushVariableFloat (aName, float (Draw::Atof (theArgVec[++anArgIter])));
+    }
+    else if (anArg == "-list"
+          || ((anArg == "-update"
+            || anArg == "-dump"
+            || anArg == "-debug"
+            || anArg == "-reload"
+            || anArg == "-load")
+           && anArgIter + 1 < theArgNb))
+    {
+      Handle(OpenGl_Context) aGlCtx;
+      if (Handle(OpenGl_GraphicDriver) aDriver = Handle(OpenGl_GraphicDriver)::DownCast (aCtx->CurrentViewer()->Driver()))
+      {
+        aGlCtx = aDriver->GetSharedContext();
+      }
+      if (aGlCtx.IsNull())
+      {
+        std::cout << "Error: no OpenGl_Context\n";
+        return 1;
+      }
+
+      if (anArg == "-list")
+      {
+        for (OpenGl_Context::OpenGl_ResourcesMap::Iterator aResIter (aGlCtx->SharedResources()); aResIter.More(); aResIter.Next())
+        {
+          if (Handle(OpenGl_ShaderProgram) aResProg = Handle(OpenGl_ShaderProgram)::DownCast (aResIter.Value()))
+          {
+            theDI << aResProg->ResourceId() << " ";
+          }
+        }
+      }
+      else
+      {
+        TCollection_AsciiString aShaderName = theArgVec[++anArgIter];
+        Handle(OpenGl_ShaderProgram) aResProg;
+        if (!aGlCtx->GetResource (aShaderName, aResProg))
+        {
+          std::cout << "Syntax error: shader resource '" << aShaderName << "' is not found\n";
+          return 1;
+        }
+        if (aResProg->UpdateDebugDump (aGlCtx, "", false, anArg == "-dump"))
+        {
+          aCtx->UpdateCurrentViewer();
+        }
+      }
+      if (anArgIter + 1 < theArgNb)
+      {
+        std::cout << "Syntax error: wrong number of arguments\n";
+        return 1;
+      }
+      return 0;
+    }
+    else if (!aProgram.IsNull()
+          &&  aProgram->ShaderObjects().IsEmpty()
+          && (anArg == "-off"
+           || anArg ==  "off"))
+    {
+      aProgram.Nullify();
+    }
+    else if (!aProgram.IsNull()
+          &&  aProgram->ShaderObjects().IsEmpty()
+          && (anArg == "-phong"
+           || anArg ==  "phong"))
+    {
+      const TCollection_AsciiString& aShadersRoot = Graphic3d_ShaderProgram::ShadersFolder();
+      if (aShadersRoot.IsEmpty())
+      {
+        std::cout << "Error: both environment variables CSF_ShadersDirectory and CASROOT are undefined!\n"
+                     "At least one should be defined to load Phong program.\n";
+        return 1;
+      }
+
+      const TCollection_AsciiString aSrcVert = aShadersRoot + "/PhongShading.vs";
+      const TCollection_AsciiString aSrcFrag = aShadersRoot + "/PhongShading.fs";
+      if (!aSrcVert.IsEmpty()
+       && !OSD_File (aSrcVert).Exists())
+      {
+        std::cout << "Error: PhongShading.vs is not found\n";
+        return 1;
+      }
+      if (!aSrcFrag.IsEmpty()
+       && !OSD_File (aSrcFrag).Exists())
+      {
+        std::cout << "Error: PhongShading.fs is not found\n";
+        return 1;
+      }
+
+      aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_VERTEX,   aSrcVert));
+      aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_FRAGMENT, aSrcFrag));
+    }
+    else if (aPrsList.IsEmpty()
+          && anArg == "*")
+    {
+      //
+    }
+    else if (!isSetGroupAspect
+          &&  anArgIter + 1 < theArgNb
+          && (anArg == "-primtype"
+           || anArg == "-primitivetype"
+           || anArg == "-groupaspect"
+           || anArg == "-aspecttype"
+           || anArg == "-aspect"))
+    {
+      isSetGroupAspect = true;
+      TCollection_AsciiString aPrimTypeStr (theArgVec[++anArgIter]);
+      aPrimTypeStr.LowerCase();
+      if (aPrimTypeStr == "line")
+      {
+        aGroupAspect = Graphic3d_ASPECT_LINE;
+      }
+      else if (aPrimTypeStr == "tris"
+            || aPrimTypeStr == "triangles"
+            || aPrimTypeStr == "fill"
+            || aPrimTypeStr == "fillarea"
+            || aPrimTypeStr == "shading"
+            || aPrimTypeStr == "shade")
+      {
+        aGroupAspect = Graphic3d_ASPECT_FILL_AREA;
+      }
+      else if (aPrimTypeStr == "text")
+      {
+        aGroupAspect = Graphic3d_ASPECT_TEXT;
+      }
+      else if (aPrimTypeStr == "marker"
+            || aPrimTypeStr == "point"
+            || aPrimTypeStr == "pnt")
+      {
+        aGroupAspect = Graphic3d_ASPECT_MARKER;
+      }
+      else
+      {
+        std::cerr << "Syntax error at '" << aPrimTypeStr << "'\n";
+        return 1;
+      }
+    }
+    else if (anArgIter + 1 < theArgNb
+         && !aProgram.IsNull()
+         &&  aProgram->Header().IsEmpty()
+         &&  (anArg == "-version"
+           || anArg == "-glslversion"
+           || anArg == "-header"
+           || anArg == "-glslheader"))
+    {
+      TCollection_AsciiString aHeader (theArgVec[++anArgIter]);
+      if (aHeader.IsIntegerValue())
+      {
+        aHeader = TCollection_AsciiString ("#version ") + aHeader;
+      }
+      aProgram->SetHeader (aHeader);
+    }
+    else if (!anArg.StartsWith ("-")
+          && GetMapOfAIS().IsBound2 (theArgVec[anArgIter]))
+    {
+      Handle(AIS_InteractiveObject) anIO = GetMapOfAIS().Find2 (theArgVec[anArgIter]);
+      if (anIO.IsNull())
+      {
+        std::cerr << "Syntax error: " << theArgVec[anArgIter] << " is not an AIS object\n";
+        return 1;
+      }
+      aPrsList.Append (anIO);
+    }
+    else if (!aProgram.IsNull()
+           && ((anArgIter + 1 < theArgNb && parseShaderTypeArg (aShaderTypeArg, anArg))
+            || (!isExplicitShaderType && aProgram->ShaderObjects().Size() < 2)))
+    {
+      TCollection_AsciiString aShaderPath (theArgVec[anArgIter]);
+      if (aShaderTypeArg != Graphic3d_TypeOfShaderObject(-1))
+      {
+        aShaderPath = (theArgVec[++anArgIter]);
+        isExplicitShaderType = true;
+      }
+
+      const bool isSrcFile = OSD_File (aShaderPath).Exists();
+      Handle(Graphic3d_ShaderObject) aShader = isSrcFile
+                                             ? Graphic3d_ShaderObject::CreateFromFile  (Graphic3d_TOS_VERTEX, aShaderPath)
+                                             : Graphic3d_ShaderObject::CreateFromSource(Graphic3d_TOS_VERTEX, aShaderPath);
+      const TCollection_AsciiString& aShaderSrc = aShader->Source();
+
+      const bool hasVertPos   = aShaderSrc.Search ("gl_Position")  != -1;
+      const bool hasFragColor = aShaderSrc.Search ("occSetFragColor") != -1
+                             || aShaderSrc.Search ("occFragColor") != -1
+                             || aShaderSrc.Search ("gl_FragColor") != -1
+                             || aShaderSrc.Search ("gl_FragData")  != -1;
+      Graphic3d_TypeOfShaderObject aShaderType = aShaderTypeArg;
+      if (aShaderType == Graphic3d_TypeOfShaderObject(-1))
+      {
+        if (hasVertPos
+        && !hasFragColor)
+        {
+          aShaderType = Graphic3d_TOS_VERTEX;
+        }
+        if (hasFragColor
+        && !hasVertPos)
+        {
+          aShaderType = Graphic3d_TOS_FRAGMENT;
+        }
+      }
+      if (aShaderType == Graphic3d_TypeOfShaderObject(-1))
+      {
+        std::cerr << "Error: non-existing or invalid shader source\n";
+        return 1;
+      }
+
+      aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromSource (aShaderType, aShaderSrc));
+    }
+    else
+    {
+      std::cerr << "Syntax error at '" << anArg << "'\n";
+      return 1;
+    }
   }
-  if (!toTurnOff
-   && aProgram.IsNull())
+
+  if (!aProgram.IsNull()
+    && ViewerTest::CurrentView()->RenderingParams().TransparencyMethod == Graphic3d_RTM_BLEND_OIT)
+  {
+    aProgram->SetNbFragmentOutputs (2);
+    aProgram->SetWeightOitOutput (true);
+  }
+
+  ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName aGlobalPrsIter (GetMapOfAIS());
+  NCollection_Sequence<Handle(AIS_InteractiveObject)>::Iterator aPrsIter (aPrsList);
+  const bool isGlobalList = aPrsList.IsEmpty();
+  for (;;)
   {
-    if (theArgNb < 3)
+    Handle(AIS_InteractiveObject) anIO;
+    if (isGlobalList)
     {
-      std::cerr << theArgVec[0] << " syntax error: lack of arguments\n";
-      return 1;
+      if (!aGlobalPrsIter.More())
+      {
+        break;
+      }
+      anIO = aGlobalPrsIter.Key1();
+      aGlobalPrsIter.Next();
+      if (anIO.IsNull())
+      {
+        continue;
+      }
+    }
+    else
+    {
+      if (!aPrsIter.More())
+      {
+        break;
+      }
+      anIO = aPrsIter.Value();
+      aPrsIter.Next();
     }
 
-    const TCollection_AsciiString aSrcVert = theArgVec[theArgNb - 2];
-    const TCollection_AsciiString aSrcFrag = theArgVec[theArgNb - 1];
-    if (!aSrcVert.IsEmpty()
-     && !OSD_File (aSrcVert).Exists())
+    if (anIO->Attributes()->SetShaderProgram (aProgram, aGroupAspect, true))
     {
-      std::cerr << "Non-existing vertex shader source\n";
-      return 1;
+      aCtx->Redisplay (anIO, Standard_False);
+    }
+    else
+    {
+      anIO->SynchronizeAspects();
+    }
+  }
+
+  aCtx->UpdateCurrentViewer();
+  return 0;
+}
+
+//! Print triplet of values.
+template<class S, class T> static S& operator<< (S& theStream, const NCollection_Vec3<T>& theVec)
+{
+  theStream << theVec[0] << " " << theVec[1] << " " << theVec[2];
+  return theStream;
+}
+
+//! Print 4 values.
+template<class S, class T> static S& operator<< (S& theStream, const NCollection_Vec4<T>& theVec)
+{
+  theStream << theVec[0] << " " << theVec[1] << " " << theVec[2] << " " << theVec[3];
+  return theStream;
+}
+
+//! Print fresnel model.
+static const char* fresnelModelString (const Graphic3d_FresnelModel theModel)
+{
+  switch (theModel)
+  {
+    case Graphic3d_FM_SCHLICK:    return "SCHLICK";
+    case Graphic3d_FM_CONSTANT:   return "CONSTANT";
+    case Graphic3d_FM_CONDUCTOR:  return "CONDUCTOR";
+    case Graphic3d_FM_DIELECTRIC: return "DIELECTRIC";
+  }
+  return "N/A";
+}
+
+//! Create a colored rectangle SVG element.
+static TCollection_AsciiString formatSvgColoredRect (const Quantity_Color& theColor)
+{
+  return TCollection_AsciiString()
+       + "<svg width='20px' height='20px'><rect width='20px' height='20px' fill='" + Quantity_Color::ColorToHex (theColor) + "' /></svg>";
+}
+
+//==============================================================================
+//function : VListMaterials
+//purpose  :
+//==============================================================================
+static Standard_Integer VListMaterials (Draw_Interpretor& theDI,
+                                        Standard_Integer  theArgNb,
+                                        const char**      theArgVec)
+{
+  TCollection_AsciiString aDumpFile;
+  NCollection_Sequence<Graphic3d_NameOfMaterial> aMatList;
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
+  {
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    Graphic3d_NameOfMaterial aMat = Graphic3d_MaterialAspect::MaterialFromName (theArgVec[anArgIter]);
+    if (aMat != Graphic3d_NOM_DEFAULT)
+    {
+      aMatList.Append (aMat);
+    }
+    else if (anArg == "*")
+    {
+      for (Standard_Integer aMatIter = 0; aMatIter < (Standard_Integer )Graphic3d_NOM_DEFAULT; ++aMatIter)
+      {
+        aMatList.Append ((Graphic3d_NameOfMaterial )aMatIter);
+      }
+    }
+    else if (aDumpFile.IsEmpty()
+          && (anArg.EndsWith (".obj")
+           || anArg.EndsWith (".mtl")
+           || anArg.EndsWith (".htm")
+           || anArg.EndsWith (".html")))
+    {
+      aDumpFile = theArgVec[anArgIter];
     }
-    if (!aSrcFrag.IsEmpty()
-     && !OSD_File (aSrcFrag).Exists())
+    else
     {
-      std::cerr << "Non-existing fragment shader source\n";
+      std::cout << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'\n";
       return 1;
     }
+  }
+  if (aMatList.IsEmpty())
+  {
+    if (aDumpFile.IsEmpty())
+    {
+      for (Standard_Integer aMatIter = 1; aMatIter <= Graphic3d_MaterialAspect::NumberOfMaterials(); ++aMatIter)
+      {
+        theDI << Graphic3d_MaterialAspect::MaterialName (aMatIter) << " ";
+      }
+      return 0;
+    }
 
-    aProgram = new Graphic3d_ShaderProgram();
-    aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_VERTEX,   aSrcVert));
-    aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_FRAGMENT, aSrcFrag));
-    anArgsNb = theArgNb - 2;
+    for (Standard_Integer aMatIter = 0; aMatIter < (Standard_Integer )Graphic3d_NOM_DEFAULT; ++aMatIter)
+    {
+      aMatList.Append ((Graphic3d_NameOfMaterial )aMatIter);
+    }
   }
 
-  Handle(AIS_InteractiveObject) anIO;
-  if (anArgsNb <= 1
-   || *theArgVec[1] == '*')
+  // geometry for dumping
+  const Graphic3d_Vec3 aBoxVerts[8] =
   {
-    for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIter (GetMapOfAIS());
-          anIter.More(); anIter.Next())
+    Graphic3d_Vec3( 1, -1, -1),
+    Graphic3d_Vec3( 1, -1,  1),
+    Graphic3d_Vec3(-1, -1,  1),
+    Graphic3d_Vec3(-1, -1, -1),
+    Graphic3d_Vec3( 1,  1, -1),
+    Graphic3d_Vec3( 1,  1,  1),
+    Graphic3d_Vec3(-1,  1,  1),
+    Graphic3d_Vec3(-1,  1, -1)
+  };
+
+  const Graphic3d_Vec4i aBoxQuads[6] =
+  {
+    Graphic3d_Vec4i (1, 2, 3, 4),
+    Graphic3d_Vec4i (5, 8, 7, 6),
+    Graphic3d_Vec4i (1, 5, 6, 2),
+    Graphic3d_Vec4i (2, 6, 7, 3),
+    Graphic3d_Vec4i (3, 7, 8, 4),
+    Graphic3d_Vec4i (5, 1, 4, 8)
+  };
+
+  std::ofstream aMatFile, anObjFile, anHtmlFile;
+  if (aDumpFile.EndsWith (".obj")
+   || aDumpFile.EndsWith (".mtl"))
+  {
+    const TCollection_AsciiString aMatFilePath  = aDumpFile.SubString (1, aDumpFile.Length() - 3) + "mtl";
+    const TCollection_AsciiString anObjFilePath = aDumpFile.SubString (1, aDumpFile.Length() - 3) + "obj";
+
+    OSD_OpenStream (aMatFile,  aMatFilePath.ToCString(),  std::ios::out | std::ios::binary);
+    if (!aMatFile.is_open())
+    {
+      std::cout << "Error: unable creating material file\n";
+      return 0;
+    }
+    if (!aDumpFile.EndsWith (".mtl"))
     {
-      anIO = Handle(AIS_InteractiveObject)::DownCast (anIter.Key1());
-      if (!anIO.IsNull())
+      OSD_OpenStream (anObjFile, anObjFilePath.ToCString(), std::ios::out | std::ios::binary);
+      if (!anObjFile.is_open())
       {
-        anIO->Attributes()->ShadingAspect()->Aspect()->SetShaderProgram (aProgram);
-        aCtx->Redisplay (anIO, Standard_False);
+        std::cout << "Error: unable creating OBJ file\n";
+        return 0;
       }
+
+      TCollection_AsciiString anMtlName, aFolder;
+      OSD_Path::FolderAndFileFromPath (aMatFilePath, aFolder, anMtlName);
+      anObjFile << "mtllib " << anMtlName << "\n";
     }
-    aCtx->UpdateCurrentViewer();
-    return 0;
+  }
+  else if (aDumpFile.EndsWith (".htm")
+        || aDumpFile.EndsWith (".html"))
+  {
+    OSD_OpenStream (anHtmlFile, aDumpFile.ToCString(), std::ios::out | std::ios::binary);
+    if (!anHtmlFile.is_open())
+    {
+      std::cout << "Error: unable creating HTML file\n";
+      return 0;
+    }
+    anHtmlFile << "<html>\n"
+                  "<head><title>OCCT Material table</title></head>\n"
+                  "<body>\n"
+                  "<table border='1'><tbody>\n"
+                  "<tr>\n"
+                  "<th rowspan='2'><div title='Material name.\n"
+                                              "See also Graphic3d_NameOfMaterial enumeration'>"
+                                   "Name</div></th>\n"
+                  "<th rowspan='2'><div title='Material type: PHYSIC or ASPECT.\n"
+                                              "ASPECT material does not define final colors, it is taken from Internal Color instead.\n"
+                                              "See also Graphic3d_TypeOfMaterial enumeration'>"
+                                   "Type</div></th>\n"
+                  "<th colspan='5'><div title='Common material definition for Phong shading model'>"
+                                   "Common</div></th>\n"
+                  "<th rowspan='2'>Transparency</th>\n"
+                  "<th rowspan='2'>Refraction Index</th>\n"
+                  "<th colspan='9'><div title='BSDF (Bidirectional Scattering Distribution Function).\n"
+                                              "Used for physically-based rendering (in path tracing engine).\n"
+                                              "BSDF is represented as weighted mixture of basic BRDFs/BTDFs (Bidirectional Reflectance (Transmittance) Distribution Functions).\n"
+                                              "See also Graphic3d_BSDF structure.'>"
+                                   "BSDF</div></th>\n"
+                  "</tr>\n"
+                  "<tr>\n"
+                  "<th>Ambient</th>\n"
+                  "<th>Diffuse</th>\n"
+                  "<th>Specular</th>\n"
+                  "<th>Emissive</th>\n"
+                  "<th>Shiness</th>\n"
+                  "<th><div title='Weight of coat specular/glossy BRDF'>"
+                       "Kc</div></th>\n"
+                  "<th><div title='Weight of base diffuse BRDF'>"
+                       "Kd</div></th>\n"
+                  "<th><div title='Weight of base specular/glossy BRDF'>"
+                       "Ks</div></th>\n"
+                  "<th><div title='Weight of base specular/glossy BTDF'>"
+                       "Kt</div></th>\n"
+                  "<th><div title='Radiance emitted by the surface'>"
+                       "Le</div></th>\n"
+                  "<th><div title='Volume scattering color/density'>"
+                       "Absorption</div></th>\n"
+                  "<th><div title='Parameters of Fresnel reflectance of coat layer'>"
+                       "FresnelCoat</div></th>\n"
+                  "<th><div title='Parameters of Fresnel reflectance of base layer'>"
+                       "FresnelBase</div></th>\n"
+                  "</tr>\n";
+  }
+  else if (!aDumpFile.IsEmpty())
+  {
+    std::cout << "Syntax error: unknown output file format\n";
+    return 1;
   }
 
-  for (Standard_Integer anArgIter = 1; anArgIter < anArgsNb; ++anArgIter)
+  Standard_Integer aMatIndex = 0, anX = 0, anY = 0;
+  for (NCollection_Sequence<Graphic3d_NameOfMaterial>::Iterator aMatIter (aMatList); aMatIter.More(); aMatIter.Next(), ++aMatIndex)
   {
-    const TCollection_AsciiString aName (theArgVec[anArgIter]);
-    if (!GetMapOfAIS().IsBound2 (aName))
+    Graphic3d_MaterialAspect aMat (aMatIter.Value());
+    const TCollection_AsciiString aMatName = aMat.StringName();
+    const Graphic3d_Vec3 anAmbient = aMat.ReflectionMode (Graphic3d_TOR_AMBIENT)
+                                   ? (Graphic3d_Vec3 )aMat.AmbientColor()  * aMat.Ambient()
+                                   : Graphic3d_Vec3 (0.0f);
+    const Graphic3d_Vec3 aDiffuse  = aMat.ReflectionMode (Graphic3d_TOR_DIFFUSE)
+                                   ? (Graphic3d_Vec3 )aMat.DiffuseColor()  * aMat.Diffuse()
+                                   : Graphic3d_Vec3 (0.0f);
+    const Graphic3d_Vec3 aSpecular = aMat.ReflectionMode (Graphic3d_TOR_SPECULAR)
+                                   ? (Graphic3d_Vec3 )aMat.SpecularColor() * aMat.Specular()
+                                   : Graphic3d_Vec3 (0.0f);
+    const Graphic3d_Vec3 anEmission = aMat.ReflectionMode (Graphic3d_TOR_EMISSION)
+                                   ? (Graphic3d_Vec3 )aMat.EmissiveColor() * aMat.Emissive()
+                                   : Graphic3d_Vec3 (0.0f);
+    const Standard_Real  aShiness  = aMat.Shininess() * 1000.0;
+    if (aMatFile.is_open())
     {
-      std::cerr << "Warning: " << aName.ToCString() << " is not displayed\n";
-      continue;
+      aMatFile << "newmtl " << aMatName << "\n";
+      aMatFile << "Ka " << anAmbient << "\n";
+      aMatFile << "Kd " << aDiffuse  << "\n";
+      aMatFile << "Ks " << aSpecular << "\n";
+      aMatFile << "Ns " << aShiness  << "\n";
+      if (aMat.Transparency() >= 0.0001)
+      {
+        aMatFile << "Tr " << aMat.Transparency() << "\n";
+      }
+      aMatFile << "\n";
     }
-    anIO = Handle(AIS_InteractiveObject)::DownCast (GetMapOfAIS().Find2 (aName));
-    if (anIO.IsNull())
+    else if (anHtmlFile.is_open())
     {
-      std::cerr << "Warning: " << aName.ToCString() << " is not an AIS object\n";
-      continue;
+      anHtmlFile << "<tr>\n";
+      anHtmlFile << "<td>" << aMat.StringName() << "</td>\n";
+      anHtmlFile << "<td>" << (aMat.MaterialType() == Graphic3d_MATERIAL_PHYSIC ? "PHYSIC" : "ASPECT")  << "</td>\n";
+      anHtmlFile << "<td>" << formatSvgColoredRect (Quantity_Color (anAmbient))  << anAmbient  << "</td>\n";
+      anHtmlFile << "<td>" << formatSvgColoredRect (Quantity_Color (aDiffuse))   << aDiffuse   << "</td>\n";
+      anHtmlFile << "<td>" << formatSvgColoredRect (Quantity_Color (aSpecular))  << aSpecular  << "</td>\n";
+      anHtmlFile << "<td>" << formatSvgColoredRect (Quantity_Color (anEmission)) << anEmission << "</td>\n";
+      anHtmlFile << "<td>" << aMat.Shininess() << "</td>\n";
+      anHtmlFile << "<td>" << aMat.Transparency() << "</td>\n";
+      anHtmlFile << "<td>" << aMat.RefractionIndex() << "</td>\n";
+      anHtmlFile << "<td>" << aMat.BSDF().Kc << "</td>\n";
+      anHtmlFile << "<td>" << aMat.BSDF().Kd << "</td>\n";
+      anHtmlFile << "<td>" << aMat.BSDF().Ks << "</td>\n";
+      anHtmlFile << "<td>" << aMat.BSDF().Kt << "</td>\n";
+      anHtmlFile << "<td>" << aMat.BSDF().Le << "</td>\n";
+      anHtmlFile << "<td>" << aMat.BSDF().Absorption << "</td>\n";
+      anHtmlFile << "<td>" << fresnelModelString (aMat.BSDF().FresnelCoat.FresnelType()) << "</td>\n";
+      anHtmlFile << "<td>" << fresnelModelString (aMat.BSDF().FresnelBase.FresnelType()) << "</td>\n";
+      anHtmlFile << "</tr>\n";
+    }
+    else
+    {
+      theDI << aMat.StringName() << "\n";
+      theDI << "  Common.Ambient:         " << anAmbient << "\n";
+      theDI << "  Common.Diffuse:         " << aDiffuse  << "\n";
+      theDI << "  Common.Specular:        " << aSpecular << "\n";
+      theDI << "  Common.Emissive:        " << anEmission << "\n";
+      theDI << "  Common.Shiness:         " << aMat.Shininess() << "\n";
+      theDI << "  Common.Transparency:    " << aMat.Transparency() << "\n";
+      theDI << "  RefractionIndex:        " << aMat.RefractionIndex() << "\n";
+      theDI << "  BSDF.Kc:                " << aMat.BSDF().Kc << "\n";
+      theDI << "  BSDF.Kd:                " << aMat.BSDF().Kd << "\n";
+      theDI << "  BSDF.Ks:                " << aMat.BSDF().Ks << "\n";
+      theDI << "  BSDF.Kt:                " << aMat.BSDF().Kt << "\n";
+      theDI << "  BSDF.Le:                " << aMat.BSDF().Le << "\n";
+      theDI << "  BSDF.Absorption:        " << aMat.BSDF().Absorption << "\n";
+      theDI << "  BSDF.FresnelCoat:       " << fresnelModelString (aMat.BSDF().FresnelCoat.FresnelType()) << "\n";
+      theDI << "  BSDF.FresnelBase:       " << fresnelModelString (aMat.BSDF().FresnelBase.FresnelType()) << "\n";
+    }
+
+    if (anObjFile.is_open())
+    {
+      anObjFile << "g " << aMatName << "\n";
+      anObjFile << "usemtl " << aMatName << "\n";
+      for (Standard_Integer aVertIter = 0; aVertIter < 8; ++aVertIter)
+      {
+        anObjFile << "v " << (aBoxVerts[aVertIter] + Graphic3d_Vec3 (3.0f * anX, -3.0f * anY, 0.0f)) << "\n";
+      }
+      anObjFile << "s off\n";
+      for (Standard_Integer aFaceIter = 0; aFaceIter < 6; ++aFaceIter)
+      {
+        anObjFile << "f " << (aBoxQuads[aFaceIter] + Graphic3d_Vec4i (8 * aMatIndex)) << "\n";
+      }
+      anObjFile << "\n";
+      if (++anX > 5)
+      {
+        anX = 0;
+        ++anY;
+      }
     }
-    anIO->Attributes()->ShadingAspect()->Aspect()->SetShaderProgram (aProgram);
-    aCtx->Redisplay (anIO, Standard_False);
   }
 
-  aCtx->UpdateCurrentViewer();
+  if (anHtmlFile.is_open())
+  {
+    anHtmlFile << "</tbody></table>\n</body>\n</html>\n";
+  }
+  return 0;
+}
+
+//==============================================================================
+//function : VListColors
+//purpose  :
+//==============================================================================
+static Standard_Integer VListColors (Draw_Interpretor& theDI,
+                                     Standard_Integer  theArgNb,
+                                     const char**      theArgVec)
+{
+  TCollection_AsciiString aDumpFile;
+  NCollection_Sequence<Quantity_NameOfColor> aColList;
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
+  {
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    anArg.LowerCase();
+    Quantity_NameOfColor aName;
+    if (Quantity_Color::ColorFromName (theArgVec[anArgIter], aName))
+    {
+      aColList.Append (aName);
+    }
+    else if (anArg == "*")
+    {
+      for (Standard_Integer aColIter = 0; aColIter <= (Standard_Integer )Quantity_NOC_WHITE; ++aColIter)
+      {
+        aColList.Append ((Quantity_NameOfColor )aColIter);
+      }
+    }
+    else if (aDumpFile.IsEmpty()
+          && (anArg.EndsWith (".htm")
+           || anArg.EndsWith (".html")))
+    {
+      aDumpFile = theArgVec[anArgIter];
+    }
+    else
+    {
+      std::cout << "Syntax error: unknown argument '" << theArgVec[anArgIter] << "'\n";
+      return 1;
+    }
+  }
+  if (aColList.IsEmpty())
+  {
+    if (aDumpFile.IsEmpty())
+    {
+      for (Standard_Integer aColIter = 0; aColIter <= (Standard_Integer )Quantity_NOC_WHITE; ++aColIter)
+      {
+        theDI << Quantity_Color::StringName (Quantity_NameOfColor (aColIter)) << " ";
+      }
+      return 0;
+    }
+
+    for (Standard_Integer aColIter = 0; aColIter <= (Standard_Integer )Quantity_NOC_WHITE; ++aColIter)
+    {
+      aColList.Append ((Quantity_NameOfColor )aColIter);
+    }
+  }
+
+  std::ofstream anHtmlFile;
+  TCollection_AsciiString aFileNameBase, aFolder;
+  if (aDumpFile.EndsWith (".htm")
+   || aDumpFile.EndsWith (".html"))
+  {
+    OSD_Path::FolderAndFileFromPath (aDumpFile, aFolder, aFileNameBase);
+    aFileNameBase = aFileNameBase.SubString (1, aFileNameBase.Length() -  (aDumpFile.EndsWith (".htm") ? 4 : 5));
+  }
+  else if (!aDumpFile.IsEmpty())
+  {
+    std::cout << "Syntax error: unknown output file format\n";
+    return 1;
+  }
+
+  Standard_Integer aMaxNameLen = 1;
+  for (NCollection_Sequence<Quantity_NameOfColor>::Iterator aColIter (aColList); aColIter.More(); aColIter.Next())
+  {
+    aMaxNameLen = Max (aMaxNameLen, TCollection_AsciiString (Quantity_Color::StringName (aColIter.Value())).Length());
+  }
+
+  V3d_ImageDumpOptions anImgParams;
+  anImgParams.Width  = 60;
+  anImgParams.Height = 30;
+  anImgParams.BufferType = Graphic3d_BT_RGB;
+  anImgParams.StereoOptions  = V3d_SDO_MONO;
+  anImgParams.ToAdjustAspect = Standard_True;
+  Handle(V3d_View) aView;
+  if (!aDumpFile.IsEmpty())
+  {
+    ViewerTest::ViewerInit (0, 0, anImgParams.Width, anImgParams.Height, "TmpDriver/TmpViewer/TmpView");
+    aView = ViewerTest::CurrentView();
+    aView->SetImmediateUpdate (false);
+    aView->SetBgGradientStyle (Aspect_GFM_NONE, false);
+  }
+
+  if (!aDumpFile.IsEmpty())
+  {
+    OSD_OpenStream (anHtmlFile, aDumpFile.ToCString(), std::ios::out | std::ios::binary);
+    if (!anHtmlFile.is_open())
+    {
+      std::cout << "Error: unable creating HTML file\n";
+      return 0;
+    }
+    anHtmlFile << "<html>\n"
+               << "<head><title>OCCT Color table</title></head>\n"
+               << "<body>\n"
+               << "<table border='1'><tbody>\n"
+               << "<tr>\n"
+               << "<th>HTML</th>\n"
+               << "<th>OCCT</th>\n"
+               << "<th>Color name</th>\n"
+               << "<th>sRGB hex</th>\n"
+               << "<th>sRGB dec</th>\n"
+               << "<th>RGB linear</th>\n"
+               << "</tr>\n";
+  }
+
+  Image_AlienPixMap anImg;
+  Standard_Integer aColIndex = 0;
+  for (NCollection_Sequence<Quantity_NameOfColor>::Iterator aColIter (aColList); aColIter.More(); aColIter.Next(), ++aColIndex)
+  {
+    Quantity_Color aCol (aColIter.Value());
+    const TCollection_AsciiString aColName  = Quantity_Color::StringName (aColIter.Value());
+    const TCollection_AsciiString anSRgbHex = Quantity_Color::ColorToHex (aCol);
+    const Graphic3d_Vec3i anSRgbInt ((Graphic3d_Vec3 )aCol * 255.0f);
+    if (anHtmlFile.is_open())
+    {
+      const TCollection_AsciiString anImgPath = aFileNameBase + "_" + aColName + ".png";
+      if (!aView.IsNull())
+      {
+        aView->SetImmediateUpdate (false);
+        aView->SetBackgroundColor (aCol);
+        if (!aView->ToPixMap (anImg, anImgParams)
+         || !anImg.Save (aFolder + anImgPath))
+        {
+          theDI << "Error: image dump failed\n";
+          return 0;
+        }
+      }
+
+      anHtmlFile << "<tr>\n";
+      anHtmlFile << "<td style='background-color:" << anSRgbHex << "'><pre>       </pre></td>\n";
+      anHtmlFile << "<td><img src='" << (!aView.IsNull() ? anImgPath : "") << "'></img></td>\n";
+      anHtmlFile << "<td style='text-align:left'>" << aColName << "</td>\n";
+      anHtmlFile << "<td style='text-align:left'><pre>" << anSRgbHex << "</pre></td>\n";
+      anHtmlFile << "<td style='text-align:left'>(" << anSRgbInt.r() << " " << anSRgbInt.g() << " " << anSRgbInt.b() << ")</td>\n";
+      anHtmlFile << "<td style='text-align:left'>(" << aCol.Red() << " " << aCol.Green() << " " << aCol.Blue() << ")</td>\n";
+      anHtmlFile << "</tr>\n";
+    }
+    else
+    {
+      TCollection_AsciiString aColNameLong (aColName);
+      aColNameLong.RightJustify (aMaxNameLen, ' ');
+      theDI << aColNameLong << " [" << anSRgbHex << "]: " << aCol.Red() << " " << aCol.Green() << " " << aCol.Blue() << "\n";
+    }
+  }
+
+  if (!aView.IsNull())
+  {
+    ViewerTest::RemoveView (aView);
+  }
+
+  if (anHtmlFile.is_open())
+  {
+    anHtmlFile << "</tbody></table>\n</body>\n</html>\n";
+  }
   return 0;
 }
 
@@ -637,13 +1362,36 @@ void ViewerTest::OpenGlCommands(Draw_Interpretor& theCommands)
     "vimmediatefront : render immediate mode to front buffer or to back buffer",
     __FILE__, VImmediateFront, aGroup);
   theCommands.Add("vglinfo",
-    "vglinfo [GL_VENDOR] [GL_RENDERER] [GL_VERSION] [GL_SHADING_LANGUAGE_VERSION] [GL_EXTENSIONS]"
-    " : prints GL info",
+                "vglinfo [-short|-basic|-complete]"
+        "\n\t\t:         [GL_VENDOR] [GL_RENDERER] [GL_VERSION]"
+        "\n\t\t:         [GL_SHADING_LANGUAGE_VERSION] [GL_EXTENSIONS]"
+        "\n\t\t: print OpenGL info",
     __FILE__, VGlInfo, aGroup);
-  theCommands.Add("vshaderprog",
-            "   'vshaderprog [name] pathToVertexShader pathToFragmentShader'"
-    "\n\t\t: or 'vshaderprog [name] off'   to disable GLSL program"
-    "\n\t\t: or 'vshaderprog [name] phong' to enable per-pixel lighting calculations"
-    "\n\t\t: * might be used to specify all displayed objects",
+  theCommands.Add("vshader",
+                  "vshader name -vert VertexShader -frag FragmentShader [-geom GeometryShader]"
+                  "\n\t\t:   [-off] [-phong] [-aspect {shading|line|point|text}=shading]"
+                  "\n\t\t:   [-header VersionHeader]"
+                  "\n\t\t:   [-tessControl TessControlShader -tesseval TessEvaluationShader]"
+                  "\n\t\t:   [-uniform Name FloatValue]"
+                  "\n\t\t: Assign custom GLSL program to presentation aspects."
+                  "\nvshader [-list] [-dump] [-reload] ShaderId"
+                  "\n\t\t:  -list   prints the list of registered GLSL programs"
+                  "\n\t\t:  -dump   dumps specified GLSL program (for debugging)"
+                  "\n\t\t:  -reload restores dump of specified GLSL program",
     __FILE__, VShaderProg, aGroup);
+  theCommands.Add("vshaderprog", "Alias for vshader", __FILE__, VShaderProg, aGroup);
+  theCommands.Add("vlistmaterials",
+                  "vlistmaterials [*] [MaterialName1 [MaterialName2 [...]]] [dump.obj|dump.html]"
+                  "\n\t\t: Without arguments, command prints the list of standard materials."
+                  "\n\t\t: Otherwise, properties of specified materials will be printed"
+                  "\n\t\t: or dumped into specified file."
+                  "\n\t\t: * can be used to refer to complete list of standard materials.",
+                  __FILE__, VListMaterials, aGroup);
+  theCommands.Add("vlistcolors",
+                  "vlistcolors [*] [ColorName1 [ColorName2 [...]]] [dump.html]"
+                  "\n\t\t: Without arguments, command prints the list of standard colors."
+                  "\n\t\t: Otherwise, properties of specified colors will be printed"
+                  "\n\t\t: or dumped into specified file."
+                  "\n\t\t: * can be used to refer to complete list of standard colors.",
+                  __FILE__, VListColors, aGroup);
 }