From 392ac9808ec93a5dbe0fc1ddda9e6d0627702892 Mon Sep 17 00:00:00 2001 From: kgv Date: Fri, 1 Nov 2013 13:52:19 +0400 Subject: [PATCH] 0024250: TKOpenGl - per-pixel lighting using GLSL program (Phong shading) --- src/Graphic3d/Graphic3d_ShaderProgram.cxx | 91 ++++++++++ src/Graphic3d/Graphic3d_ShaderProgram.hxx | 20 +++ src/Graphic3d/Graphic3d_TextureRoot.cxx | 6 +- src/OpenGl/OpenGl_AspectFace.cxx | 35 ++-- src/OpenGl/OpenGl_AspectLine.cxx | 34 ++-- src/OpenGl/OpenGl_AspectMarker.cxx | 30 ++-- src/OpenGl/OpenGl_AspectText.cxx | 33 ++-- src/OpenGl/OpenGl_CappingAlgo.cxx | 2 +- src/OpenGl/OpenGl_Caps.cxx | 5 +- src/OpenGl/OpenGl_Caps.hxx | 11 +- src/OpenGl/OpenGl_Context.cxx | 8 + src/OpenGl/OpenGl_GraphicDriver.hxx | 23 +++ src/OpenGl/OpenGl_GraphicDriver_7.cxx | 2 +- src/OpenGl/OpenGl_ShaderManager.cxx | 43 +++-- src/OpenGl/OpenGl_ShaderManager.hxx | 20 ++- src/OpenGl/OpenGl_ShaderProgram.cxx | 112 ++++++------ src/OpenGl/OpenGl_ShaderProgram.hxx | 24 ++- src/OpenGl/OpenGl_View.cxx | 22 ++- src/OpenGl/OpenGl_View.hxx | 19 ++- src/OpenGl/OpenGl_View_2.cxx | 67 ++++---- src/OpenGl/OpenGl_Workspace_5.cxx | 8 +- src/Shaders/PhongShading.fs | 170 +++++++++++++++++++ src/Shaders/PhongShading.vs | 60 +++++++ src/ViewerTest/ViewerTest.cxx | 69 +------- src/ViewerTest/ViewerTest_OpenGlCommands.cxx | 119 ++++++++++++- src/ViewerTest/ViewerTest_ViewerCommands.cxx | 92 +++++++++- tests/v3d/begin | 11 +- tests/v3d/end | 5 +- tests/v3d/glsl/phong_box | 25 +++ tests/v3d/glsl/phong_couple | 29 ++++ tests/v3d/glsl/phong_fuse | 28 +++ tests/v3d/glsl/phong_views | 21 +++ tests/v3d/grids.list | 1 + 33 files changed, 932 insertions(+), 313 deletions(-) create mode 100644 src/Shaders/PhongShading.fs create mode 100644 src/Shaders/PhongShading.vs create mode 100644 tests/v3d/glsl/phong_box create mode 100644 tests/v3d/glsl/phong_couple create mode 100644 tests/v3d/glsl/phong_fuse create mode 100644 tests/v3d/glsl/phong_views diff --git a/src/Graphic3d/Graphic3d_ShaderProgram.cxx b/src/Graphic3d/Graphic3d_ShaderProgram.cxx index 29aa9c73e0..64e6eb9163 100644 --- a/src/Graphic3d/Graphic3d_ShaderProgram.cxx +++ b/src/Graphic3d/Graphic3d_ShaderProgram.cxx @@ -23,6 +23,10 @@ #include #include #include +#include +#include +#include +#include namespace { @@ -32,6 +36,52 @@ namespace 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 @@ -42,6 +92,47 @@ Graphic3d_ShaderProgram::Graphic3d_ShaderProgram() + TCollection_AsciiString (Standard_Atomic_Increment (&THE_PROGRAM_OBJECT_COUNTER)); } +// ======================================================================= +// 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 diff --git a/src/Graphic3d/Graphic3d_ShaderProgram.hxx b/src/Graphic3d/Graphic3d_ShaderProgram.hxx index ac816f5395..938ab35027 100644 --- a/src/Graphic3d/Graphic3d_ShaderProgram.hxx +++ b/src/Graphic3d/Graphic3d_ShaderProgram.hxx @@ -34,11 +34,25 @@ typedef NCollection_Sequence 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(); @@ -71,6 +85,12 @@ public: //! Removes all custom uniform variables from the program. Standard_EXPORT void ClearVariables(); +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) diff --git a/src/Graphic3d/Graphic3d_TextureRoot.cxx b/src/Graphic3d/Graphic3d_TextureRoot.cxx index a599e099e0..f5bb528798 100755 --- a/src/Graphic3d/Graphic3d_TextureRoot.cxx +++ b/src/Graphic3d/Graphic3d_TextureRoot.cxx @@ -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; } diff --git a/src/OpenGl/OpenGl_AspectFace.cxx b/src/OpenGl/OpenGl_AspectFace.cxx index a9a7483e03..f7f9a79483 100644 --- a/src/OpenGl/OpenGl_AspectFace.cxx +++ b/src/OpenGl/OpenGl_AspectFace.cxx @@ -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 (ShaderProgramId, ShaderProgram)) - { - ShaderProgram = aContext->ShaderManager()->Create (theShader); - if (!ShaderProgramId.IsEmpty()) - { - aContext->ShareResource (ShaderProgramId, ShaderProgram); - } - } - } - else - { - ShaderProgram.Nullify(); + return; } + + aContext->ShaderManager()->Create (theShader, ShaderProgramId, ShaderProgram); } diff --git a/src/OpenGl/OpenGl_AspectLine.cxx b/src/OpenGl/OpenGl_AspectLine.cxx index a347949188..e5b80ba23d 100644 --- a/src/OpenGl/OpenGl_AspectLine.cxx +++ b/src/OpenGl/OpenGl_AspectLine.cxx @@ -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 (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); } diff --git a/src/OpenGl/OpenGl_AspectMarker.cxx b/src/OpenGl/OpenGl_AspectMarker.cxx index 78a077d834..5dbfe52f6d 100644 --- a/src/OpenGl/OpenGl_AspectMarker.cxx +++ b/src/OpenGl/OpenGl_AspectMarker.cxx @@ -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 (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); } // ======================================================================= diff --git a/src/OpenGl/OpenGl_AspectText.cxx b/src/OpenGl/OpenGl_AspectText.cxx index 482a374e5f..046a07df2d 100644 --- a/src/OpenGl/OpenGl_AspectText.cxx +++ b/src/OpenGl/OpenGl_AspectText.cxx @@ -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 (ShaderProgramId, ShaderProgram)) - { - ShaderProgram = aContext->ShaderManager()->Create (theShader); - if (!ShaderProgramId.IsEmpty()) - { - aContext->ShareResource (ShaderProgramId, ShaderProgram); - } - } - } - else - { - ShaderProgram.Nullify(); + return; } + + aContext->ShaderManager()->Create (theShader, ShaderProgramId, ShaderProgram); } diff --git a/src/OpenGl/OpenGl_CappingAlgo.cxx b/src/OpenGl/OpenGl_CappingAlgo.cxx index a24a8796cb..24a994fe02 100644 --- a/src/OpenGl/OpenGl_CappingAlgo.cxx +++ b/src/OpenGl/OpenGl_CappingAlgo.cxx @@ -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 diff --git a/src/OpenGl/OpenGl_Caps.cxx b/src/OpenGl/OpenGl_Caps.cxx index 5b57f7b218..1c3ee00e7d 100644 --- a/src/OpenGl/OpenGl_Caps.cxx +++ b/src/OpenGl/OpenGl_Caps.cxx @@ -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; } diff --git a/src/OpenGl/OpenGl_Caps.hxx b/src/OpenGl/OpenGl_Caps.hxx index a7935bf3d3..c6ca52c960 100644 --- a/src/OpenGl/OpenGl_Caps.hxx +++ b/src/OpenGl/OpenGl_Caps.hxx @@ -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 diff --git a/src/OpenGl/OpenGl_Context.cxx b/src/OpenGl/OpenGl_Context.cxx index 85f7481f1e..c321fb5283 100644 --- a/src/OpenGl/OpenGl_Context.cxx +++ b/src/OpenGl/OpenGl_Context.cxx @@ -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::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; } diff --git a/src/OpenGl/OpenGl_GraphicDriver.hxx b/src/OpenGl/OpenGl_GraphicDriver.hxx index fa7d4ae7dc..fe53540320 100644 --- a/src/OpenGl/OpenGl_GraphicDriver.hxx +++ b/src/OpenGl/OpenGl_GraphicDriver.hxx @@ -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
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 diff --git a/src/OpenGl/OpenGl_GraphicDriver_7.cxx b/src/OpenGl/OpenGl_GraphicDriver_7.cxx index 68d3aaa186..0e40dfee1f 100755 --- a/src/OpenGl/OpenGl_GraphicDriver_7.cxx +++ b/src/OpenGl/OpenGl_GraphicDriver_7.cxx @@ -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); diff --git a/src/OpenGl/OpenGl_ShaderManager.cxx b/src/OpenGl/OpenGl_ShaderManager.cxx index 97b0fbb0ed..cff325cadc 100644 --- a/src/OpenGl/OpenGl_ShaderManager.cxx +++ b/src/OpenGl/OpenGl_ShaderManager.cxx @@ -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 (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; } } diff --git a/src/OpenGl/OpenGl_ShaderManager.hxx b/src/OpenGl/OpenGl_ShaderManager.hxx index b3ddf2239a..1ee5e47fc5 100644 --- a/src/OpenGl/OpenGl_ShaderManager.hxx +++ b/src/OpenGl/OpenGl_ShaderManager.hxx @@ -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 diff --git a/src/OpenGl/OpenGl_ShaderProgram.cxx b/src/OpenGl/OpenGl_ShaderProgram.cxx index 6a6e5e1f66..59903d2f86 100644 --- a/src/OpenGl/OpenGl_ShaderProgram.cxx +++ b/src/OpenGl/OpenGl_ShaderProgram.cxx @@ -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; diff --git a/src/OpenGl/OpenGl_ShaderProgram.hxx b/src/OpenGl/OpenGl_ShaderProgram.hxx index a38f845dfd..51b09d8939 100644 --- a/src/OpenGl/OpenGl_ShaderProgram.hxx +++ b/src/OpenGl/OpenGl_ShaderProgram.hxx @@ -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: diff --git a/src/OpenGl/OpenGl_View.cxx b/src/OpenGl/OpenGl_View.cxx index 29244efba8..2df7ae10bc 100644 --- a/src/OpenGl/OpenGl_View.cxx +++ b/src/OpenGl/OpenGl_View.cxx @@ -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 #endif @@ -28,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -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(); } /*----------------------------------------------------------------------*/ diff --git a/src/OpenGl/OpenGl_View.hxx b/src/OpenGl/OpenGl_View.hxx index 6419c1cba4..d8f13ac5b5 100644 --- a/src/OpenGl/OpenGl_View.hxx +++ b/src/OpenGl/OpenGl_View.hxx @@ -45,6 +45,7 @@ #include #include +#include #include #include #include @@ -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 StateInfo; + + StateInfo myLastOrientationState; + StateInfo myLastViewMappingState; + StateInfo myLastLightSourceState; #ifdef HAVE_OPENCL Standard_Size myModificationState; diff --git a/src/OpenGl/OpenGl_View_2.cxx b/src/OpenGl/OpenGl_View_2.cxx index c11b1f9cc3..e00f141017 100644 --- a/src/OpenGl/OpenGl_View_2.cxx +++ b/src/OpenGl/OpenGl_View_2.cxx @@ -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 diff --git a/src/OpenGl/OpenGl_Workspace_5.cxx b/src/OpenGl/OpenGl_Workspace_5.cxx index df0247499d..718147b939 100644 --- a/src/OpenGl/OpenGl_Workspace_5.cxx +++ b/src/OpenGl/OpenGl_Workspace_5.cxx @@ -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 index 0000000000..70fb9491de --- /dev/null +++ b/src/Shaders/PhongShading.fs @@ -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 index 0000000000..3f7104d3f8 --- /dev/null +++ b/src/Shaders/PhongShading.vs @@ -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; +} diff --git a/src/ViewerTest/ViewerTest.cxx b/src/ViewerTest/ViewerTest.cxx index 065fd97a07..12fc1f2108 100755 --- a/src/ViewerTest/ViewerTest.cxx +++ b/src/ViewerTest/ViewerTest.cxx @@ -32,9 +32,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -54,10 +51,8 @@ #include #include #include -#include #include -#include -#include +#include #include #include #include @@ -1899,64 +1894,6 @@ Standard_Integer VTexture (Draw_Interpretor& di,Standard_Integer argc, const cha 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) 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 @@ -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 \ diff --git a/src/ViewerTest/ViewerTest_OpenGlCommands.cxx b/src/ViewerTest/ViewerTest_OpenGlCommands.cxx index a30169dbe4..118a2b3b9c 100644 --- a/src/ViewerTest/ViewerTest_OpenGlCommands.cxx +++ b/src/ViewerTest/ViewerTest_OpenGlCommands.cxx @@ -23,11 +23,14 @@ #include +#include #include #include #include #include #include +#include +#include #include #include #include @@ -39,19 +42,25 @@ #include #include #include +#include +#include #include #include +#include #include #include #include -#include #include #include +#include #include +#include +#include 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); } diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 0686cdb94c..42738a62bf 100755 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -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); diff --git a/tests/v3d/begin b/tests/v3d/begin index 5a0b190a6f..785f55391b 100755 --- a/tests/v3d/begin +++ b/tests/v3d/begin @@ -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 } - - - - - diff --git a/tests/v3d/end b/tests/v3d/end index 1f3e4732b8..1d492e6848 100755 --- a/tests/v3d/end +++ b/tests/v3d/end @@ -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 index 0000000000..896d63ba35 --- /dev/null +++ b/tests/v3d/glsl/phong_box @@ -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 index 0000000000..47cb3423c4 --- /dev/null +++ b/tests/v3d/glsl/phong_couple @@ -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 index 0000000000..1a94e3d23c --- /dev/null +++ b/tests/v3d/glsl/phong_fuse @@ -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 index 0000000000..f6fa308761 --- /dev/null +++ b/tests/v3d/glsl/phong_views @@ -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 diff --git a/tests/v3d/grids.list b/tests/v3d/grids.list index f80c8451c9..626997505d 100644 --- a/tests/v3d/grids.list +++ b/tests/v3d/grids.list @@ -10,3 +10,4 @@ 010 wire 011 wire_solid 012 voxel +013 glsl -- 2.20.1