0030748: Visualization - Marker displayed in immediate layer ruins QT Quick view...
[occt.git] / src / OpenGl / OpenGl_Sampler.cxx
index 13d5b29..4ee9e5b 100644 (file)
 // commercial license or contractual agreement.
 
 #include <OpenGl_Sampler.hxx>
-#include <OpenGl_GlCore33.hxx>
+
+#include <OpenGl_ArbSamplerObject.hxx>
+#include <OpenGl_Texture.hxx>
 #include <Standard_Assert.hxx>
 
+IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Sampler,OpenGl_Resource)
 
 // =======================================================================
 // function : OpenGl_Sampler
 // purpose  :
 // =======================================================================
-OpenGl_Sampler::OpenGl_Sampler()
-: mySamplerID (NO_SAMPLER)
+OpenGl_Sampler::OpenGl_Sampler (const Handle(Graphic3d_TextureParams)& theParams)
+: myParams (theParams),
+  mySamplerRevision (0),
+  mySamplerID (NO_SAMPLER),
+  myIsImmutable (false)
 {
-  //
+  if (myParams.IsNull())
+  {
+    myParams = new Graphic3d_TextureParams();
+  }
 }
 
 // =======================================================================
@@ -41,61 +50,86 @@ OpenGl_Sampler::~OpenGl_Sampler()
 // function : Release
 // purpose  :
 // =======================================================================
-void OpenGl_Sampler::Release (OpenGl_Context* theContext)
+void OpenGl_Sampler::Release (OpenGl_Context* theCtx)
 {
-  if (isValidSampler())
+  myIsImmutable = false;
+  mySamplerRevision = myParams->SamplerRevision() - 1;
+  if (!isValidSampler())
   {
-    // application can not handle this case by exception - this is bug in code
-    Standard_ASSERT_RETURN (theContext != NULL,
-      "OpenGl_Sampler destroyed without GL context! Possible GPU memory leakage...",);
+    return;
+  }
 
-    if (theContext->IsValid())
-    {
-    #if !defined(GL_ES_VERSION_2_0) || defined(GL_ES_VERSION_3_0)
-      theContext->core33->glDeleteSamplers (1, &mySamplerID);
-    #endif
-    }
+  // application can not handle this case by exception - this is bug in code
+  Standard_ASSERT_RETURN (theCtx != NULL,
+    "OpenGl_Sampler destroyed without GL context! Possible GPU memory leakage...",);
 
-    mySamplerID = NO_SAMPLER;
+  if (theCtx->IsValid())
+  {
+    theCtx->arbSamplerObject->glDeleteSamplers (1, &mySamplerID);
   }
+
+  mySamplerID = NO_SAMPLER;
 }
 
 // =======================================================================
-// function : Init
-// purpose  : Initializes sampler object
+// function : Create
+// purpose  :
 // =======================================================================
-Standard_Boolean OpenGl_Sampler::Init (OpenGl_Context& theContext)
+Standard_Boolean OpenGl_Sampler::Create (const Handle(OpenGl_Context)& theCtx)
 {
-  if (theContext.core33 == NULL)
+  if (isValidSampler())
+  {
+    return Standard_True;
+  }
+  else if (theCtx->arbSamplerObject == NULL)
   {
     return Standard_False;
   }
 
+  theCtx->arbSamplerObject->glGenSamplers (1, &mySamplerID);
+  return Standard_True;
+}
+
+// =======================================================================
+// function : Init
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_Sampler::Init (const Handle(OpenGl_Context)& theCtx,
+                                       const OpenGl_Texture& theTexture)
+{
   if (isValidSampler())
   {
-    Release (&theContext);
+    if (!ToUpdateParameters())
+    {
+      return Standard_True;
+    }
+    else if (!myIsImmutable)
+    {
+      applySamplerParams (theCtx, myParams, this, theTexture.GetTarget(), theTexture.HasMipmaps());
+      return Standard_True;
+    }
+    Release (theCtx.get());
+  }
+
+  if (!Create (theCtx))
+  {
+    return Standard_False;
   }
 
-#if !defined(GL_ES_VERSION_2_0) || defined(GL_ES_VERSION_3_0)
-  theContext.core33->glGenSamplers (1, &mySamplerID);
+  applySamplerParams (theCtx, myParams, this, theTexture.GetTarget(), theTexture.HasMipmaps());
   return Standard_True;
-#else
-  return Standard_False;
-#endif
 }
 
 // =======================================================================
 // function : Bind
 // purpose  : Binds sampler object to the given texture unit
 // =======================================================================
-void OpenGl_Sampler::Bind (OpenGl_Context& theContext,
-                           const GLuint    theUnit)
+void OpenGl_Sampler::Bind (const Handle(OpenGl_Context)& theCtx,
+                           const Graphic3d_TextureUnit   theUnit)
 {
   if (isValidSampler())
   {
-  #if !defined(GL_ES_VERSION_2_0) || defined(GL_ES_VERSION_3_0)
-    theContext.core33->glBindSampler (theUnit, mySamplerID);
-  #endif
+    theCtx->arbSamplerObject->glBindSampler (theUnit, mySamplerID);
   }
 }
 
@@ -103,29 +137,295 @@ void OpenGl_Sampler::Bind (OpenGl_Context& theContext,
 // function : Unbind
 // purpose  : Unbinds sampler object from the given texture unit
 // =======================================================================
-void OpenGl_Sampler::Unbind (OpenGl_Context& theContext,
-                             const GLuint    theUnit)
+void OpenGl_Sampler::Unbind (const Handle(OpenGl_Context)& theCtx,
+                             const Graphic3d_TextureUnit   theUnit)
 {
   if (isValidSampler())
   {
-  #if !defined(GL_ES_VERSION_2_0) || defined(GL_ES_VERSION_3_0)
-    theContext.core33->glBindSampler (theUnit, NO_SAMPLER);
-  #endif
+    theCtx->arbSamplerObject->glBindSampler (theUnit, NO_SAMPLER);
   }
 }
 
 // =======================================================================
-// function : SetParameter
-// purpose  : Sets sampler parameters
+// function : setParameter
+// purpose  :
 // =======================================================================
-void OpenGl_Sampler::SetParameter (OpenGl_Context& theContext,
-                                   const GLenum    theParam,
-                                   const GLint     theValue)
+void OpenGl_Sampler::setParameter (const Handle(OpenGl_Context)& theCtx,
+                                   OpenGl_Sampler* theSampler,
+                                   GLenum theTarget,
+                                   GLenum theParam,
+                                   GLint  theValue)
 {
-  if (isValidSampler())
+  if (theSampler != NULL && theSampler->isValidSampler())
+  {
+    theCtx->arbSamplerObject->glSamplerParameteri (theSampler->mySamplerID, theParam, theValue);
+  }
+  else
+  {
+    theCtx->core11fwd->glTexParameteri (theTarget, theParam, theValue);
+  }
+}
+
+// =======================================================================
+// function : SetParameters
+// purpose  :
+// =======================================================================
+void OpenGl_Sampler::SetParameters (const Handle(Graphic3d_TextureParams)& theParams)
+{
+  if (myParams != theParams)
+  {
+    myParams = theParams;
+    mySamplerRevision = myParams->SamplerRevision() - 1;
+  }
+}
+
+// =======================================================================
+// function : applySamplerParams
+// purpose  :
+// =======================================================================
+void OpenGl_Sampler::applySamplerParams (const Handle(OpenGl_Context)& theCtx,
+                                         const Handle(Graphic3d_TextureParams)& theParams,
+                                         OpenGl_Sampler* theSampler,
+                                         const GLenum theTarget,
+                                         const bool theHasMipMaps)
+{
+  if (theSampler != NULL && theSampler->Parameters() == theParams)
+  {
+    theSampler->mySamplerRevision = theParams->SamplerRevision();
+  }
+
+  // setup texture filtering
+  const GLenum aFilter = (theParams->Filter() == Graphic3d_TOTF_NEAREST) ? GL_NEAREST : GL_LINEAR;
+  GLenum aFilterMin = aFilter;
+  if (theHasMipMaps)
+  {
+    aFilterMin = GL_NEAREST_MIPMAP_NEAREST;
+    if (theParams->Filter() == Graphic3d_TOTF_BILINEAR)
+    {
+      aFilterMin = GL_LINEAR_MIPMAP_NEAREST;
+    }
+    else if (theParams->Filter() == Graphic3d_TOTF_TRILINEAR)
+    {
+      aFilterMin = GL_LINEAR_MIPMAP_LINEAR;
+    }
+  }
+
+  setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_MIN_FILTER, aFilterMin);
+  setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_MAG_FILTER, aFilter);
+
+  // setup texture wrapping
+  const GLenum aWrapMode = theParams->IsRepeat() ? GL_REPEAT : theCtx->TextureWrapClamp();
+  setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_WRAP_S, aWrapMode);
+#if !defined(GL_ES_VERSION_2_0)
+  if (theTarget == GL_TEXTURE_1D)
   {
-  #if !defined(GL_ES_VERSION_2_0) || defined(GL_ES_VERSION_3_0)
-    theContext.core33->glSamplerParameteri (mySamplerID, theParam, theValue);
-  #endif
+    return;
   }
+#endif
+  setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_WRAP_T, aWrapMode);
+  if (theTarget == GL_TEXTURE_3D)
+  {
+    setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_WRAP_R, aWrapMode);
+    return;
+  }
+
+  if (theCtx->extAnis)
+  {
+    // setup degree of anisotropy filter
+    const GLint aMaxDegree = theCtx->MaxDegreeOfAnisotropy();
+    GLint aDegree;
+    switch (theParams->AnisoFilter())
+    {
+      case Graphic3d_LOTA_QUALITY:
+      {
+        aDegree = aMaxDegree;
+        break;
+      }
+      case Graphic3d_LOTA_MIDDLE:
+      {
+        aDegree = (aMaxDegree <= 4) ? 2 : (aMaxDegree / 2);
+        break;
+      }
+      case Graphic3d_LOTA_FAST:
+      {
+        aDegree = 2;
+        break;
+      }
+      case Graphic3d_LOTA_OFF:
+      default:
+      {
+        aDegree = 1;
+        break;
+      }
+    }
+
+    setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, aDegree);
+  }
+}
+
+// =======================================================================
+// function : applyGlobalTextureParams
+// purpose  :
+// =======================================================================
+void OpenGl_Sampler::applyGlobalTextureParams (const Handle(OpenGl_Context)& theCtx,
+                                               const OpenGl_Texture& theTexture,
+                                               const Handle(Graphic3d_TextureParams)& theParams)
+{
+#if defined(GL_ES_VERSION_2_0)
+  (void )theCtx;
+  (void )theTexture;
+  (void )theParams;
+#else
+  if (theCtx->core11 == NULL)
+  {
+    return;
+  }
+
+  GLint anEnvMode = GL_MODULATE; // lighting mode
+  if (!theParams->IsModulate())
+  {
+    anEnvMode = GL_DECAL;
+    if (theTexture.GetFormat() == GL_ALPHA
+     || theTexture.GetFormat() == GL_LUMINANCE)
+    {
+      anEnvMode = GL_REPLACE;
+    }
+  }
+
+  // setup generation of texture coordinates
+  switch (theParams->GenMode())
+  {
+    case Graphic3d_TOTM_OBJECT:
+    {
+      theCtx->core11->glTexGeni  (GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+      theCtx->core11->glTexGenfv (GL_S, GL_OBJECT_PLANE,     theParams->GenPlaneS().GetData());
+      if (theTexture.GetTarget() != GL_TEXTURE_1D)
+      {
+        theCtx->core11->glTexGeni  (GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+        theCtx->core11->glTexGenfv (GL_T, GL_OBJECT_PLANE,     theParams->GenPlaneT().GetData());
+      }
+      break;
+    }
+    case Graphic3d_TOTM_SPHERE:
+    {
+      theCtx->core11->glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
+      if (theTexture.GetTarget() != GL_TEXTURE_1D)
+      {
+        theCtx->core11->glTexGeni (GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
+      }
+      break;
+    }
+    case Graphic3d_TOTM_EYE:
+    {
+      theCtx->WorldViewState.Push();
+      theCtx->WorldViewState.SetIdentity();
+      theCtx->ApplyWorldViewMatrix();
+
+      theCtx->core11->glTexGeni  (GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+      theCtx->core11->glTexGenfv (GL_S, GL_EYE_PLANE,        theParams->GenPlaneS().GetData());
+      if (theTexture.GetTarget() != GL_TEXTURE_1D)
+      {
+        theCtx->core11->glTexGeni  (GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+        theCtx->core11->glTexGenfv (GL_T, GL_EYE_PLANE,        theParams->GenPlaneT().GetData());
+      }
+
+      theCtx->WorldViewState.Pop();
+      break;
+    }
+    case Graphic3d_TOTM_SPRITE:
+    {
+      if (theCtx->core20fwd != NULL)
+      {
+        theCtx->core11fwd->glEnable (GL_POINT_SPRITE);
+        glTexEnvi (GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
+        anEnvMode = GL_REPLACE;
+      }
+      break;
+    }
+    case Graphic3d_TOTM_MANUAL:
+    default: break;
+  }
+
+  // setup lighting
+  glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, anEnvMode);
+
+  switch (theTexture.GetTarget())
+  {
+    case GL_TEXTURE_1D:
+    {
+      if (theParams->GenMode() != Graphic3d_TOTM_MANUAL)
+      {
+        theCtx->core11fwd->glEnable (GL_TEXTURE_GEN_S);
+      }
+      theCtx->core11fwd->glEnable (GL_TEXTURE_1D);
+      break;
+    }
+    case GL_TEXTURE_2D:
+    {
+      if (theParams->GenMode() != Graphic3d_TOTM_MANUAL)
+      {
+        theCtx->core11fwd->glEnable (GL_TEXTURE_GEN_S);
+        theCtx->core11fwd->glEnable (GL_TEXTURE_GEN_T);
+      }
+      theCtx->core11fwd->glEnable (GL_TEXTURE_2D);
+      break;
+    }
+    default: break;
+  }
+#endif
+}
+
+// =======================================================================
+// function : resetGlobalTextureParams
+// purpose  :
+// =======================================================================
+void OpenGl_Sampler::resetGlobalTextureParams (const Handle(OpenGl_Context)& theCtx,
+                                               const OpenGl_Texture& theTexture,
+                                               const Handle(Graphic3d_TextureParams)& theParams)
+{
+#if defined(GL_ES_VERSION_2_0)
+  (void )theCtx;
+  (void )theTexture;
+  (void )theParams;
+#else
+  if (theCtx->core11 == NULL)
+  {
+    return;
+  }
+
+  // reset texture matrix because some code may expect it is identity
+  GLint aMatrixMode = GL_TEXTURE;
+  theCtx->core11fwd->glGetIntegerv (GL_MATRIX_MODE, &aMatrixMode);
+  theCtx->core11->glMatrixMode (GL_TEXTURE);
+  theCtx->core11->glLoadIdentity();
+  theCtx->core11->glMatrixMode (aMatrixMode);
+
+  switch (theTexture.GetTarget())
+  {
+    case GL_TEXTURE_1D:
+    {
+      if (theParams->GenMode() != GL_NONE)
+      {
+        theCtx->core11fwd->glDisable (GL_TEXTURE_GEN_S);
+      }
+      theCtx->core11fwd->glDisable (GL_TEXTURE_1D);
+      break;
+    }
+    case GL_TEXTURE_2D:
+    {
+      if (theParams->GenMode() != GL_NONE)
+      {
+        theCtx->core11fwd->glDisable (GL_TEXTURE_GEN_S);
+        theCtx->core11fwd->glDisable (GL_TEXTURE_GEN_T);
+        if (theParams->GenMode() == Graphic3d_TOTM_SPRITE)
+        {
+          theCtx->core11fwd->glDisable (GL_POINT_SPRITE);
+        }
+      }
+      theCtx->core11fwd->glDisable (GL_TEXTURE_2D);
+      break;
+    }
+    default: break;
+  }
+#endif
 }