0029283: Visualization - allow defining more than 8 light sources
authorkgv <kgv@opencascade.com>
Tue, 31 Oct 2017 17:02:13 +0000 (20:02 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 9 Nov 2017 15:08:34 +0000 (18:08 +0300)
OpenGl_ShaderManager now overrides THE_MAX_LIGHTS within built-in shading programs
so that maximum number of lights is now limited only by OpenGL hardware
(e.g. length of GLSL program, number of defined uniforms, result performance, etc.).
THE_MAX_CLIP_PLANES is now also defined by OpenGl_ShaderManager,
so that unused lights and clipping planes do not reserve extra uniforms in GLSL programs.

V3d_View::SetLightOn() does not throw exception anymore, when the number of lights exceeds 8.
Instead, OpenGl_ShaderManager::PushLightSourceState() emits warning
in case of usage of FFP providing consistent behavior with Clipping Planes number limit.

13 files changed:
src/Graphic3d/Graphic3d_ShaderProgram.cxx
src/Graphic3d/Graphic3d_ShaderProgram.hxx
src/OpenGl/OpenGl_GraphicDriver.cxx
src/OpenGl/OpenGl_ShaderManager.cxx
src/OpenGl/OpenGl_ShaderManager.hxx
src/OpenGl/OpenGl_ShaderProgram.cxx
src/OpenGl/OpenGl_ShaderProgram.hxx
src/Shaders/Declarations.glsl
src/Shaders/DeclarationsImpl.glsl
src/Shaders/Shaders_DeclarationsImpl_glsl.pxx
src/Shaders/Shaders_Declarations_glsl.pxx
src/V3d/V3d_View_2.cxx
tests/v3d/glsl/phong_pos2 [new file with mode: 0644]

index 119d642..2d708d6 100755 (executable)
@@ -77,6 +77,8 @@ const TCollection_AsciiString& Graphic3d_ShaderProgram::ShadersFolder()
 // purpose  : Creates new empty program object
 // =======================================================================
 Graphic3d_ShaderProgram::Graphic3d_ShaderProgram()
+: myNbLightsMax (THE_MAX_LIGHTS_DEFAULT),
+  myNbClipPlanesMax (THE_MAX_CLIP_PLANES_DEFAULT)
 {
   myID = TCollection_AsciiString ("Graphic3d_ShaderProgram_")
        + TCollection_AsciiString (Standard_Atomic_Increment (&THE_PROGRAM_OBJECT_COUNTER));
index 5118e17..b723e9d 100755 (executable)
@@ -34,6 +34,14 @@ typedef NCollection_Sequence<Handle(Graphic3d_ShaderAttribute)> Graphic3d_Shader
 //! This class is responsible for managing shader programs.
 class Graphic3d_ShaderProgram : public Standard_Transient
 {
+  DEFINE_STANDARD_RTTIEXT(Graphic3d_ShaderProgram, Standard_Transient)
+public:
+
+  //! Default value of THE_MAX_LIGHTS macros within GLSL program (see Declarations.glsl).
+  static const Standard_Integer THE_MAX_LIGHTS_DEFAULT = 8;
+
+  //! Default value of THE_MAX_CLIP_PLANES macros within GLSL program (see Declarations.glsl).
+  static const Standard_Integer THE_MAX_CLIP_PLANES_DEFAULT = 8;
 
 public:
 
@@ -61,6 +69,32 @@ public:
   //! @endcode
   void SetHeader (const TCollection_AsciiString& theHeader) { myHeader = theHeader; }
 
+  //! Append line to GLSL header.
+  void AppendToHeader (const TCollection_AsciiString& theHeaderLine)
+  {
+    if (!myHeader.IsEmpty())
+    {
+      myHeader += "\n";
+    }
+    myHeader += theHeaderLine;
+  }
+
+  //! Return the length of array of light sources (THE_MAX_LIGHTS),
+  //! to be used for initialization occLightSources.
+  //! Default value is THE_MAX_LIGHTS_DEFAULT.
+  Standard_Integer NbLightsMax() const { return myNbLightsMax; }
+
+  //! Specify the length of array of light sources (THE_MAX_LIGHTS).
+  void SetNbLightsMax (Standard_Integer theNbLights) { myNbLightsMax = theNbLights; }
+
+  //! Return the length of array of clipping planes (THE_MAX_CLIP_PLANES),
+  //! to be used for initialization occClipPlaneEquations.
+  //! Default value is THE_MAX_CLIP_PLANES_DEFAULT.
+  Standard_Integer NbClipPlanesMax() const { return myNbClipPlanesMax; }
+
+  //! Specify the length of array of clipping planes (THE_MAX_CLIP_PLANES).
+  void SetNbClipPlanesMax (Standard_Integer theNbPlanes) { myNbClipPlanesMax = theNbPlanes; }
+
   //! Attaches shader object to the program object.
   Standard_EXPORT Standard_Boolean AttachShader (const Handle(Graphic3d_ShaderObject)& theShader);
 
@@ -121,10 +155,6 @@ public:
   //! @return the root folder with default GLSL programs.
   Standard_EXPORT static const TCollection_AsciiString& ShadersFolder();
 
-public:
-
-  DEFINE_STANDARD_RTTIEXT(Graphic3d_ShaderProgram,Standard_Transient)
-
 private:
 
   TCollection_AsciiString       myID;            //!< the unique identifier of program object
@@ -132,6 +162,8 @@ private:
   Graphic3d_ShaderVariableList  myVariables;     //!< the list of custom uniform variables
   Graphic3d_ShaderAttributeList myAttributes;    //!< the list of custom vertex attributes
   TCollection_AsciiString       myHeader;        //!< GLSL header with version code and used extensions
+  Standard_Integer              myNbLightsMax;   //!< length of array of light sources (THE_MAX_LIGHTS)
+  Standard_Integer              myNbClipPlanesMax; //!< length of array of clipping planes (THE_MAX_CLIP_PLANES)
 
 };
 
index 196837e..14ceb7b 100644 (file)
@@ -406,7 +406,7 @@ Standard_Integer OpenGl_GraphicDriver::InquireLimit (const Graphic3d_TypeOfLimit
   switch (theType)
   {
     case Graphic3d_TypeOfLimit_MaxNbLights:
-      return OpenGLMaxLights;
+      return Graphic3d_ShaderProgram::THE_MAX_LIGHTS_DEFAULT;
     case Graphic3d_TypeOfLimit_MaxNbClipPlanes:
       return !aCtx.IsNull() ? aCtx->MaxClipPlanes() : 0;
     case Graphic3d_TypeOfLimit_MaxNbViews:
index 1867cc7..5faea41 100644 (file)
@@ -33,9 +33,6 @@ IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderManager,Standard_Transient)
 namespace
 {
 
-  //! Clipping planes limit (see the same definition in Declarations.glsl).
-  static const Standard_Size THE_MAX_CLIP_PLANES = 8;
-
 #define EOL "\n"
 
 //! Definition of TexCoord varying.
@@ -596,70 +593,85 @@ void OpenGl_ShaderManager::PushLightSourceState (const Handle(OpenGl_ShaderProgr
       return;
     }
 
-    if (myContext->core11 != NULL)
+    GLenum aLightGlId = GL_LIGHT0;
+    OpenGl_Vec4 anAmbient (0.0f, 0.0f, 0.0f, 0.0f);
+    const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
+    if (myLightSourceState.LightSources() != NULL)
     {
-      GLenum aLightGlId = GL_LIGHT0;
-      OpenGl_Vec4 anAmbient (0.0f, 0.0f, 0.0f, 0.0f);
-      const OpenGl_Mat4 aModelView = myWorldViewState.WorldViewMatrix() * myModelWorldState.ModelWorldMatrix();
-      for (OpenGl_ListOfLight::Iterator aLightIt (*myLightSourceState.LightSources()); aLightIt.More(); aLightIt.Next())
+      for (Graphic3d_ListOfCLight::Iterator aLightIt (*myLightSourceState.LightSources()); aLightIt.More(); aLightIt.Next())
       {
-        const OpenGl_Light& aLight = aLightIt.Value();
+        const Graphic3d_CLight& aLight = aLightIt.Value();
         if (aLight.Type == Graphic3d_TOLS_AMBIENT)
         {
           anAmbient += aLight.Color;
           continue;
         }
-        else if (aLightGlId > GL_LIGHT7) // OpenGLMaxLights - only 8 lights in OpenGL...
+        else if (aLightGlId > GL_LIGHT7) // only 8 lights in FFP...
         {
+          myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
+                                  "Warning: light sources limit (8) has been exceeded within Fixed-function pipeline.");
           continue;
         }
 
-        bindLight (aLightIt.Value(), aLightGlId, aModelView, myContext);
+        bindLight (aLight, aLightGlId, aModelView, myContext);
         ++aLightGlId;
       }
+    }
 
-      // apply accumulated ambient color
-      anAmbient.a() = 1.0f;
-      myContext->core11->glLightModelfv (GL_LIGHT_MODEL_AMBIENT, anAmbient.GetData());
+    // apply accumulated ambient color
+    anAmbient.a() = 1.0f;
+    myContext->core11->glLightModelfv (GL_LIGHT_MODEL_AMBIENT, anAmbient.GetData());
 
-      // GL_LIGHTING is managed by drawers to switch between shaded / no lighting output,
-      // therefore managing the state here does not have any effect - do it just for consistency.
-      if (aLightGlId != GL_LIGHT0)
-      {
-        ::glEnable (GL_LIGHTING);
-      }
-      else
-      {
-        ::glDisable (GL_LIGHTING);
-      }
-      // switch off unused lights
-      for (; aLightGlId <= GL_LIGHT7; ++aLightGlId)
-      {
-        ::glDisable (aLightGlId);
-      }
+    // GL_LIGHTING is managed by drawers to switch between shaded / no lighting output,
+    // therefore managing the state here does not have any effect - do it just for consistency.
+    if (aLightGlId != GL_LIGHT0)
+    {
+      ::glEnable (GL_LIGHTING);
+    }
+    else
+    {
+      ::glDisable (GL_LIGHTING);
+    }
+    // switch off unused lights
+    for (; aLightGlId <= GL_LIGHT7; ++aLightGlId)
+    {
+      ::glDisable (aLightGlId);
     }
   #endif
     return;
   }
 
-  for (Standard_Integer aLightIt = 0; aLightIt < OpenGLMaxLights; ++aLightIt)
+  const Standard_Integer aNbLightsMax = theProgram->NbLightsMax();
+  const GLint anAmbientLoc = theProgram->GetStateLocation (OpenGl_OCC_LIGHT_AMBIENT);
+  if (aNbLightsMax == 0
+   && anAmbientLoc == OpenGl_ShaderProgram::INVALID_LOCATION)
   {
-    myLightTypeArray[aLightIt].Type = -1;
+    return;
   }
 
-  const Standard_Integer aLightsDefNb = Min (myLightSourceState.LightSources()->Size(), OpenGLMaxLights);
-  if (aLightsDefNb < 1)
+  if (myLightTypeArray.Size() < aNbLightsMax)
+  {
+    myLightTypeArray  .Resize (0, aNbLightsMax - 1, false);
+    myLightParamsArray.Resize (0, aNbLightsMax - 1, false);
+  }
+  for (Standard_Integer aLightIt = 0; aLightIt < aNbLightsMax; ++aLightIt)
+  {
+    myLightTypeArray.ChangeValue (aLightIt).Type = -1;
+  }
+
+  if (myLightSourceState.LightSources() == NULL
+   || myLightSourceState.LightSources()->IsEmpty())
   {
     theProgram->SetUniform (myContext,
                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_COUNT),
                             0);
     theProgram->SetUniform (myContext,
-                            theProgram->GetStateLocation (OpenGl_OCC_LIGHT_AMBIENT),
+                            anAmbientLoc,
                             OpenGl_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
     theProgram->SetUniform (myContext,
                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
-                            OpenGLMaxLights * OpenGl_ShaderLightType::NbOfVec2i(),
-                            myLightTypeArray[0].Packed());
+                            aNbLightsMax * OpenGl_ShaderLightType::NbOfVec2i(),
+                            myLightTypeArray.First().Packed());
     return;
   }
 
@@ -673,17 +685,21 @@ void OpenGl_ShaderManager::PushLightSourceState (const Handle(OpenGl_ShaderProgr
       anAmbient += aLight.Color;
       continue;
     }
-    else if (aLightsNb >= OpenGLMaxLights)
+    else if (aLightsNb >= aNbLightsMax)
     {
+      if (aNbLightsMax != 0)
+      {
+        myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
+                                TCollection_AsciiString("Warning: light sources limit (") + aNbLightsMax + ") has been exceeded.");
+      }
       continue;
     }
 
-    OpenGl_ShaderLightType& aLightType = myLightTypeArray[aLightsNb];
+    OpenGl_ShaderLightType&       aLightType   = myLightTypeArray.ChangeValue (aLightsNb);
+    OpenGl_ShaderLightParameters& aLightParams = myLightParamsArray.ChangeValue (aLightsNb);
     aLightType.Type        = aLight.Type;
     aLightType.IsHeadlight = aLight.IsHeadlight;
-
-    OpenGl_ShaderLightParameters& aLightParams = myLightParamsArray[aLightsNb];
-    aLightParams.Color = aLight.Color;
+    aLightParams.Color     = aLight.Color;
     if (aLight.Type == Graphic3d_TOLS_DIRECTIONAL)
     {
       aLightParams.Position = -aLight.Direction;
@@ -715,18 +731,18 @@ void OpenGl_ShaderManager::PushLightSourceState (const Handle(OpenGl_ShaderProgr
                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_COUNT),
                           aLightsNb);
   theProgram->SetUniform (myContext,
-                          theProgram->GetStateLocation (OpenGl_OCC_LIGHT_AMBIENT),
+                          anAmbientLoc,
                           anAmbient);
   theProgram->SetUniform (myContext,
                           theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_TYPES),
-                          OpenGLMaxLights * OpenGl_ShaderLightType::NbOfVec2i(),
-                          myLightTypeArray[0].Packed());
+                          aNbLightsMax * OpenGl_ShaderLightType::NbOfVec2i(),
+                          myLightTypeArray.First().Packed());
   if (aLightsNb > 0)
   {
     theProgram->SetUniform (myContext,
                             theProgram->GetStateLocation (OpenGl_OCC_LIGHT_SOURCE_PARAMS),
                             aLightsNb * OpenGl_ShaderLightParameters::NbOfVec4(),
-                            myLightParamsArray[0].Packed());
+                            myLightParamsArray.First().Packed());
   }
 }
 
@@ -907,8 +923,12 @@ void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram)
       return;
     }
 
-    const Standard_Integer aNbMaxPlanes = Min (myContext->MaxClipPlanes(), THE_MAX_CLIP_PLANES);
-    OpenGl_Vec4d anEquations[THE_MAX_CLIP_PLANES];
+    const Standard_Integer aNbMaxPlanes = myContext->MaxClipPlanes();
+    if (myClipPlaneArrayFfp.Size() < aNbMaxPlanes)
+    {
+      myClipPlaneArrayFfp.Resize (0, aNbMaxPlanes - 1, false);
+    }
+
     Standard_Integer aPlaneId = 0;
     Standard_Boolean toRestoreModelView = Standard_False;
     for (OpenGl_ClippingIterator aPlaneIter (myContext->Clipping()); aPlaneIter.More(); aPlaneIter.Next())
@@ -920,14 +940,13 @@ void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram)
       }
       else if (aPlaneId >= aNbMaxPlanes)
       {
-        myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
-                                GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
+        myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
                                 TCollection_ExtendedString("Warning: clipping planes limit (") + aNbMaxPlanes + ") has been exceeded.");
         break;
       }
 
       const Graphic3d_ClipPlane::Equation& anEquation = aPlane->GetEquation();
-      OpenGl_Vec4d& aPlaneEq = anEquations[aPlaneId];
+      OpenGl_Vec4d& aPlaneEq = myClipPlaneArrayFfp.ChangeValue (aPlaneId);
       aPlaneEq.x() = anEquation.x();
       aPlaneEq.y() = anEquation.y();
       aPlaneEq.z() = anEquation.z();
@@ -976,7 +995,8 @@ void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram)
     return;
   }
 
-  const GLint aNbPlanes = Min (myContext->Clipping().NbClippingOrCappingOn(), THE_MAX_CLIP_PLANES);
+  const Standard_Integer aNbClipPlanesMax = theProgram->NbClipPlanesMax();
+  const GLint aNbPlanes = Min (myContext->Clipping().NbClippingOrCappingOn(), aNbClipPlanesMax);
   theProgram->SetUniform (myContext,
                           theProgram->GetStateLocation (OpenGl_OCC_CLIP_PLANE_COUNT),
                           aNbPlanes);
@@ -985,8 +1005,12 @@ void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram)
     return;
   }
 
-  OpenGl_Vec4 anEquations[THE_MAX_CLIP_PLANES];
-  GLuint aPlaneId = 0;
+  if (myClipPlaneArray.Size() < aNbClipPlanesMax)
+  {
+    myClipPlaneArray.Resize (0, aNbClipPlanesMax - 1, false);
+  }
+
+  Standard_Integer aPlaneId = 0;
   for (OpenGl_ClippingIterator aPlaneIter (myContext->Clipping()); aPlaneIter.More(); aPlaneIter.Next())
   {
     const Handle(Graphic3d_ClipPlane)& aPlane = aPlaneIter.Value();
@@ -994,16 +1018,15 @@ void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram)
     {
       continue;
     }
-    else if (aPlaneId >= THE_MAX_CLIP_PLANES)
+    else if (aPlaneId >= aNbClipPlanesMax)
     {
-      myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
-        GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
-        "Warning: clipping planes limit (8) has been exceeded.");
+      myContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
+                              TCollection_AsciiString("Warning: clipping planes limit (") + aNbClipPlanesMax + ") has been exceeded.");
       break;
     }
 
     const Graphic3d_ClipPlane::Equation& anEquation = aPlane->GetEquation();
-    OpenGl_Vec4& aPlaneEq = anEquations[aPlaneId];
+    OpenGl_Vec4& aPlaneEq = myClipPlaneArray.ChangeValue (aPlaneId);
     aPlaneEq.x() = float(anEquation.x());
     aPlaneEq.y() = float(anEquation.y());
     aPlaneEq.z() = float(anEquation.z());
@@ -1017,7 +1040,7 @@ void OpenGl_ShaderManager::PushClippingState (const Handle(OpenGl_ShaderProgram)
     ++aPlaneId;
   }
 
-  theProgram->SetUniform (myContext, aLocEquations, THE_MAX_CLIP_PLANES, anEquations);
+  theProgram->SetUniform (myContext, aLocEquations, aNbClipPlanesMax, &myClipPlaneArray.First());
 }
 
 // =======================================================================
@@ -1173,6 +1196,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFont()
     aProgramSrc->SetHeader ("#version 300 es");
   }
 #endif
+  aProgramSrc->SetNbLightsMax (0);
+  aProgramSrc->SetNbClipPlanesMax (0);
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
   TCollection_AsciiString aKey;
@@ -1240,6 +1265,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFboBlit()
     aProgramSrc->SetHeader ("#version 150");
   }
 #endif
+  aProgramSrc->SetNbLightsMax (0);
+  aProgramSrc->SetNbClipPlanesMax (0);
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
   TCollection_AsciiString aKey;
@@ -1328,6 +1355,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramOitCompositing (const St
   #endif
   }
 
+  aProgramSrc->SetNbLightsMax (0);
+  aProgramSrc->SetNbClipPlanesMax (0);
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
   TCollection_AsciiString aKey;
@@ -1463,6 +1492,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_Shad
     aSrcFragExtraOut  += EOL"THE_SHADER_IN  vec4 VertColor;";
     aSrcFragGetColor  =  EOL"vec4 getColor(void) { return VertColor; }";
   }
+
+  int aNbClipPlanes = 0;
   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
   {
     aSrcVertExtraOut +=
@@ -1477,14 +1508,17 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_Shad
 
     if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
     {
+      aNbClipPlanes = 1;
       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
     }
     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
     {
+      aNbClipPlanes = 2;
       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2;
     }
     else
     {
+      aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
     }
   }
@@ -1575,6 +1609,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFlat (Handle(OpenGl_Shad
     aProgramSrc->SetHeader ("#version 300 es");
   }
 #endif
+  aProgramSrc->SetNbLightsMax (0);
+  aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
 
@@ -1625,12 +1661,14 @@ TCollection_AsciiString OpenGl_ShaderManager::pointSpriteShadingSrc (const TColl
 // function : stdComputeLighting
 // purpose  :
 // =======================================================================
-TCollection_AsciiString OpenGl_ShaderManager::stdComputeLighting (const Standard_Boolean theHasVertColor)
+TCollection_AsciiString OpenGl_ShaderManager::stdComputeLighting (Standard_Integer& theNbLights,
+                                                                  Standard_Boolean  theHasVertColor)
 {
   Standard_Integer aLightsMap[Graphic3d_TOLS_SPOT + 1] = { 0, 0, 0, 0 };
   TCollection_AsciiString aLightsFunc, aLightsLoop;
   const OpenGl_ListOfLight* aLights = myLightSourceState.LightSources();
   if (aLights != NULL)
+  theNbLights = 0;
   {
     Standard_Integer anIndex = 0;
     for (OpenGl_ListOfLight::Iterator aLightIter (*aLights); aLightIter.More(); aLightIter.Next(), ++anIndex)
@@ -1652,6 +1690,7 @@ TCollection_AsciiString OpenGl_ShaderManager::stdComputeLighting (const Standard
       }
       aLightsMap[aLightIter.Value().Type] += 1;
     }
+    theNbLights = anIndex;
     const Standard_Integer aNbLoopLights = aLightsMap[Graphic3d_TOLS_DIRECTIONAL]
                                          + aLightsMap[Graphic3d_TOLS_POSITIONAL]
                                          + aLightsMap[Graphic3d_TOLS_SPOT];
@@ -1762,6 +1801,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
     aSrcVertColor = EOL"vec4 getVertColor(void) { return occVertColor; }";
   }
 
+  int aNbClipPlanes = 0;
   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
   {
     aSrcVertExtraOut +=
@@ -1776,14 +1816,17 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
 
     if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
     {
+      aNbClipPlanes = 1;
       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
     }
     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
     {
+      aNbClipPlanes = 2;
       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2;
     }
     else
     {
+      aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
     }
   }
@@ -1792,7 +1835,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
     aSrcFragWriteOit += THE_FRAG_write_oit_buffers;
   }
 
-  const TCollection_AsciiString aLights = stdComputeLighting ((theBits & OpenGl_PO_VertColor) != 0);
+  Standard_Integer aNbLights = 0;
+  const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, (theBits & OpenGl_PO_VertColor) != 0);
   aSrcVert = TCollection_AsciiString()
     + THE_FUNC_transformNormal
     + EOL
@@ -1838,6 +1882,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
     aProgramSrc->SetHeader ("#version 300 es");
   }
 #endif
+  aProgramSrc->SetNbLightsMax (aNbLights);
+  aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
   TCollection_AsciiString aKey;
@@ -1914,18 +1960,22 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
                            EOL"vec4 getVertColor(void) { return VertColor; }";
   }
 
+  int aNbClipPlanes = 0;
   if ((theBits & OpenGl_PO_ClipPlanesN) != 0)
   {
     if ((theBits & OpenGl_PO_ClipPlanes1) != 0)
     {
+      aNbClipPlanes = 1;
       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_1;
     }
     else if ((theBits & OpenGl_PO_ClipPlanes2) != 0)
     {
+      aNbClipPlanes = 2;
       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_2;
     }
     else
     {
+      aNbClipPlanes = Graphic3d_ShaderProgram::THE_MAX_CLIP_PLANES_DEFAULT;
       aSrcFragExtraMain += THE_FRAG_CLIP_PLANES_N;
     }
   }
@@ -1955,7 +2005,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
     + EOL"  gl_Position = occProjectionMatrix * occWorldViewMatrix * occModelWorldMatrix * occVertex;"
       EOL"}";
 
-  const TCollection_AsciiString aLights = stdComputeLighting ((theBits & OpenGl_PO_VertColor) != 0);
+  Standard_Integer aNbLights = 0;
+  const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, (theBits & OpenGl_PO_VertColor) != 0);
   aSrcFrag = TCollection_AsciiString()
     + EOL"THE_SHADER_IN vec4 PositionWorld;"
       EOL"THE_SHADER_IN vec4 Position;"
@@ -2003,6 +2054,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
     }
   }
 #endif
+  aProgramSrc->SetNbLightsMax (aNbLights);
+  aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
   TCollection_AsciiString aKey;
@@ -2225,6 +2278,8 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramStereo (Handle(OpenGl_Sh
   }
 #endif
 
+  aProgramSrc->SetNbLightsMax (0);
+  aProgramSrc->SetNbClipPlanesMax (0);
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_VERTEX,   aSrcVert));
   aProgramSrc->AttachShader (Graphic3d_ShaderObject::CreateFromSource (Graphic3d_TOS_FRAGMENT, aSrcFrag));
   TCollection_AsciiString aKey;
index 8e68cd3..17add9f 100644 (file)
@@ -444,8 +444,10 @@ protected:
                                                            const Standard_Boolean        theIsFlatNormal = false);
 
   //! Define computeLighting GLSL function depending on current lights configuration
-  //! @param theHasVertColor flag to use getVertColor() instead of Ambient and Diffuse components of active material
-  Standard_EXPORT TCollection_AsciiString stdComputeLighting (const Standard_Boolean theHasVertColor);
+  //! @param theNbLights     [out] number of defined light sources
+  //! @param theHasVertColor [in]  flag to use getVertColor() instead of Ambient and Diffuse components of active material
+  Standard_EXPORT TCollection_AsciiString stdComputeLighting (Standard_Integer& theNbLights,
+                                                              Standard_Boolean  theHasVertColor);
 
   //! Bind specified program to current context and apply state.
   Standard_EXPORT Standard_Boolean bindProgramWithState (const Handle(OpenGl_ShaderProgram)& theProgram);
@@ -522,8 +524,10 @@ protected:
   gp_XYZ                             myLocalOrigin;        //!< local camera transformation
   Standard_Boolean                   myHasLocalOrigin;     //!< flag indicating that local camera transformation has been set
 
-  mutable OpenGl_ShaderLightType       myLightTypeArray  [OpenGLMaxLights];
-  mutable OpenGl_ShaderLightParameters myLightParamsArray[OpenGLMaxLights];
+  mutable NCollection_Array1<OpenGl_ShaderLightType>       myLightTypeArray;
+  mutable NCollection_Array1<OpenGl_ShaderLightParameters> myLightParamsArray;
+  mutable NCollection_Array1<OpenGl_Vec4>                  myClipPlaneArray;
+  mutable NCollection_Array1<OpenGl_Vec4d>                 myClipPlaneArrayFfp;
 
 private:
 
index 41a25bf..4439b33 100755 (executable)
@@ -149,6 +149,8 @@ OpenGl_ShaderProgram::OpenGl_ShaderProgram (const Handle(Graphic3d_ShaderProgram
   myProgramID (NO_PROGRAM),
   myProxy     (theProxy),
   myShareCount(1),
+  myNbLightsMax (0),
+  myNbClipPlanesMax (0),
   myHasTessShader (false)
 {
   memset (myCurrentState, 0, sizeof (myCurrentState));
@@ -327,11 +329,24 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
       case Graphic3d_TOS_FRAGMENT:        { aHeaderType = "#define FRAGMENT_SHADER\n";        break; }
     }
 
+    TCollection_AsciiString aHeaderConstants;
+    myNbLightsMax     = !myProxy.IsNull() ? myProxy->NbLightsMax() : 0;
+    myNbClipPlanesMax = !myProxy.IsNull() ? myProxy->NbClipPlanesMax() : 0;
+    if (myNbLightsMax > 0)
+    {
+      aHeaderConstants += TCollection_AsciiString("#define THE_MAX_LIGHTS ") + myNbLightsMax + "\n";
+    }
+    if (myNbClipPlanesMax > 0)
+    {
+      aHeaderConstants += TCollection_AsciiString("#define THE_MAX_CLIP_PLANES ") + myNbClipPlanesMax + "\n";
+    }
+
     const TCollection_AsciiString aSource = aHeaderVer                     // #version   - header defining GLSL version, should be first
                                           + (!aHeaderVer.IsEmpty() ? "\n" : "")
                                           + anExtensions                   // #extension - list of enabled extensions,   should be second
                                           + aPrecisionHeader               // precision  - default precision qualifiers, should be before any code
                                           + aHeaderType                    // auxiliary macros defining a shader stage (type)
+                                          + aHeaderConstants
                                           + Shaders_Declarations_glsl      // common declarations (global constants and Vertex Shader inputs)
                                           + Shaders_DeclarationsImpl_glsl
                                           + anIter.Value()->Source();      // the source code itself (defining main() function)
index 123d832..99474d8 100755 (executable)
@@ -210,9 +210,19 @@ public:
     return myProgramID;
   }
 
+public:
+
   //! Return TRUE if program defines tessellation stage.
   Standard_Boolean HasTessellationStage() const { return myHasTessShader; }
 
+  //! Return the length of array of light sources (THE_MAX_LIGHTS),
+  //! to be used for initialization occLightSources (OpenGl_OCC_LIGHT_SOURCE_PARAMS).
+  Standard_Integer NbLightsMax() const { return myNbLightsMax; }
+
+  //! Return the length of array of clipping planes (THE_MAX_CLIP_PLANES),
+  //! to be used for initialization occClipPlaneEquations (OpenGl_OCC_CLIP_PLANE_EQUATIONS).
+  Standard_Integer NbClipPlanesMax() const { return myNbClipPlanesMax; }
+
 private:
 
   //! Returns index of last modification of variables of specified state type.
@@ -554,6 +564,8 @@ protected:
   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)
+  Standard_Integer                myNbLightsMax;   //!< length of array of light sources (THE_MAX_LIGHTS)
+  Standard_Integer                myNbClipPlanesMax; //!< length of array of clipping planes (THE_MAX_CLIP_PLANES)
   Standard_Boolean                myHasTessShader; //!< flag indicating that program defines tessellation stage
 
 protected:
index ef704d5..929d909 100644 (file)
 // Alternatively, this file may be used under the terms of Open CASCADE
 // commercial license or contractual agreement.
 
-// This files includes definition of common uniform variables in OCCT GLSL programs
+//! @file Declarations.glsl
+//! This files includes definition of common uniform variables in OCCT GLSL programs
 
-#define THE_MAX_LIGHTS      8
-#define THE_MAX_CLIP_PLANES 8
+//! @def THE_MAX_LIGHTS
+//! Specifies the length of array of lights, which is 8 by default. Defined by Shader Manager.
+// #define THE_MAX_LIGHTS 8
+
+//! @def THE_MAX_CLIP_PLANES
+//! Specifies the length of array of clipping planes, which is 8 by default. Defined by Shader Manager.
+// #define THE_MAX_CLIP_PLANES 8
 
 // compatibility macros
 #if (__VERSION__ >= 130)
@@ -92,6 +98,7 @@ const int OccLightType_Spot   = 3; //!< spot            light source
 
 // Light sources
 uniform               vec4 occLightAmbient;      //!< Cumulative ambient color
+#if defined(THE_MAX_LIGHTS) && (THE_MAX_LIGHTS > 0)
 uniform THE_PREC_ENUM int  occLightSourcesCount; //!< Total number of light sources
 int   occLight_Type              (in int theId); //!< Type of light source
 int   occLight_IsHeadlight       (in int theId); //!< Is light a headlight?
@@ -103,6 +110,7 @@ float occLight_ConstAttenuation  (in int theId); //!< Const attenuation factor o
 float occLight_LinearAttenuation (in int theId); //!< Linear attenuation factor of positional light source
 float occLight_SpotCutOff        (in int theId); //!< Maximum spread angle of the spot light (in radians)
 float occLight_SpotExponent      (in int theId); //!< Attenuation of the spot light intensity (from 0 to 1)
+#endif
 
 // Front material properties accessors
 vec4  occFrontMaterial_Emission(void);     //!< Emission color
@@ -135,5 +143,7 @@ uniform               int       occOitOutput;      //!< Enable bit for writing o
 uniform               float     occOitDepthFactor; //!< Influence of the depth component to the coverage of the accumulated fragment
 
 //! Parameters of clipping planes
+#if defined(THE_MAX_CLIP_PLANES) && (THE_MAX_CLIP_PLANES > 0)
 uniform               vec4 occClipPlaneEquations[THE_MAX_CLIP_PLANES];
 uniform THE_PREC_ENUM int  occClipPlaneCount;   //!< Total number of clip planes
+#endif
index eee338b..e13307e 100644 (file)
@@ -15,6 +15,7 @@
 
 // This file includes implementation of common functions and properties accessors
 
+#if defined(THE_MAX_LIGHTS) && (THE_MAX_LIGHTS > 0)
 // arrays of light sources
 uniform THE_PREC_ENUM ivec2 occLightSourcesTypes[THE_MAX_LIGHTS]; //!< packed light sources types
 uniform               vec4  occLightSources[THE_MAX_LIGHTS * 4];  //!< packed light sources parameters
@@ -30,6 +31,7 @@ float occLight_ConstAttenuation  (in int theId) { return occLightSources[theId *
 float occLight_LinearAttenuation (in int theId) { return occLightSources[theId * 4 + 3].y; }
 float occLight_SpotCutOff        (in int theId) { return occLightSources[theId * 4 + 3].z; }
 float occLight_SpotExponent      (in int theId) { return occLightSources[theId * 4 + 3].w; }
+#endif
 
 // material state
 uniform vec4 occFrontMaterial[5];
index 1d1c832..48e69b3 100644 (file)
@@ -18,6 +18,7 @@ static const char Shaders_DeclarationsImpl_glsl[] =
   "\n"
   "// This file includes implementation of common functions and properties accessors\n"
   "\n"
+  "#if defined(THE_MAX_LIGHTS) && (THE_MAX_LIGHTS > 0)\n"
   "// arrays of light sources\n"
   "uniform THE_PREC_ENUM ivec2 occLightSourcesTypes[THE_MAX_LIGHTS]; //!< packed light sources types\n"
   "uniform               vec4  occLightSources[THE_MAX_LIGHTS * 4];  //!< packed light sources parameters\n"
@@ -33,6 +34,7 @@ static const char Shaders_DeclarationsImpl_glsl[] =
   "float occLight_LinearAttenuation (in int theId) { return occLightSources[theId * 4 + 3].y; }\n"
   "float occLight_SpotCutOff        (in int theId) { return occLightSources[theId * 4 + 3].z; }\n"
   "float occLight_SpotExponent      (in int theId) { return occLightSources[theId * 4 + 3].w; }\n"
+  "#endif\n"
   "\n"
   "// material state\n"
   "uniform vec4 occFrontMaterial[5];\n"
index ee2bba3..46928f7 100644 (file)
@@ -16,10 +16,16 @@ static const char Shaders_Declarations_glsl[] =
   "// Alternatively, this file may be used under the terms of Open CASCADE\n"
   "// commercial license or contractual agreement.\n"
   "\n"
-  "// This files includes definition of common uniform variables in OCCT GLSL programs\n"
+  "//! @file Declarations.glsl\n"
+  "//! This files includes definition of common uniform variables in OCCT GLSL programs\n"
   "\n"
-  "#define THE_MAX_LIGHTS      8\n"
-  "#define THE_MAX_CLIP_PLANES 8\n"
+  "//! @def THE_MAX_LIGHTS\n"
+  "//! Specifies the length of array of lights, which is 8 by default. Defined by Shader Manager.\n"
+  "// #define THE_MAX_LIGHTS 8\n"
+  "\n"
+  "//! @def THE_MAX_CLIP_PLANES\n"
+  "//! Specifies the length of array of clipping planes, which is 8 by default. Defined by Shader Manager.\n"
+  "// #define THE_MAX_CLIP_PLANES 8\n"
   "\n"
   "// compatibility macros\n"
   "#if (__VERSION__ >= 130)\n"
@@ -95,6 +101,7 @@ static const char Shaders_Declarations_glsl[] =
   "\n"
   "// Light sources\n"
   "uniform               vec4 occLightAmbient;      //!< Cumulative ambient color\n"
+  "#if defined(THE_MAX_LIGHTS) && (THE_MAX_LIGHTS > 0)\n"
   "uniform THE_PREC_ENUM int  occLightSourcesCount; //!< Total number of light sources\n"
   "int   occLight_Type              (in int theId); //!< Type of light source\n"
   "int   occLight_IsHeadlight       (in int theId); //!< Is light a headlight?\n"
@@ -106,6 +113,7 @@ static const char Shaders_Declarations_glsl[] =
   "float occLight_LinearAttenuation (in int theId); //!< Linear attenuation factor of positional light source\n"
   "float occLight_SpotCutOff        (in int theId); //!< Maximum spread angle of the spot light (in radians)\n"
   "float occLight_SpotExponent      (in int theId); //!< Attenuation of the spot light intensity (from 0 to 1)\n"
+  "#endif\n"
   "\n"
   "// Front material properties accessors\n"
   "vec4  occFrontMaterial_Emission(void);     //!< Emission color\n"
@@ -138,5 +146,7 @@ static const char Shaders_Declarations_glsl[] =
   "uniform               float     occOitDepthFactor; //!< Influence of the depth component to the coverage of the accumulated fragment\n"
   "\n"
   "//! Parameters of clipping planes\n"
+  "#if defined(THE_MAX_CLIP_PLANES) && (THE_MAX_CLIP_PLANES > 0)\n"
   "uniform               vec4 occClipPlaneEquations[THE_MAX_CLIP_PLANES];\n"
-  "uniform THE_PREC_ENUM int  occClipPlaneCount;   //!< Total number of clip planes\n";
+  "uniform THE_PREC_ENUM int  occClipPlaneCount;   //!< Total number of clip planes\n"
+  "#endif\n";
index 6403544..6ead291 100644 (file)
@@ -53,8 +53,6 @@ void V3d_View::SetLightOn (const Handle(V3d_Light)& theLight)
 {
   if (!myActiveLights.Contains (theLight))
   {
-    if (myActiveLights.Extent() >= LightLimit())
-      throw V3d_BadValue("V3d_View::SetLightOn, too many lights");
     myActiveLights.Append (theLight);
     UpdateLights();
   }
diff --git a/tests/v3d/glsl/phong_pos2 b/tests/v3d/glsl/phong_pos2
new file mode 100644 (file)
index 0000000..4d1eae6
--- /dev/null
@@ -0,0 +1,44 @@
+puts "========"
+puts "0029283: Visualization - allow defining more than 8 light sources"
+puts "========"
+
+pload MODELING VISUALIZATION
+
+# display objects
+vclear
+vclose ALL
+vinit View1 -width 1024 -height 768
+vcaps -ffp 0
+vrenderparams -shadingModel phong
+vaxo
+for { set anObjIter 0 } { $anObjIter < 3 } { incr anObjIter } {
+  set aShiftX [expr -4 + $anObjIter * 4]
+  psphere s$anObjIter 0.5
+  vdisplay -dispMode 1 s$anObjIter
+  vsetlocation s$anObjIter $aShiftX 0 0
+}
+vfit
+
+# define lights
+set THE_LIGHTS {
+  { -1 -1 -1 RED1 }
+  {  1 -1 -1 YELLOW }
+  { -1  1 -1 BLUE1 }
+  { -1 -1  1 CYAN1 }
+  {  1  1 -1 PURPLE }
+  {  1  1  1 WHITE }
+  { -1  1  1 HOTPINK }
+  {  1 -1  1 GREEN }
+  { -4 -1  0 MAGENTA1 }
+  {  4 -1  0 MAGENTA3 }
+}
+vlight clear
+for { set aLightIter 1 } { $aLightIter <= 10 } { incr aLightIter } {
+  set aLight [lindex $THE_LIGHTS [expr $aLightIter - 1]]
+  set aColor [lindex $aLight 3]
+  set aPos [list [lindex $aLight 0] [lindex $aLight 1] [lindex $aLight 2]]
+  vlight add positional pos {*}$aPos color $aColor headLight 0
+  vpoint v${aLightIter} {*}$aPos
+  vdrawtext t${aLightIter} "light${aLightIter} $aColor" -pos {*}$aPos -color $aColor
+  vdump $::imagedir/${::casename}_${aLightIter}.png
+}