0024250: TKOpenGl - per-pixel lighting using GLSL program (Phong shading)
authorkgv <kgv@opencascade.com>
Fri, 1 Nov 2013 09:52:19 +0000 (13:52 +0400)
committerbugmaster <bugmaster@opencascade.com>
Fri, 1 Nov 2013 10:05:56 +0000 (14:05 +0400)
33 files changed:
src/Graphic3d/Graphic3d_ShaderProgram.cxx
src/Graphic3d/Graphic3d_ShaderProgram.hxx
src/Graphic3d/Graphic3d_TextureRoot.cxx
src/OpenGl/OpenGl_AspectFace.cxx
src/OpenGl/OpenGl_AspectLine.cxx
src/OpenGl/OpenGl_AspectMarker.cxx
src/OpenGl/OpenGl_AspectText.cxx
src/OpenGl/OpenGl_CappingAlgo.cxx
src/OpenGl/OpenGl_Caps.cxx
src/OpenGl/OpenGl_Caps.hxx
src/OpenGl/OpenGl_Context.cxx
src/OpenGl/OpenGl_GraphicDriver.hxx
src/OpenGl/OpenGl_GraphicDriver_7.cxx
src/OpenGl/OpenGl_ShaderManager.cxx
src/OpenGl/OpenGl_ShaderManager.hxx
src/OpenGl/OpenGl_ShaderProgram.cxx
src/OpenGl/OpenGl_ShaderProgram.hxx
src/OpenGl/OpenGl_View.cxx
src/OpenGl/OpenGl_View.hxx
src/OpenGl/OpenGl_View_2.cxx
src/OpenGl/OpenGl_Workspace_5.cxx
src/Shaders/PhongShading.fs [new file with mode: 0644]
src/Shaders/PhongShading.vs [new file with mode: 0644]
src/ViewerTest/ViewerTest.cxx
src/ViewerTest/ViewerTest_OpenGlCommands.cxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx
tests/v3d/begin
tests/v3d/end
tests/v3d/glsl/phong_box [new file with mode: 0644]
tests/v3d/glsl/phong_couple [new file with mode: 0644]
tests/v3d/glsl/phong_fuse [new file with mode: 0644]
tests/v3d/glsl/phong_views [new file with mode: 0644]
tests/v3d/grids.list

index 29aa9c7..64e6eb9 100644 (file)
 #include <Graphic3d_GraphicDriver.hxx>
 #include <Graphic3d_ShaderObject.hxx>
 #include <Graphic3d_ShaderProgram.hxx>
+#include <OSD_Directory.hxx>
+#include <OSD_Environment.hxx>
+#include <OSD_File.hxx>
+#include <OSD_Path.hxx>
 
 namespace
 {
@@ -33,6 +37,52 @@ IMPLEMENT_STANDARD_HANDLE (Graphic3d_ShaderProgram, Standard_Transient)
 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ShaderProgram, Standard_Transient)
 
 // =======================================================================
+// function : ShadersFolder
+// purpose  :
+// =======================================================================
+const TCollection_AsciiString& Graphic3d_ShaderProgram::ShadersFolder()
+{
+  static Standard_Boolean        THE_IS_DEFINED = Standard_False;
+  static TCollection_AsciiString THE_SHADERS_FOLDER;
+  if (!THE_IS_DEFINED)
+  {
+    THE_IS_DEFINED = Standard_True;
+    OSD_Environment aDirEnv ("CSF_ShadersDirectory");
+    THE_SHADERS_FOLDER = aDirEnv.Value();
+    if (THE_SHADERS_FOLDER.IsEmpty())
+    {
+      OSD_Environment aCasRootEnv ("CASROOT");
+      THE_SHADERS_FOLDER = aCasRootEnv.Value();
+      if (!THE_SHADERS_FOLDER.IsEmpty())
+      {
+        THE_SHADERS_FOLDER += "/src/Shaders";
+      }
+    }
+
+    if (THE_SHADERS_FOLDER.IsEmpty())
+    {
+      std::cerr << "Both environment variables CSF_ShadersDirectory and CASROOT are undefined!\n"
+                << "At least one should be defined to use standard GLSL programs.\n";
+      Standard_Failure::Raise ("CSF_ShadersDirectory and CASROOT are undefined");
+      return THE_SHADERS_FOLDER;
+    }
+
+    const OSD_Path aDirPath (THE_SHADERS_FOLDER);
+    OSD_Directory aDir (aDirPath);
+    const TCollection_AsciiString aProgram = THE_SHADERS_FOLDER + "/Declarations.glsl";
+    OSD_File aProgramFile (aProgram);
+    if (!aDir.Exists()
+     || !aProgramFile.Exists())
+    {
+      std::cerr << "Standard GLSL programs are not found in: " << THE_SHADERS_FOLDER.ToCString() << std::endl;
+      Standard_Failure::Raise ("CSF_ShadersDirectory or CASROOT is set incorrectly");
+      return THE_SHADERS_FOLDER;
+    }
+  }
+  return THE_SHADERS_FOLDER;
+}
+
+// =======================================================================
 // function : Graphic3d_ShaderProgram
 // purpose  : Creates new empty program object
 // =======================================================================
@@ -43,6 +93,47 @@ Graphic3d_ShaderProgram::Graphic3d_ShaderProgram()
 }
 
 // =======================================================================
+// function : Graphic3d_ShaderProgram
+// purpose  :
+// =======================================================================
+Graphic3d_ShaderProgram::Graphic3d_ShaderProgram (const Graphic3d_ShaderProgram::ShaderName theName)
+{
+  const TCollection_AsciiString& aShadersRoot = Graphic3d_ShaderProgram::ShadersFolder();
+  switch (theName)
+  {
+    case ShaderName_Phong:
+    {
+      myID = TCollection_AsciiString ("Graphic3d_ShaderProgram_Phong");
+      const TCollection_AsciiString aSrcVert = aShadersRoot + "/PhongShading.vs";
+      const TCollection_AsciiString aSrcFrag = aShadersRoot + "/PhongShading.fs";
+
+      if (!aSrcVert.IsEmpty()
+       && !OSD_File (aSrcVert).Exists())
+      {
+        Standard_Failure::Raise ("Graphic3d_ShaderProgram, PhongShading.vs is not found");
+        return;
+      }
+      if (!aSrcFrag.IsEmpty()
+       && !OSD_File (aSrcFrag).Exists())
+      {
+        Standard_Failure::Raise ("Graphic3d_ShaderProgram, PhongShading.fs is not found");
+        return;
+      }
+
+      AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_VERTEX,   aSrcVert));
+      AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_FRAGMENT, aSrcFrag));
+      break;
+    }
+    case ShaderName_UNKNOWN:
+    default:
+    {
+      Standard_Failure::Raise ("Graphic3d_ShaderProgram, unknown program name");
+      break;
+    }
+  }
+}
+
+// =======================================================================
 // function : ~Graphic3d_ShaderProgram
 // purpose  : Releases resources of program object
 // =======================================================================
index ac816f5..938ab35 100644 (file)
@@ -34,11 +34,25 @@ typedef NCollection_Sequence<Handle(Graphic3d_ShaderVariable)> Graphic3d_ShaderV
 //! This class is responsible for managing shader programs.
 class Graphic3d_ShaderProgram : public Standard_Transient
 {
+
+public:
+
+  //! The list of built-in GLSL programs
+  enum ShaderName
+  {
+    ShaderName_UNKNOWN, //!< undefined program
+    ShaderName_Phong    //!< per-pixel lighting (Phong shading)
+  };
+
 public:
 
   //! Creates new empty program object.
   Standard_EXPORT Graphic3d_ShaderProgram();
 
+  //! Creates program object from pre-defined shaders.
+  //! Raises Standard_Failure exception if shader resources are unavailable.
+  Standard_EXPORT Graphic3d_ShaderProgram (const Graphic3d_ShaderProgram::ShaderName theName);
+
   //! Releases resources of program object.
   Standard_EXPORT virtual ~Graphic3d_ShaderProgram();
 
@@ -73,6 +87,12 @@ public:
 
 public:
 
+  //! The path to GLSL programs determined from CSF_ShadersDirectory or CASROOT environment variables.
+  //! @return the root folder with default GLSL programs.
+  Standard_EXPORT static const TCollection_AsciiString& ShadersFolder();
+
+public:
+
   DEFINE_STANDARD_RTTI (Graphic3d_ShaderProgram)
 
 private:
index a599e09..f5bb528 100755 (executable)
@@ -60,9 +60,9 @@ TCollection_AsciiString Graphic3d_TextureRoot::TexturesFolder()
 
     if (VarName.IsEmpty())
     {
-      std::cerr << " CSF_MDTVTexturesDirectory and CASROOT not setted\n";
-      std::cerr << " one of these variable are mandatory to use this functionality\n";
-      Standard_Failure::Raise ("CSF_MDTVTexturesDirectory and CASROOT not setted");
+      std::cerr << "Both environment variables CSF_MDTVTexturesDirectory and CASROOT are undefined!\n"
+                << "At least one should be defined to use standard Textures.\n";
+      Standard_Failure::Raise ("CSF_MDTVTexturesDirectory and CASROOT are undefined");
       return VarName;
     }
 
index a9a7483..f7f9a79 100644 (file)
@@ -224,7 +224,6 @@ void OpenGl_AspectFace::SetAspect (const CALL_DEF_CONTEXTFILLAREA& theAspect)
   myTexture = theAspect.Texture.TextureMap;
 
   const TCollection_AsciiString& aTextureKey = myTexture.IsNull() ? THE_EMPTY_KEY : myTexture->GetId();
-
   if (aTextureKey.IsEmpty() || myResources.TextureId != aTextureKey)
   {
     myResources.ResetTexture();
@@ -234,7 +233,6 @@ void OpenGl_AspectFace::SetAspect (const CALL_DEF_CONTEXTFILLAREA& theAspect)
   myShaderProgram = theAspect.ShaderProgram;
 
   const TCollection_AsciiString& aShaderKey = myShaderProgram.IsNull() ? THE_EMPTY_KEY : myShaderProgram->GetId();
-
   if (aShaderKey.IsEmpty() || myResources.ShaderProgramId != aShaderKey)
   {
     myResources.ResetShader();
@@ -415,9 +413,11 @@ void OpenGl_AspectFace::Release (const Handle(OpenGl_Context)& theContext)
   myResources.TextureId.Clear();
   myResources.ResetTexture();
 
-  if (!myResources.ShaderProgram.IsNull() && !theContext.IsNull())
+  if (!myResources.ShaderProgram.IsNull()
+   && !theContext.IsNull())
   {
-    theContext->ShaderManager()->Unregister (myResources.ShaderProgram);
+    theContext->ShaderManager()->Unregister (myResources.ShaderProgramId,
+                                             myResources.ShaderProgram);
   }
   myResources.ShaderProgramId.Clear();
   myResources.ResetShader();
@@ -471,35 +471,24 @@ void OpenGl_AspectFace::Resources::BuildTexture (const Handle(OpenGl_Workspace)&
 // function : BuildShader
 // purpose  :
 // =======================================================================
-void OpenGl_AspectFace::Resources::BuildShader (const Handle(OpenGl_Workspace)& theWS,
+void OpenGl_AspectFace::Resources::BuildShader (const Handle(OpenGl_Workspace)&        theWS,
                                                 const Handle(Graphic3d_ShaderProgram)& theShader)
 {
   const Handle(OpenGl_Context)& aContext = theWS->GetGlContext();
-
   if (!aContext->IsGlGreaterEqual (2, 0))
+  {
     return;
+  }
 
   // release old shader program resources
   if (!ShaderProgram.IsNull())
   {
-    aContext->ShaderManager()->Unregister (ShaderProgram);
+    aContext->ShaderManager()->Unregister (ShaderProgramId, ShaderProgram);
   }
-
-  ShaderProgramId = theShader.IsNull() ? THE_EMPTY_KEY : theShader->GetId();
-
-  if (!theShader.IsNull())
+  if (theShader.IsNull())
   {
-    if (!aContext->GetResource<Handle(OpenGl_ShaderProgram)> (ShaderProgramId, ShaderProgram))
-    {
-      ShaderProgram = aContext->ShaderManager()->Create (theShader);
-      if (!ShaderProgramId.IsEmpty())
-      {
-        aContext->ShareResource (ShaderProgramId, ShaderProgram);
-      }
-    }
-  }
-  else
-  {
-    ShaderProgram.Nullify();
+    return;
   }
+
+  aContext->ShaderManager()->Create (theShader, ShaderProgramId, ShaderProgram);
 }
index a347949..e5b80ba 100644 (file)
@@ -68,7 +68,6 @@ void OpenGl_AspectLine::SetAspect (const CALL_DEF_CONTEXTLINE &theAspect)
   myShaderProgram = theAspect.ShaderProgram;
 
   const TCollection_AsciiString& aShaderKey = myShaderProgram.IsNull() ? THE_EMPTY_KEY : myShaderProgram->GetId();
-
   if (aShaderKey.IsEmpty() || myResources.ShaderProgramId != aShaderKey)
   {
     myResources.ResetShader();
@@ -90,9 +89,11 @@ void OpenGl_AspectLine::Render (const Handle(OpenGl_Workspace) &theWorkspace) co
 // =======================================================================
 void OpenGl_AspectLine::Release (const Handle(OpenGl_Context)& theContext)
 {
-  if (!myResources.ShaderProgram.IsNull() && !theContext.IsNull())
+  if (!myResources.ShaderProgram.IsNull()
+   && !theContext.IsNull())
   {
-    theContext->ShaderManager()->Unregister (myResources.ShaderProgram);
+    theContext->ShaderManager()->Unregister (myResources.ShaderProgramId,
+                                             myResources.ShaderProgram);
   }
   myResources.ShaderProgramId.Clear();
   myResources.ResetShader();
@@ -102,35 +103,24 @@ void OpenGl_AspectLine::Release (const Handle(OpenGl_Context)& theContext)
 // function : BuildShader
 // purpose  :
 // =======================================================================
-void OpenGl_AspectLine::Resources::BuildShader (const Handle(OpenGl_Workspace)& theWS,
+void OpenGl_AspectLine::Resources::BuildShader (const Handle(OpenGl_Workspace)&        theWS,
                                                 const Handle(Graphic3d_ShaderProgram)& theShader)
 {
   const Handle(OpenGl_Context)& aContext = theWS->GetGlContext();
-
   if (!aContext->IsGlGreaterEqual (2, 0))
+  {
     return;
+  }
 
   // release old shader program resources
   if (!ShaderProgram.IsNull())
   {
-    aContext->ShaderManager()->Unregister (ShaderProgram);
-  }
-
-  ShaderProgramId = theShader.IsNull() ? THE_EMPTY_KEY : theShader->GetId();
-
-  if (!theShader.IsNull())
-  {
-    if (!aContext->GetResource<Handle(OpenGl_ShaderProgram)> (ShaderProgramId, ShaderProgram))
-    {
-      ShaderProgram = aContext->ShaderManager()->Create (theShader);
-      if (!ShaderProgramId.IsEmpty())
-      {
-        aContext->ShareResource (ShaderProgramId, ShaderProgram);
-      }
-    }
+    aContext->ShaderManager()->Unregister (ShaderProgramId, ShaderProgram);
   }
-  else
+  if (theShader.IsNull())
   {
-    ShaderProgram.Nullify();
+    return;
   }
+
+  aContext->ShaderManager()->Create (theShader, ShaderProgramId, ShaderProgram);
 }
index 78a077d..5dbfe52 100644 (file)
@@ -1539,7 +1539,8 @@ void OpenGl_AspectMarker::Release (const Handle(OpenGl_Context)& theCtx)
 
   if (!myResources.ShaderProgram.IsNull() && !theCtx.IsNull())
   {
-    theCtx->ShaderManager()->Unregister (myResources.ShaderProgram);
+    theCtx->ShaderManager()->Unregister (myResources.ShaderProgramId,
+                                         myResources.ShaderProgram);
   }
   myResources.ShaderProgramId.Clear();
   myResources.ResetShader();
@@ -1895,37 +1896,26 @@ void OpenGl_AspectMarker::Resources::BuildSprites (const Handle(OpenGl_Workspace
 // function : BuildShader
 // purpose  :
 // =======================================================================
-void OpenGl_AspectMarker::Resources::BuildShader (const Handle(OpenGl_Workspace)& theWS,
+void OpenGl_AspectMarker::Resources::BuildShader (const Handle(OpenGl_Workspace)&        theWS,
                                                   const Handle(Graphic3d_ShaderProgram)& theShader)
 {
   const Handle(OpenGl_Context)& aContext = theWS->GetGlContext();
-
   if (!aContext->IsGlGreaterEqual (2, 0))
+  {
     return;
+  }
 
   // release old shader program resources
   if (!ShaderProgram.IsNull())
   {
-    aContext->ShaderManager()->Unregister (ShaderProgram);
-  }
-
-  ShaderProgramId = theShader.IsNull() ? THE_EMPTY_KEY : theShader->GetId();
-
-  if (!theShader.IsNull())
-  {
-    if (!aContext->GetResource<Handle(OpenGl_ShaderProgram)> (ShaderProgramId, ShaderProgram))
-    {
-      ShaderProgram = aContext->ShaderManager()->Create (theShader);
-      if (!ShaderProgramId.IsEmpty())
-      {
-        aContext->ShareResource (ShaderProgramId, ShaderProgram);
-      }
-    }
+    aContext->ShaderManager()->Unregister (ShaderProgramId, ShaderProgram);
   }
-  else
+  if (theShader.IsNull())
   {
-    ShaderProgram.Nullify();
+    return;
   }
+
+  aContext->ShaderManager()->Create (theShader, ShaderProgramId, ShaderProgram);
 }
 
 // =======================================================================
index 482a374..046a07d 100644 (file)
@@ -107,9 +107,11 @@ void OpenGl_AspectText::Render (const Handle(OpenGl_Workspace)& theWorkspace) co
 // =======================================================================
 void OpenGl_AspectText::Release (const Handle(OpenGl_Context)& theContext)
 {
-  if (!myResources.ShaderProgram.IsNull() && !theContext.IsNull())
+  if (!myResources.ShaderProgram.IsNull()
+   && !theContext.IsNull())
   {
-    theContext->ShaderManager()->Unregister (myResources.ShaderProgram);
+    theContext->ShaderManager()->Unregister (myResources.ShaderProgramId,
+                                             myResources.ShaderProgram);
   }
   myResources.ShaderProgramId.Clear();
   myResources.ResetShader();
@@ -119,35 +121,24 @@ void OpenGl_AspectText::Release (const Handle(OpenGl_Context)& theContext)
 // function : BuildShader
 // purpose  :
 // =======================================================================
-void OpenGl_AspectText::Resources::BuildShader (const Handle(OpenGl_Workspace)& theWS,
+void OpenGl_AspectText::Resources::BuildShader (const Handle(OpenGl_Workspace)&        theWS,
                                                 const Handle(Graphic3d_ShaderProgram)& theShader)
 {
   const Handle(OpenGl_Context)& aContext = theWS->GetGlContext();
-
   if (!aContext->IsGlGreaterEqual (2, 0))
+  {
     return;
+  }
 
   // release old shader program resources
   if (!ShaderProgram.IsNull())
   {
-    aContext->ShaderManager()->Unregister (ShaderProgram);
+    aContext->ShaderManager()->Unregister (ShaderProgramId, ShaderProgram);
   }
-
-  ShaderProgramId = theShader.IsNull() ? THE_EMPTY_KEY : theShader->GetId();
-
-  if (!theShader.IsNull())
+  if (theShader.IsNull())
   {
-    if (!aContext->GetResource<Handle(OpenGl_ShaderProgram)> (ShaderProgramId, ShaderProgram))
-    {
-      ShaderProgram = aContext->ShaderManager()->Create (theShader);
-      if (!ShaderProgramId.IsEmpty())
-      {
-        aContext->ShareResource (ShaderProgramId, ShaderProgram);
-      }
-    }
-  }
-  else
-  {
-    ShaderProgram.Nullify();
+    return;
   }
+
+  aContext->ShaderManager()->Create (theShader, ShaderProgramId, ShaderProgram);
 }
index a24a879..24a994f 100644 (file)
@@ -228,7 +228,7 @@ void OpenGl_CappingAlgo::RenderPlane (const Handle(OpenGl_Workspace)& theWorkspa
   glDisableClientState (GL_VERTEX_ARRAY);
   glDisableClientState (GL_TEXTURE_COORD_ARRAY);
 
-  theWorkspace->SetStructureMatrix (aModelMatrix);
+  theWorkspace->SetStructureMatrix (aModelMatrix, true);
   theWorkspace->SetAspectFace (aFaceAspect);
 
   // set delayed resource release
index 5b57f7b..1c3ee00 100644 (file)
@@ -29,6 +29,7 @@ IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Caps, Standard_Transient)
 OpenGl_Caps::OpenGl_Caps()
 : vboDisable        (Standard_False),
   pntSpritesDisable (Standard_False),
+  keepArrayData     (Standard_False),
   contextStereo     (Standard_False),
 #ifdef DEB
   contextDebug      (Standard_True),
@@ -36,7 +37,7 @@ OpenGl_Caps::OpenGl_Caps()
   contextDebug      (Standard_False),
 #endif
   contextNoAccel    (Standard_False),
-  keepArrayData     (Standard_False)
+  glslWarnings      (Standard_False)
 {
   //
 }
@@ -49,9 +50,11 @@ OpenGl_Caps& OpenGl_Caps::operator= (const OpenGl_Caps& theCopy)
 {
   vboDisable        = theCopy.vboDisable;
   pntSpritesDisable = theCopy.pntSpritesDisable;
+  keepArrayData     = theCopy.keepArrayData;
   contextStereo     = theCopy.contextStereo;
   contextDebug      = theCopy.contextDebug;
   contextNoAccel    = theCopy.contextNoAccel;
+  glslWarnings      = theCopy.glslWarnings;
   return *this;
 }
 
index a7935bf..c6ca52c 100644 (file)
@@ -33,6 +33,7 @@ public: //! @name flags to disable particular functionality, should be used only
 
   Standard_Boolean vboDisable;        //!< flag permits VBO usage, will significantly affect performance (OFF by default)
   Standard_Boolean pntSpritesDisable; //!< flag permits Point Sprites usage, will significantly affect performance (OFF by default)
+  Standard_Boolean keepArrayData;     //!< Disables freeing CPU memory after building VBOs (OFF by default)
 
 public: //! @name context creation parameters
 
@@ -67,12 +68,10 @@ public: //! @name context creation parameters
    */
   Standard_Boolean contextNoAccel;
 
-  /**
-   * Disables freeing CPU memory after building VBOs.
-   *
-   * OFF by default.
-   */
-  Standard_Boolean keepArrayData;
+public: //! @name flags to activate verbose output
+
+  //! Print GLSL program compilation/linkage warnings, if any. OFF by default.
+  Standard_Boolean glslWarnings;
 
 public: //! @name class methods
 
index 85f7481..c321fb5 100644 (file)
@@ -135,12 +135,17 @@ OpenGl_Context::~OpenGl_Context()
   // release shared resources if any
   if (((const Handle(Standard_Transient)& )mySharedResources)->GetRefCount() <= 1)
   {
+    myShaderManager.Nullify();
     for (NCollection_DataMap<TCollection_AsciiString, Handle(OpenGl_Resource)>::Iterator anIter (*mySharedResources);
          anIter.More(); anIter.Next())
     {
       anIter.Value()->Release (this);
     }
   }
+  else
+  {
+    myShaderManager->SetContext (NULL);
+  }
   mySharedResources.Nullify();
   myDelayed.Nullify();
 
@@ -203,6 +208,7 @@ void OpenGl_Context::Share (const Handle(OpenGl_Context)& theShareCtx)
     mySharedResources = theShareCtx->mySharedResources;
     myDelayed         = theShareCtx->myDelayed;
     myReleaseQueue    = theShareCtx->myReleaseQueue;
+    myShaderManager   = theShareCtx->myShaderManager;
   }
 }
 
@@ -250,6 +256,7 @@ Standard_Boolean OpenGl_Context::MakeCurrent()
   // however some drivers (Intel etc.) may FAIL doing this for unknown reason
   if (IsCurrent())
   {
+    myShaderManager->SetContext (this);
     return Standard_True;
   }
   else if (wglMakeCurrent ((HDC )myWindowDC, (HGLRC )myGContext) != TRUE)
@@ -285,6 +292,7 @@ Standard_Boolean OpenGl_Context::MakeCurrent()
     return Standard_False;
   }
 #endif
+  myShaderManager->SetContext (this);
   return Standard_True;
 }
 
index fa7d4ae..fe53540 100644 (file)
@@ -81,6 +81,21 @@ class OpenGl_Element;
 class OpenGl_Structure;
 class OpenGl_Text;
 
+//! Tool class to implement consistent state counter
+//! for objects inside the same driver instance.
+class OpenGl_StateCounter
+{
+public:
+
+  OpenGl_StateCounter() : myCounter (0) { }
+
+  Standard_Size Increment() { return ++myCounter; }
+
+private:
+  
+  Standard_Size myCounter;
+};
+
 //! This class defines an OpenGl graphic driver <br>
 class OpenGl_GraphicDriver : public Graphic3d_GraphicDriver
 {
@@ -351,6 +366,14 @@ private:
   OpenGl_UserDrawCallback_t                                       myUserDrawCallback;
   OpenGl_Text*                                                    myTempText;         //!< variable for compatibility (drawing text in layers)
 
+public:
+
+  OpenGl_StateCounter* GetStateCounter() const { return &myStateCounter; }
+
+private:
+
+  mutable OpenGl_StateCounter myStateCounter;
+
 };
 
 #endif //_OpenGl_GraphicDriver_HeaderFile
index 68d3aaa..0e40dfe 100755 (executable)
@@ -558,7 +558,7 @@ Standard_Boolean OpenGl_GraphicDriver::View (Graphic3d_CView& theCView)
 
   Handle(OpenGl_Context)   aShareCtx = GetSharedContext();
   Handle(OpenGl_Workspace) aWS       = new OpenGl_Workspace (myGlDisplay, theCView.DefWindow, theCView.GContext, myCaps, aShareCtx);
-  Handle(OpenGl_View)      aView     = new OpenGl_View (theCView.Context);
+  Handle(OpenGl_View)      aView     = new OpenGl_View (theCView.Context, &myStateCounter);
   myMapOfWS  .Bind (theCView.WsId,   aWS);
   myMapOfView.Bind (theCView.ViewId, aView);
 
index 97b0fbb..cff325c 100644 (file)
@@ -55,35 +55,56 @@ OpenGl_ShaderManager::~OpenGl_ShaderManager()
 // function : Create
 // purpose  : Creates new shader program
 // =======================================================================
-Handle(OpenGl_ShaderProgram) OpenGl_ShaderManager::Create (const Handle(Graphic3d_ShaderProgram)& theProxyProgram)
+void OpenGl_ShaderManager::Create (const Handle(Graphic3d_ShaderProgram)& theProxy,
+                                   TCollection_AsciiString&               theShareKey,
+                                   Handle(OpenGl_ShaderProgram)&          theProgram)
 {
-  if (theProxyProgram.IsNull())
+  theProgram.Nullify();
+  if (theProxy.IsNull())
   {
-    return NULL;
+    return;
   }
-  
-  Handle(OpenGl_ShaderProgram) aProgram = new OpenGl_ShaderProgram (theProxyProgram);
-  if (!aProgram->Initialize (myContext, theProxyProgram->ShaderObjects()))
+
+  theShareKey = theProxy->GetId();
+  if (myContext->GetResource<Handle(OpenGl_ShaderProgram)> (theShareKey, theProgram))
   {
-    return NULL;
+    theProgram->Share();
+    return;
   }
-  
-  myProgramList.Append (aProgram);
 
-  return aProgram;
+  theProgram = new OpenGl_ShaderProgram (theProxy);
+  if (!theProgram->Initialize (myContext, theProxy->ShaderObjects()))
+  {
+    theProgram->Release (myContext);
+    theShareKey.Clear();
+    theProgram.Nullify();
+    return;
+  }
+
+  myProgramList.Append (theProgram);
+  myContext->ShareResource (theShareKey, theProgram);
 }
 
 // =======================================================================
 // function : Unregister
 // purpose  : Removes specified shader program from the manager
 // =======================================================================
-void OpenGl_ShaderManager::Unregister (Handle(OpenGl_ShaderProgram)& theProgram)
+void OpenGl_ShaderManager::Unregister (TCollection_AsciiString&      theShareKey,
+                                       Handle(OpenGl_ShaderProgram)& theProgram)
 {
   for (OpenGl_ShaderProgramList::Iterator anIt (myProgramList); anIt.More(); anIt.Next())
   {
     if (anIt.Value() == theProgram)
     {
+      if (!theProgram->UnShare())
+      {
+        theShareKey.Clear();
+        theProgram.Nullify();
+        return;
+      }
+
       myProgramList.Remove (anIt);
+      myMaterialStates.UnBind (theProgram);
       break;
     }
   }
index b3ddf22..1ee5e47 100644 (file)
@@ -48,11 +48,17 @@ public:
   //! Releases resources of shader manager.
   Standard_EXPORT virtual ~OpenGl_ShaderManager();
 
-  //! Creates new shader program.
-  Standard_EXPORT Handle(OpenGl_ShaderProgram) Create (const Handle(Graphic3d_ShaderProgram)& theProxyProgram = NULL);
+  //! Creates new shader program or re-use shared instance.
+  //! @param theProxy    [IN]  program definition
+  //! @param theShareKey [OUT] sharing key
+  //! @param theProgram  [OUT] OpenGL program
+  Standard_EXPORT void Create (const Handle(Graphic3d_ShaderProgram)& theProxy,
+                               TCollection_AsciiString&               theShareKey,
+                               Handle(OpenGl_ShaderProgram)&          theProgram);
 
   //! Unregisters specified shader program.
-  Standard_EXPORT void Unregister (Handle(OpenGl_ShaderProgram)& theProgram);
+  Standard_EXPORT void Unregister (TCollection_AsciiString&      theShareKey,
+                                   Handle(OpenGl_ShaderProgram)& theProgram);
 
   //! Returns list of registered shader programs.
   Standard_EXPORT const OpenGl_ShaderProgramList& ShaderPrograms() const;
@@ -155,6 +161,14 @@ public:
   //! Pushes current state of OCCT graphics parameters to specified program.
   Standard_EXPORT void PushState (const Handle(OpenGl_ShaderProgram)& theProgram) const;
 
+public:
+
+  //! Overwrites context
+  void SetContext (OpenGl_Context* theCtx)
+  {
+    myContext = theCtx;
+  }
+
 protected:
 
   OpenGl_ShaderProgramList myProgramList;  //!< The list of shader programs
index 6a6e5e1..59903d2 100644 (file)
@@ -238,7 +238,8 @@ void OpenGl_VariableSetterSelector::Set (const Handle(OpenGl_Context)&
 // =======================================================================
 OpenGl_ShaderProgram::OpenGl_ShaderProgram (const Handle(Graphic3d_ShaderProgram)& theProxy)
 : myProgramID (NO_PROGRAM),
-  myProxy     (theProxy)
+  myProxy     (theProxy),
+  myShareCount(1)
 {
   memset (myCurrentState, 0, sizeof (myCurrentState));
   for (GLint aVar = 0; aVar < OpenGl_OCCT_NUMBER_OF_STATE_VARIABLES; ++aVar)
@@ -259,31 +260,15 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  GLchar *aShaderDir = getenv ("CSF_ShadersDirectory");
-  if (aShaderDir == NULL)
-  {
-    TCollection_ExtendedString aMsg = "Error! Failed to get OCCT shaders directory";
-
-    theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
-                         GL_DEBUG_TYPE_ERROR_ARB,
-                         0,
-                         GL_DEBUG_SEVERITY_HIGH_ARB,
-                         aMsg);
-
-    return Standard_False;
-  }
-
-  OSD_File aDeclFile (TCollection_AsciiString (aShaderDir) + "/Declarations.glsl");
+  OSD_File aDeclFile (Graphic3d_ShaderProgram::ShadersFolder() + "/Declarations.glsl");
   if (!aDeclFile.Exists())
   {
-    TCollection_ExtendedString aMsg = "Error! Failed to load OCCT shader declarations file";
-
+    const TCollection_ExtendedString aMsg = "Error! Failed to load OCCT shader declarations file";
     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
                          GL_DEBUG_TYPE_ERROR_ARB,
                          0,
                          GL_DEBUG_SEVERITY_HIGH_ARB,
                          aMsg);
-
     return Standard_False;
   }
 
@@ -298,14 +283,12 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
   {
     if (!anIter.Value()->IsDone())
     {
-      TCollection_ExtendedString aMsg = "Error! Failed to get shader source";
-
+      const TCollection_ExtendedString aMsg = "Error! Failed to get shader source";
       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
                            GL_DEBUG_TYPE_ERROR_ARB,
                            0,
                            GL_DEBUG_SEVERITY_HIGH_ARB,
                            aMsg);
-
       return Standard_False;
     }
 
@@ -326,23 +309,21 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
     if (aShader.IsNull())
     {
       TCollection_ExtendedString aMsg = "Error! Unsupported shader type";
-
       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
                            GL_DEBUG_TYPE_ERROR_ARB,
                            0,
                            GL_DEBUG_SEVERITY_HIGH_ARB,
                            aMsg);
-
       return Standard_False;
     }
 
     if (!aShader->Create (theCtx))
     {
+      aShader->Release (theCtx.operator->());
       return Standard_False;
     }
 
     TCollection_AsciiString aSource = aDeclarations + anIter.Value()->Source();
-    
     if (anIter.Value()->Type() == Graphic3d_TOS_VERTEX)
     {
       aSource = TCollection_AsciiString ("#define VERTEX_SHADER\n") + aSource;
@@ -350,75 +331,82 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
 
     if (!aShader->LoadSource (theCtx, aSource))
     {
-      TCollection_ExtendedString aMsg = "Error! Failed to set shader source";
-
+      const TCollection_ExtendedString aMsg = "Error! Failed to set shader source";
       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
                            GL_DEBUG_TYPE_ERROR_ARB,
                            0,
                            GL_DEBUG_SEVERITY_HIGH_ARB,
                            aMsg);
-
+      aShader->Release (theCtx.operator->());
       return Standard_False;
     }
 
     if (!aShader->Compile (theCtx))
     {
-      TCollection_ExtendedString aMsg = "Error! Failed to compile shader object";
-
+      TCollection_AsciiString aLog;
+      aShader->FetchInfoLog (theCtx, aLog);
+      if (aLog.IsEmpty())
+      {
+        aLog = "Compilation log is empty.";
+      }
       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
                            GL_DEBUG_TYPE_ERROR_ARB,
                            0,
                            GL_DEBUG_SEVERITY_HIGH_ARB,
-                           aMsg);
-
-      if (theCtx->caps->contextDebug)
+                           TCollection_ExtendedString ("Failed to compile shader object. Compilation log:\n") + aLog);
+      aShader->Release (theCtx.operator->());
+      return Standard_False;
+    }
+    else if (theCtx->caps->glslWarnings)
+    {
+      TCollection_AsciiString aLog;
+      aShader->FetchInfoLog (theCtx, aLog);
+      if (!aLog.IsEmpty()
+       && !aLog.IsEqual ("No errors.\n"))
       {
-        TCollection_AsciiString aLog;
-        aShader->FetchInfoLog (theCtx, aLog);
-        if (!aLog.IsEmpty())
-        {
-          std::cout << aLog.ToCString() << std::endl << std::flush;
-        }
-        else
-        {
-          std::cout << "Information log is empty" << std::endl;
-        }
+        theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
+                             GL_DEBUG_TYPE_PORTABILITY_ARB,
+                             0,
+                             GL_DEBUG_SEVERITY_LOW_ARB,
+                             TCollection_ExtendedString ("Shader compilation log:\n") + aLog);
       }
-
-      return Standard_False;
     }
 
     if (!AttachShader (theCtx, aShader))
     {
+      aShader->Release (theCtx.operator->());
       return Standard_False;
     }
   }
 
   if (!Link (theCtx))
   {
-    TCollection_ExtendedString aMsg = "Error! Failed to link program object";
-
+    TCollection_AsciiString aLog;
+    FetchInfoLog (theCtx, aLog);
+    if (aLog.IsEmpty())
+    {
+      aLog = "Linker log is empty.";
+    }
     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
                          GL_DEBUG_TYPE_ERROR_ARB,
                          0,
                          GL_DEBUG_SEVERITY_HIGH_ARB,
-                         aMsg);
-
-    if (theCtx->caps->contextDebug)
+                         TCollection_ExtendedString ("Failed to link program object! Linker log:\n"));
+    return Standard_False;
+  }
+  else if (theCtx->caps->glslWarnings)
+  {
+    TCollection_AsciiString aLog;
+    FetchInfoLog (theCtx, aLog);
+    if (!aLog.IsEmpty()
+     && !aLog.IsEqual ("No errors.\n"))
     {
-      TCollection_AsciiString aLog;
-      FetchInfoLog (theCtx, aLog);
-      if (!aLog.IsEmpty())
-      {
-        std::cout << aLog.ToCString() << std::endl;
-      }
-      else
-      {
-        std::cout << "Information log is empty" << std::endl;
-      }
+      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
+                           GL_DEBUG_TYPE_PORTABILITY_ARB,
+                           0,
+                           GL_DEBUG_SEVERITY_LOW_ARB,
+                           TCollection_ExtendedString ("GLSL linker log:\n") + aLog);
     }
-
-    return Standard_False;
   }
 
   return Standard_True;
index a38f845..51b09d8 100644 (file)
@@ -491,9 +491,27 @@ public:
 
 protected:
 
-  GLuint                          myProgramID;     //! Handle of OpenGL shader program
-  OpenGl_ShaderList               myShaderObjects; //! List of attached shader objects
-  Handle(Graphic3d_ShaderProgram) myProxy;         //! Proxy shader program (from application layer)
+  //! Increments counter of users.
+  //! Used by OpenGl_ShaderManager.
+  void Share()
+  {
+    ++myShareCount;
+  }
+
+  //! Decrements counter of users.
+  //! Used by OpenGl_ShaderManager.
+  //! @return true when there are no more users of this program has been left
+  bool UnShare()
+  {
+    return --myShareCount == 0;
+  }
+
+protected:
+
+  GLuint                          myProgramID;     //!< Handle of OpenGL shader program
+  OpenGl_ShaderList               myShaderObjects; //!< List of attached shader objects
+  Handle(Graphic3d_ShaderProgram) myProxy;         //!< Proxy shader program (from application layer)
+  Standard_Integer                myShareCount;    //!< program users count, initialized with 1 (already shared by one user)
 
 protected:
 
index 29244ef..2df7ae1 100644 (file)
@@ -17,7 +17,6 @@
 // purpose or non-infringement. Please see the License for the specific terms
 // and conditions governing the rights and limitations under the License.
 
-
 #ifdef HAVE_CONFIG_H
   #include <config.h>
 #endif
@@ -28,6 +27,7 @@
 #include <OpenGl_Display.hxx>
 #include <OpenGl_GlCore11.hxx>
 #include <OpenGl_GraduatedTrihedron.hxx>
+#include <OpenGl_GraphicDriver.hxx>
 #include <OpenGl_ShaderManager.hxx>
 #include <OpenGl_Texture.hxx>
 #include <OpenGl_Trihedron.hxx>
@@ -87,7 +87,8 @@ static const GLdouble THE_IDENTITY_MATRIX[4][4] =
 
 /*----------------------------------------------------------------------*/
 
-OpenGl_View::OpenGl_View (const CALL_DEF_VIEWCONTEXT &AContext)
+OpenGl_View::OpenGl_View (const CALL_DEF_VIEWCONTEXT &AContext,
+                          OpenGl_StateCounter*       theCounter)
 : mySurfaceDetail(Visual3d_TOD_NONE),
   myBackfacing(0),
   myBgTexture(myDefaultBgTexture),
@@ -109,9 +110,10 @@ OpenGl_View::OpenGl_View (const CALL_DEF_VIEWCONTEXT &AContext)
   myAntiAliasing(Standard_False),
   myTransPers(&myDefaultTransPers),
   myIsTransPers(Standard_False),
-  myOrientationChanged (Standard_True),
-  myViewMappingChanged (Standard_True),
-  myLightSourcesChanged (Standard_True)
+  myStateCounter (theCounter),
+  myLastOrientationState (0, 0),
+  myLastViewMappingState (0, 0),
+  myLastLightSourceState (0, 0)
 {
   // Initialize matrices
   memcpy(myOrientationMatrix,myDefaultMatrix,sizeof(Tmatrix3));
@@ -129,6 +131,10 @@ OpenGl_View::OpenGl_View (const CALL_DEF_VIEWCONTEXT &AContext)
       break;
   }
 
+  myCurrOrientationState = myStateCounter->Increment(); // <-- delete after merge with camera
+  myCurrViewMappingState = myStateCounter->Increment(); // <-- delete after merge with camera
+  myCurrLightSourceState = myStateCounter->Increment();
+
 #ifdef HAVE_OPENCL
   myModificationState = 1; // initial state
 #endif
@@ -268,7 +274,7 @@ void OpenGl_View::SetLights (const CALL_DEF_VIEWCONTEXT &AContext)
     myLights.Append(rep);
   }
 
-  myLightSourcesChanged = Standard_True;
+  myCurrLightSourceState = myStateCounter->Increment();
 }
 
 /*----------------------------------------------------------------------*/
@@ -381,7 +387,7 @@ void OpenGl_View::SetMapping (const Handle(OpenGl_Display)& theGlDisplay,
   if (!err_ind)
     myExtra.map = Map;
 
-  myViewMappingChanged = Standard_True;
+  myCurrViewMappingState = myStateCounter->Increment();
 }
 
 /*----------------------------------------------------------------------*/
@@ -444,7 +450,7 @@ void OpenGl_View::SetOrientation (const Graphic3d_CView& theCView)
     myExtra.scaleFactors[2] = ScaleFactors[2];
   }
 
-  myOrientationChanged = Standard_True;
+  myCurrOrientationState = myStateCounter->Increment();
 }
 
 /*----------------------------------------------------------------------*/
index 6419c1c..d8f13ac 100644 (file)
@@ -45,6 +45,7 @@
 #include <OpenGl_Light.hxx>
 
 #include <Handle_OpenGl_Context.hxx>
+#include <Handle_OpenGl_GraphicDriver.hxx>
 #include <Handle_OpenGl_Display.hxx>
 #include <Handle_OpenGl_Workspace.hxx>
 #include <Handle_OpenGl_View.hxx>
@@ -98,11 +99,12 @@ class OpenGl_GraduatedTrihedron;
 class OpenGl_Structure;
 class OpenGl_Trihedron;
 class Handle(OpenGl_PrinterContext);
+class OpenGl_StateCounter;
 
 class OpenGl_View : public MMgt_TShared
 {
  public:
-  OpenGl_View (const CALL_DEF_VIEWCONTEXT &AContext);
+  OpenGl_View (const CALL_DEF_VIEWCONTEXT &AContext, OpenGl_StateCounter* theCounter);
   virtual ~OpenGl_View ();
 
   void ReleaseGlResources (const Handle(OpenGl_Context)& theCtx);
@@ -265,10 +267,17 @@ public:
   const TEL_TRANSFORM_PERSISTENCE *myTransPers;
   Standard_Boolean myIsTransPers;
 
-  //! Modification flags.
-  Standard_Boolean myOrientationChanged;
-  Standard_Boolean myViewMappingChanged;
-  Standard_Boolean myLightSourcesChanged;
+  OpenGl_StateCounter* myStateCounter;
+
+  Standard_Size myCurrOrientationState; // <-- delete it after merge with new camera
+  Standard_Size myCurrViewMappingState; // <-- delete it after merge with new camera
+  Standard_Size myCurrLightSourceState;
+
+  typedef std::pair<Standard_Size, Standard_Size> StateInfo;
+
+  StateInfo myLastOrientationState;
+  StateInfo myLastViewMappingState;
+  StateInfo myLastLightSourceState;
 
 #ifdef HAVE_OPENCL
   Standard_Size myModificationState;
index c11b1f9..e00f141 100644 (file)
@@ -865,36 +865,30 @@ void OpenGl_View::Render (const Handle(OpenGl_PrinterContext)& thePrintContext,
   }
 
   // Set OCCT state uniform variables
-
-  if (!aContext->ShaderManager()->IsEmpty())
+  const Handle(OpenGl_ShaderManager) aManager = aContext->ShaderManager();
+  if (StateInfo (myCurrLightSourceState, aManager->LightSourceState().Index()) != myLastLightSourceState)
   {
-    if (myLightSourcesChanged)
-    {
-      aContext->ShaderManager()->UpdateLightSourceStateTo (&myLights);
-      myLightSourcesChanged = Standard_False;
-    }
-
-    if (myViewMappingChanged)
-    {
-      aContext->ShaderManager()->UpdateProjectionStateTo (myMappingMatrix);
-      myViewMappingChanged = Standard_False;
-    }
-
-    if (myOrientationChanged)
-    {
-      aContext->ShaderManager()->UpdateWorldViewStateTo (myOrientationMatrix);
-      myOrientationChanged = Standard_False;
-    }
-
-    if (aContext->ShaderManager()->ModelWorldState().Index() == 0)
-    {
-      Tmatrix3 aModelWorldState = { { 1.f, 0.f, 0.f, 0.f },
-                                    { 0.f, 1.f, 0.f, 0.f },
-                                    { 0.f, 0.f, 1.f, 0.f },
-                                    { 0.f, 0.f, 0.f, 1.f } };
-
-      aContext->ShaderManager()->UpdateModelWorldStateTo (aModelWorldState);
-    }
+    aManager->UpdateLightSourceStateTo (&myLights);
+    myLastLightSourceState = StateInfo (myCurrLightSourceState, aManager->LightSourceState().Index());
+  }
+  if (StateInfo (myCurrViewMappingState, aManager->ProjectionState().Index()) != myLastViewMappingState)
+  {
+    aManager->UpdateProjectionStateTo (myMappingMatrix);
+    myLastViewMappingState = StateInfo (myCurrViewMappingState, aManager->ProjectionState().Index());
+  }
+  if (StateInfo (myCurrOrientationState, aManager->WorldViewState().Index()) != myLastOrientationState)
+  {
+    aManager->UpdateWorldViewStateTo (myOrientationMatrix);
+    myLastOrientationState = StateInfo (myCurrOrientationState, aManager->WorldViewState().Index());
+  }
+  if (aManager->ModelWorldState().Index() == 0)
+  {
+    Tmatrix3 aModelWorldState = { { 1.f, 0.f, 0.f, 0.f },
+                                  { 0.f, 1.f, 0.f, 0.f },
+                                  { 0.f, 0.f, 1.f, 0.f },
+                                  { 0.f, 0.f, 0.f, 1.f } };
+    
+    aManager->UpdateModelWorldStateTo (aModelWorldState);
   }
 
   /////////////////////////////////////////////////////////////////////////////
@@ -1100,9 +1094,9 @@ D = -[Px,Py,Pz] dot |Nx|
       }
     }
     
-    if (!aContext->ShaderManager()->IsEmpty())
+    if (!aManager->IsEmpty())
     {
-      aContext->ShaderManager()->UpdateClippingState();
+      aManager->UpdateClippingState();
     }
   }
 
@@ -1191,10 +1185,15 @@ D = -[Px,Py,Pz] dot |Nx|
 
   aContext->ChangeClipping().RemoveAll();
 
-  if (!aContext->ShaderManager()->IsEmpty())
+  if (!aManager->IsEmpty())
   {
-    aContext->ShaderManager()->ResetMaterialStates();
-    aContext->ShaderManager()->RevertClippingState();
+    aManager->ResetMaterialStates();
+    aManager->RevertClippingState();
+
+    // We need to disable (unbind) all shaders programs to ensure
+    // that all objects without specified aspect will be drawn
+    // correctly (such as background)
+    OpenGl_ShaderProgram::Unbind (aContext);
   }
 
   // display global trihedron
index df02474..718147b 100644 (file)
@@ -459,9 +459,13 @@ const OpenGl_Matrix * OpenGl_Workspace::SetStructureMatrix (const OpenGl_Matrix
   if (!myGlContext->ShaderManager()->IsEmpty())
   {
     if (aRevert)
-      myGlContext->ShaderManager()->UpdateModelWorldStateTo (lmat.mat);
-    else
+    {
       myGlContext->ShaderManager()->RevertModelWorldStateTo (lmat.mat);
+    }
+    else
+    {
+      myGlContext->ShaderManager()->UpdateModelWorldStateTo (lmat.mat);
+    }
   }
 
   return StructureMatrix_old;
diff --git a/src/Shaders/PhongShading.fs b/src/Shaders/PhongShading.fs
new file mode 100644 (file)
index 0000000..70fb949
--- /dev/null
@@ -0,0 +1,170 @@
+// Created on: 2013-10-10
+// Created by: Denis BOGOLEPOV
+// Copyright (c) 2013 OPEN CASCADE SAS
+//
+// The content of this file is subject to the Open CASCADE Technology Public
+// License Version 6.5 (the "License"). You may not use the content of this file
+// except in compliance with the License. Please obtain a copy of the License
+// at http://www.opencascade.org and read it completely before using this file.
+//
+// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
+// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
+//
+// The Original Code and all software distributed under the License is
+// distributed on an "AS IS" basis, without warranty of any kind, and the
+// Initial Developer hereby disclaims all such warranties, including without
+// limitation, any warranties of merchantability, fitness for a particular
+// purpose or non-infringement. Please see the License for the specific terms
+// and conditions governing the rights and limitations under the License.
+
+//! Direction to the viewer.
+varying vec3 View;
+
+//! Vertex normal in view space.
+varying vec3 Normal;
+
+//! Vertex position in view space.
+varying vec4 Position;
+
+
+//! Ambient contribution of light sources.
+vec3 Ambient;
+
+//! Diffuse contribution of light sources.
+vec3 Diffuse;
+
+//! Specular contribution of light sources.
+vec3 Specular;
+
+
+// =======================================================================
+// function : AmbientLight
+// purpose  : Computes contribution of OCCT pure ambient light source
+// =======================================================================
+void AmbientLight (in int theIndex)
+{
+  Ambient += occLightSources[theIndex].Ambient;
+}
+
+// =======================================================================
+// function : PointLight
+// purpose  : Computes contribution of OCCT isotropic point light source
+// =======================================================================
+void PointLight (in int  theIndex,
+                 in vec3 theNormal,
+                 in vec3 theView,
+                 in vec3 thePoint)
+{
+  vec3 aLight = occLightSources[theIndex].Position;
+  if (occLightSources[theIndex].Head == 0)
+  {
+    aLight = vec3 (occWorldViewMatrix * occModelWorldMatrix * vec4 (aLight, 1.0));
+  }
+  aLight -= thePoint;
+
+  float aDist = length (aLight);
+  aLight = aLight * (1.0 / aDist);
+  
+  float anAttenuation = 1.0 / (occLightSources[theIndex].ConstAttenuation +
+                               occLightSources[theIndex].LinearAttenuation * aDist);
+
+  vec3 aHalf = normalize (aLight + theView);
+
+  float aNdotL = max (0.0, dot (theNormal, aLight));
+  float aNdotH = max (0.0, dot (theNormal,  aHalf));
+
+  float aSpecl = 0.0;
+  if (aNdotL > 0.0)
+  {
+    aSpecl = pow (aNdotH, occFrontMaterial.Shininess);
+  }
+  
+  Ambient  += occLightSources[theIndex].Ambient * anAttenuation;
+  Diffuse  += occLightSources[theIndex].Diffuse * aNdotL * anAttenuation;
+  Specular += occLightSources[theIndex].Specular * aSpecl * anAttenuation;
+}
+
+// =======================================================================
+// function : DirectionalLight
+// purpose  : Computes contribution of OCCT directional light source
+// =======================================================================
+void DirectionalLight (in int theIndex,
+                       in vec3 theNormal,
+                       in vec3 theView)
+{
+  vec3 aLight = normalize (occLightSources[theIndex].Position);
+
+  if (occLightSources[theIndex].Head == 0)
+  {
+    aLight = vec3 (occWorldViewMatrix * occModelWorldMatrix * vec4 (aLight, 0.0));
+  }
+  
+  vec3 aHalf = normalize (aLight + theView);
+  
+  float aNdotL = max (0.0, dot (theNormal, aLight));
+  float aNdotH = max (0.0, dot (theNormal,  aHalf));
+
+  float aSpecl = 0.0;
+  
+  if (aNdotL > 0.0)
+  {
+    aSpecl = pow (aNdotH, occFrontMaterial.Shininess);
+  }
+
+  Ambient  += occLightSources[theIndex].Ambient;
+  Diffuse  += occLightSources[theIndex].Diffuse * aNdotL;
+  Specular += occLightSources[theIndex].Specular * aSpecl;
+}
+
+// =======================================================================
+// function : ComputeLighting
+// purpose  : Computes illumination from OCCT light sources
+// =======================================================================
+vec4 ComputeLighting (in vec3 theNormal,
+                      in vec3 theView,
+                      in vec4 thePoint)
+{
+  // Clear the light intensity accumulators
+  Ambient  = vec3 (0.0);
+  Diffuse  = vec3 (0.0);
+  Specular = vec3 (0.0);
+
+  vec3 aPoint = thePoint.xyz / thePoint.w;
+       
+  for (int anIndex = 0; anIndex < occLightSourcesCount; ++anIndex)
+  {
+    occLightSource light = occLightSources[anIndex];
+    
+    if (light.Type == occAmbientLight)
+    {
+      AmbientLight (anIndex);
+    }
+    else if (light.Type == occDirectLight)
+         {
+           DirectionalLight (anIndex, theNormal, theView);
+         }
+         else if (light.Type == occPointLight)
+               {
+      PointLight (anIndex, theNormal, theView, aPoint);
+               }
+               else if (light.Type == occSpotLight)
+               {
+                 /* Not implemented */
+               }
+  }
+  
+  return vec4 (Ambient,  1.0) * occFrontMaterial.Ambient +
+         vec4 (Diffuse,  1.0) * occFrontMaterial.Diffuse +
+         vec4 (Specular, 1.0) * occFrontMaterial.Specular;
+}
+
+// =======================================================================
+// function : main
+// purpose  : Entry point to the fragment shader
+// =======================================================================
+void main()
+{
+  gl_FragColor = ComputeLighting (normalize (Normal),
+                                  normalize (View),
+                                  Position);
+}
diff --git a/src/Shaders/PhongShading.vs b/src/Shaders/PhongShading.vs
new file mode 100644 (file)
index 0000000..3f7104d
--- /dev/null
@@ -0,0 +1,60 @@
+// Created on: 2013-10-10
+// Created by: Denis BOGOLEPOV
+// Copyright (c) 2013 OPEN CASCADE SAS
+//
+// The content of this file is subject to the Open CASCADE Technology Public
+// License Version 6.5 (the "License"). You may not use the content of this file
+// except in compliance with the License. Please obtain a copy of the License
+// at http://www.opencascade.org and read it completely before using this file.
+//
+// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
+// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
+//
+// The Original Code and all software distributed under the License is
+// distributed on an "AS IS" basis, without warranty of any kind, and the
+// Initial Developer hereby disclaims all such warranties, including without
+// limitation, any warranties of merchantability, fitness for a particular
+// purpose or non-infringement. Please see the License for the specific terms
+// and conditions governing the rights and limitations under the License.
+
+//! Direction to the viewer.
+varying vec3 View;
+
+//! Vertex normal in view space.
+varying vec3 Normal;
+
+//! Vertex position in view space.
+varying vec4 Position;
+
+// =======================================================================
+// function : TransformNormal
+// purpose  : Computes the normal in view space
+// =======================================================================
+vec3 TransformNormal (in vec3 theNormal)
+{
+  vec4 aResult = occWorldViewMatrixInverseTranspose *
+    occModelWorldMatrixInverseTranspose * vec4 (theNormal, 0.0);
+  
+  return normalize (aResult.xyz);
+}
+
+// =======================================================================
+// function : main
+// purpose  : Entry point to the vertex shader
+// =======================================================================
+void main()
+{
+  // Compute vertex position in the view space
+  Position = occWorldViewMatrix * occModelWorldMatrix * occVertex;
+  
+  // Compute vertex normal in the view space
+  Normal = TransformNormal (occNormal);
+  
+  // Note: The specified view vector is absolutely correct only for the orthogonal
+  // projection. For perspective projection it will be approximate, but it is in
+  // good agreement with the OpenGL calculations
+  View = vec3 (0.0, 0.0, 1.0);
+
+  // Do fixed functionality vertex transform
+  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;
+}
index 065fd97..12fc1f2 100755 (executable)
@@ -32,9 +32,6 @@
 #include <TopLoc_Location.hxx>
 #include <TopTools_HArray1OfShape.hxx>
 #include <TColStd_HArray1OfTransient.hxx>
-#include <OSD_Directory.hxx>
-#include <OSD_File.hxx>
-#include <OSD_Path.hxx>
 #include <OSD_Timer.hxx>
 #include <Geom_Axis2Placement.hxx>
 #include <Geom_Axis1Placement.hxx>
 #include <AIS_ListIteratorOfListOfInteractive.hxx>
 #include <Aspect_InteriorStyle.hxx>
 #include <Graphic3d_AspectFillArea3d.hxx>
-#include <Graphic3d_TextureRoot.hxx>
 #include <Graphic3d_AspectLine3d.hxx>
-#include <Graphic3d_ShaderObject.hxx>
-#include <Graphic3d_ShaderProgram.hxx>
+#include <Graphic3d_TextureRoot.hxx>
 #include <Image_AlienPixMap.hxx>
 #include <Prs3d_ShadingAspect.hxx>
 #include <Prs3d_IsoAspect.hxx>
@@ -1900,64 +1895,6 @@ Standard_Integer VTexture (Draw_Interpretor& di,Standard_Integer argc, const cha
 }
 
 //==============================================================================
-//function : VShaderProg
-//purpose  : Sets the pair of vertex and fragment shaders for the object
-//==============================================================================
-static Standard_Integer VShaderProg (Draw_Interpretor& /*theDI*/,
-                                     Standard_Integer  theArgNb,
-                                     const char**      theArgVec)
-{
-  Handle(AIS_InteractiveContext) anAISContext = ViewerTest::GetAISContext();
-  if (anAISContext.IsNull())
-  {
-    std::cerr << "Use 'vinit' command before " << theArgVec[0] << "\n";
-    return 1;
-  }
-
-  if (theArgNb < 3)
-  {
-    std::cerr << theArgVec[0] <<" syntax error: lack of arguments - Type 'help vshaderprog\n";
-    return 1;
-  }
-
-  const TCollection_AsciiString aShapeName = theArgVec[1];
-  if (!GetMapOfAIS().IsBound2 (aShapeName))
-  {
-    std::cerr << theArgVec[0] << ": Use 'vdisplay' before\n";
-    return 1;
-  }
-
-  Handle(AIS_InteractiveObject) anIO = Handle(AIS_InteractiveObject)::DownCast (GetMapOfAIS().Find2 (aShapeName));
-  if (anIO.IsNull())
-  {
-    std::cerr << "Shape " << aShapeName.ToCString() << " does not exist\n";
-    return 1;
-  }
-
-  Handle(Graphic3d_ShaderProgram) aProgram = new Graphic3d_ShaderProgram();
-  const TCollection_AsciiString aVertexSource (theArgVec[2]);
-  if (!aVertexSource.IsEmpty() && !OSD_File(aVertexSource).Exists())
-  {
-    std::cerr << "Non-existing vertex shader source\n";
-    return 1;
-  }
-
-  TCollection_AsciiString aFragmentSource (theArgVec[3]);
-  if (!aFragmentSource.IsEmpty() && !OSD_File(aFragmentSource).Exists())
-  {
-    std::cerr << "Non-existing fragment shader source\n";
-    return 1;
-  }
-
-  aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_VERTEX,   aVertexSource));
-  aProgram->AttachShader (Graphic3d_ShaderObject::CreateFromFile (Graphic3d_TOS_FRAGMENT, aFragmentSource));
-  anIO->Attributes()->ShadingAspect()->Aspect()->SetShaderProgram (aProgram);
-
-  anAISContext->Redisplay (anIO);
-  return 0;
-}
-
-//==============================================================================
 //function : VDisplay2
 //author   : ege
 //purpose  : Display an object from its name
@@ -3341,10 +3278,6 @@ void ViewerTest::Commands(Draw_Interpretor& theCommands)
                   or 'vtexture NameOfShape IdOfTexture' (0<=IdOfTexture<=20)' to use predefined  textures\n ",
                  __FILE__,VTexture,group);
 
-  theCommands.Add("vshaderprog",
-                 "'vshaderprog NameOfShape VertexShaderFile FragmentShaderFile'",
-      __FILE__,VShaderProg,group);
-
   theCommands.Add("vtexscale",
                  "'vtexscale  NameOfShape ScaleU ScaleV' \n \
                    or 'vtexscale NameOfShape ScaleUV' \n \
index a30169d..118a2b3 100644 (file)
 
 #include <ViewerTest.hxx>
 
+#include <AIS_Drawer.hxx>
 #include <AIS_InteractiveContext.hxx>
 #include <AIS_InteractiveObject.hxx>
 #include <Draw.hxx>
 #include <Draw_Interpretor.hxx>
 #include <Graphic3d_Group.hxx>
+#include <Graphic3d_ShaderObject.hxx>
+#include <Graphic3d_ShaderProgram.hxx>
 #include <OpenGl_ArbVBO.hxx>
 #include <OpenGl_AspectFace.hxx>
 #include <OpenGl_AspectLine.hxx>
 #include <OpenGl_GlCore20.hxx>
 #include <OpenGl_GraphicDriver.hxx>
 #include <OpenGl_Workspace.hxx>
+#include <OSD_Environment.hxx>
+#include <OSD_File.hxx>
 #include <Prs3d_Presentation.hxx>
 #include <Prs3d_Root.hxx>
+#include <Prs3d_ShadingAspect.hxx>
 #include <Select3D_SensitiveCurve.hxx>
 #include <SelectMgr_EntityOwner.hxx>
 #include <SelectMgr_Selection.hxx>
-#include <V3d_Viewer.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>
 
 extern Standard_Boolean VDisplayAISObject (const TCollection_AsciiString& theName,
                                            const Handle(AIS_InteractiveObject)& theAISObj,
                                            Standard_Boolean theReplaceIfExists = Standard_True);
+extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS();
 
 //=======================================================================
 //function : VUserDraw
@@ -505,6 +514,107 @@ static int VGlInfo (Draw_Interpretor& theDI,
   return 0;
 }
 
+
+//==============================================================================
+//function : VShaderProg
+//purpose  : Sets the pair of vertex and fragment shaders for the object
+//==============================================================================
+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";
+    return 1;
+  }
+  else if (theArgNb < 2)
+  {
+    std::cerr << theArgVec[0] << " 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")
+  {
+    aProgram = new Graphic3d_ShaderProgram (Graphic3d_ShaderProgram::ShaderName_Phong);
+  }
+  if (!toTurnOff
+   && aProgram.IsNull())
+  {
+    if (theArgNb < 3)
+    {
+      std::cerr << theArgVec[0] << " syntax error: lack of arguments\n";
+      return 1;
+    }
+
+    const TCollection_AsciiString aSrcVert = theArgVec[theArgNb - 2];
+    const TCollection_AsciiString aSrcFrag = theArgVec[theArgNb - 1];
+    if (!aSrcVert.IsEmpty()
+     && !OSD_File (aSrcVert).Exists())
+    {
+      std::cerr << "Non-existing vertex shader source\n";
+      return 1;
+    }
+    if (!aSrcFrag.IsEmpty()
+     && !OSD_File (aSrcFrag).Exists())
+    {
+      std::cerr << "Non-existing fragment shader source\n";
+      return 1;
+    }
+
+    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;
+  }
+
+  Handle(AIS_InteractiveObject) anIO;
+  if (anArgsNb <= 1
+   || *theArgVec[1] == '*')
+  {
+    for (ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName anIter (GetMapOfAIS());
+          anIter.More(); anIter.Next())
+    {
+      anIO = Handle(AIS_InteractiveObject)::DownCast (anIter.Key1());
+      if (!anIO.IsNull())
+      {
+        anIO->Attributes()->ShadingAspect()->Aspect()->SetShaderProgram (aProgram);
+        aCtx->Redisplay (anIO, Standard_False);
+      }
+    }
+    aCtx->UpdateCurrentViewer();
+    return 0;
+  }
+
+  for (Standard_Integer anArgIter = 1; anArgIter < anArgsNb; ++anArgIter)
+  {
+    const TCollection_AsciiString aName (theArgVec[anArgIter]);
+    if (!GetMapOfAIS().IsBound2 (aName))
+    {
+      std::cerr << "Warning: " << aName.ToCString() << " is not displayed\n";
+      continue;
+    }
+    anIO = Handle(AIS_InteractiveObject)::DownCast (GetMapOfAIS().Find2 (aName));
+    if (anIO.IsNull())
+    {
+      std::cerr << "Warning: " << aName.ToCString() << " is not an AIS object\n";
+      continue;
+    }
+    anIO->Attributes()->ShadingAspect()->Aspect()->SetShaderProgram (aProgram);
+    aCtx->Redisplay (anIO, Standard_False);
+  }
+
+  aCtx->UpdateCurrentViewer();
+  return 0;
+}
+
 //=======================================================================
 //function : OpenGlCommands
 //purpose  :
@@ -523,9 +633,14 @@ void ViewerTest::OpenGlCommands(Draw_Interpretor& theCommands)
   theCommands.Add("vimmediatefront",
     "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",
     __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",
+    __FILE__, VShaderProg, aGroup);
 }
index 0686cdb..42738a6 100755 (executable)
@@ -724,12 +724,12 @@ void ViewerTest::RedrawAllViews()
 }
 
 //==============================================================================
-//function : SplitParameter
-//purpose  : Split parameter string to parameter name an patameter value
+//function : splitParameter
+//purpose  : Split parameter string to parameter name an parameter value
 //==============================================================================
-Standard_Boolean SplitParameter (const TCollection_AsciiString& theString,
-                                      TCollection_AsciiString& theName,
-                                      TCollection_AsciiString& theValue)
+Standard_Boolean splitParameter (const TCollection_AsciiString& theString,
+                                 TCollection_AsciiString&       theName,
+                                 TCollection_AsciiString&       theValue)
 {
   Standard_Integer aParamNameEnd = theString.FirstLocationInSet("=",1, theString.Length());
   if (aParamNameEnd == 0)
@@ -768,7 +768,7 @@ if (theArgsNb > 9)
   for (Standard_Integer i = 1; i < theArgsNb; ++i)
   {
     TCollection_AsciiString aName = "", aValue = "";
-    if(!SplitParameter (TCollection_AsciiString(theArgVec[i]),aName,aValue) && theArgsNb == 2)
+    if(!splitParameter (TCollection_AsciiString(theArgVec[i]),aName,aValue) && theArgsNb == 2)
     {
       // In case of syntax: vinit ViewName
       aViewName = theArgVec[1];
@@ -5276,6 +5276,83 @@ static int VSetTextureMode (Draw_Interpretor& theDi, Standard_Integer theArgsNb,
   return 0;
 }
 
+//===============================================================================================
+//function : VDefaults
+//purpose  :
+//===============================================================================================
+static int VDefaults (Draw_Interpretor& theDi,
+                      Standard_Integer  theArgsNb,
+                      const char**      theArgVec)
+{
+  const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
+  if (aCtx.IsNull())
+  {
+    std::cerr << "No active viewer!\n";
+    return 1;
+  }
+
+  Handle(Prs3d_Drawer) aDefParams = aCtx->DefaultDrawer();
+  if (theArgsNb < 2)
+  {
+    if (aDefParams->TypeOfDeflection() == Aspect_TOD_RELATIVE)
+    {
+      theDi << "DeflType:           relative\n"
+            << "DeviationCoeff:     " << aDefParams->DeviationCoefficient() << "\n";
+    }
+    else
+    {
+      theDi << "DeflType:           absolute\n"
+            << "AbsoluteDeflection: " << aDefParams->MaximalChordialDeviation() << "\n";
+    }
+    theDi << "AngularDeflection:  " << (180.0 * aDefParams->HLRAngle() / M_PI) << "\n";
+    return 0;
+  }
+
+  for (Standard_Integer anArgIter = 1; anArgIter < theArgsNb; ++anArgIter)
+  {
+    TCollection_AsciiString anArg (theArgVec[anArgIter]);
+    TCollection_AsciiString aKey, aValue;
+    if (!splitParameter (anArg, aKey, aValue)
+     || aValue.IsEmpty())
+    {
+      std::cerr << "Error, wrong syntax at: '" << anArg.ToCString() << "'!\n";
+      return 1;
+    }
+
+    aKey.UpperCase();
+    if (aKey == "ABSDEFL"
+     || aKey == "ABSOLUTEDEFLECTION"
+     || aKey == "DEFL"
+     || aKey == "DEFLECTION")
+    {
+      aDefParams->SetTypeOfDeflection         (Aspect_TOD_ABSOLUTE);
+      aDefParams->SetMaximalChordialDeviation (aValue.RealValue());
+    }
+    else if (aKey == "RELDEFL"
+          || aKey == "RELATIVEDEFLECTION"
+          || aKey == "DEVCOEFF"
+          || aKey == "DEVIATIONCOEFF"
+          || aKey == "DEVIATIONCOEFFICIENT")
+    {
+      aDefParams->SetTypeOfDeflection     (Aspect_TOD_RELATIVE);
+      aDefParams->SetDeviationCoefficient (aValue.RealValue());
+    }
+    else if (aKey == "ANGDEFL"
+          || aKey == "ANGULARDEFL"
+          || aKey == "ANGULARDEFLECTION")
+    {
+      // currently HLRDeviationAngle is used instead of DeviationAngle in most places
+      aDefParams->SetHLRAngle (M_PI * aValue.RealValue() / 180.0);
+    }
+    else
+    {
+      std::cerr << "Warning, unknown argument '" << anArg.ToCString() << "'\n";
+    }
+  }
+
+  return 0;
+}
+
 //==============================================================================
 //function : VClInfo
 //purpose  : Prints info about active OpenCL device
@@ -5726,6 +5803,9 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "  2 - all textures enabled.\n"
     "  this command sets texture details mode for the specified view.\n"
     , __FILE__, VSetTextureMode, group);
+  theCommands.Add("vdefaults",
+    "vdefaults [absDefl=value] [devCoeff=value] [angDefl=value]",
+    __FILE__, VDefaults, group);
   theCommands.Add("vraytrace",
     "vraytrace 0|1",
     __FILE__,VRaytrace,group);
index 5a0b190..785f553 100755 (executable)
@@ -2,18 +2,13 @@ cpulimit 300
 set group "v3d"
 
 pload VISUALIZATION
-vinit
+vinit View1
 pload TOPTEST
 
 if { [info exists imagedir] == 0 } {
-    set imagedir .
+  set imagedir .
 }
 
 if { [info exists test_image ] == 0 } {
-    set test_image photo
+  set test_image photo
 }
-
-
-
-
-
index 1f3e473..1d492e6 100755 (executable)
@@ -1,8 +1,7 @@
 catch { vfit }
 if { [ catch { vdump $imagedir/${test_image}.png } catch_result ] } {
-    puts $catch_result
+  puts $catch_result
 }
+catch { vglinfo }
 
 puts "TEST COMPLETED"
-
-
diff --git a/tests/v3d/glsl/phong_box b/tests/v3d/glsl/phong_box
new file mode 100644 (file)
index 0000000..896d63b
--- /dev/null
@@ -0,0 +1,25 @@
+puts "========"
+puts "Per-pixel lighting using GLSL program (Phong shading)"
+puts "========"
+
+# create box
+box b 1 2 3
+
+# draw box
+vinit View1
+vclear
+vsetdispmode 1
+vdisplay b
+vfit
+vrotate 0.2 0.0 0.0
+
+# take snapshot with fixed pipeline
+vdump $::imagedir/${::casename}_OFF.png
+vshaderprog b phong
+vdump $::imagedir/${::casename}_ph1.png
+
+vclear
+vdisplay b
+vshaderprog b phong
+vdump $::imagedir/${::casename}_ph2.png
+vmoveto 250 250
diff --git a/tests/v3d/glsl/phong_couple b/tests/v3d/glsl/phong_couple
new file mode 100644 (file)
index 0000000..47cb342
--- /dev/null
@@ -0,0 +1,29 @@
+puts "========"
+puts "Per-pixel lighting using GLSL program (Phong shading)"
+puts "========"
+
+# import model
+restore [locate_data_file occ/fuse.brep] f
+tclean f
+box b 2 0 0 1 0.5 0.25
+
+# draw box
+vinit View1
+vclear
+vdefaults absDefl=0.5
+vsetdispmode 1
+vdisplay f
+vfit
+vrotate -0.5 0.0 0.0
+vdisplay b
+vfit
+
+# take snapshot with fixed pipeline
+vdump $::imagedir/${::casename}_OFF.png
+
+vshaderprog f phong
+vshaderprog b phong
+vshaderprog b off
+vrotate -0.2 0.0 0.0
+vmoveto 100 100
+vdump $::imagedir/${::casename}_ph1.png
diff --git a/tests/v3d/glsl/phong_fuse b/tests/v3d/glsl/phong_fuse
new file mode 100644 (file)
index 0000000..1a94e3d
--- /dev/null
@@ -0,0 +1,28 @@
+puts "========"
+puts "Per-pixel lighting using GLSL program (Phong shading)"
+puts "========"
+
+# import model
+restore [locate_data_file occ/fuse.brep] f
+tclean f
+
+# draw box
+vinit View1
+vclear
+vdefaults absDefl=0.5
+vsetdispmode 1
+vdisplay f
+vfit
+vrotate -0.5 0.0 0.0
+vfit
+
+# take snapshot with fixed pipeline
+vdump $::imagedir/${::casename}_OFF.png
+vshaderprog f phong
+vdump $::imagedir/${::casename}_ph1.png
+
+vclear
+vdisplay f
+vshaderprog f phong
+vdump $::imagedir/${::casename}_ph2.png
+vmoveto 250 250
diff --git a/tests/v3d/glsl/phong_views b/tests/v3d/glsl/phong_views
new file mode 100644 (file)
index 0000000..f6fa308
--- /dev/null
@@ -0,0 +1,21 @@
+puts "========"
+puts "Per-pixel lighting using GLSL program (Phong shading)"
+puts "========"
+
+# create box
+box b 1 2 3
+
+# draw box
+vinit View1
+vclear
+vsetdispmode 1
+vdisplay b
+vfit
+vrotate 0.2 0.0 0.0
+
+vshaderprog b phong
+vdump $::imagedir/${::casename}_1.png
+
+vinit View2
+vdump $::imagedir/${::casename}_2.png
+vclose View2
index f80c845..6269975 100644 (file)
@@ -10,3 +10,4 @@
 010 wire
 011 wire_solid
 012 voxel
+013 glsl