0030807: Visualization, TKOpenGl - supporting cubemaps
[occt.git] / src / OpenGl / OpenGl_Texture.cxx
index a87bb9f..6a354d1 100644 (file)
@@ -182,7 +182,7 @@ bool OpenGl_Texture::InitSamplerObject (const Handle(OpenGl_Context)& theCtx)
 //purpose  :
 //=======================================================================
 bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx,
-                                    const Image_PixMap&           theData,
+                                    const Image_Format            theFormat,
                                     GLint&                        theTextFormat,
                                     GLenum&                       thePixelFormat,
                                     GLenum&                       theDataType)
@@ -190,7 +190,7 @@ bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx,
   theTextFormat  = GL_RGBA8;
   thePixelFormat = 0;
   theDataType    = 0;
-  switch (theData.Format())
+  switch (theFormat)
   {
     case Image_Format_GrayF:
     {
@@ -733,6 +733,12 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
       Unbind (theCtx);
       return true;
     }
+    case Graphic3d_TOT_CUBEMAP:
+    {
+      Unbind (theCtx);
+      Release (theCtx.get());
+      return false;
+    }
   }
 
   Release (theCtx.operator->());
@@ -769,6 +775,36 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
                theType, &theImage);
 }
 
+// =======================================================================
+// function : Init
+// purpose  :
+// =======================================================================
+bool OpenGl_Texture::Init (const Handle(OpenGl_Context)&       theCtx,
+                           const Handle(Graphic3d_TextureMap)& theTextureMap)
+{
+  if (theTextureMap.IsNull())
+  {
+    return false;
+  }
+
+  switch (theTextureMap->Type())
+  {
+    case Graphic3d_TOT_CUBEMAP:
+    {
+      return InitCubeMap (theCtx, Handle(Graphic3d_CubeMap)::DownCast(theTextureMap));
+    }
+    default:
+    {
+      Handle(Image_PixMap) anImage = theTextureMap->GetImage();
+      if (anImage.IsNull())
+      {
+        return false;
+      }
+      return Init (theCtx, *anImage, theTextureMap->Type());
+    }
+  }
+}
+
 // =======================================================================
 // function : Init2DMultisample
 // purpose  :
@@ -997,6 +1033,141 @@ bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
   return true;
 }
 
+// =======================================================================
+// function : InitCubeMap
+// purpose  :
+// =======================================================================
+bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)&    theCtx,
+                                  const Handle(Graphic3d_CubeMap)& theCubeMap,
+                                  Standard_Size                    theSize,
+                                  Image_Format                     theFormat,
+                                  Standard_Boolean                 theToGenMipmap)
+{
+  if (!Create (theCtx))
+  {
+    Release (theCtx.get());
+    return false;
+  }
+
+  if (!theCubeMap.IsNull())
+  {
+    Handle(Image_PixMap) anImage = theCubeMap->Reset().Value();
+    if (!anImage.IsNull())
+    {
+      theSize   = anImage->SizeX();
+      theFormat = anImage->Format();
+    }
+    else
+    {
+      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+        "Unable to get the first side of cubemap");
+      Release(theCtx.get());
+      return false;
+    }
+  }
+
+  GLenum aPixelFormat = GL_RGB;
+  GLenum aDataType = 0;
+  GLint aTextFormat = 0;
+
+  if (!GetDataFormat (theCtx, theFormat, aTextFormat, aPixelFormat, aDataType))
+  {
+    Unbind(theCtx);
+    Release(theCtx.get());
+    return false;
+  }
+
+  myTarget = GL_TEXTURE_CUBE_MAP;
+  myHasMipmaps = theToGenMipmap;
+  myNbSamples = 1;
+  Bind (theCtx);
+  applyDefaultSamplerParams (theCtx);
+
+  for (Standard_Integer i = 0; i < 6; ++i)
+  {
+    const void* aData = NULL;
+    Handle(Image_PixMap) anImage;
+
+    if (!theCubeMap.IsNull())
+    {
+      anImage = theCubeMap->Value();
+      if (!anImage.IsNull())
+      {
+#if !defined(GL_ES_VERSION_2_0)
+        const GLint anAligment = Min ((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
+        glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
+
+        // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
+        const GLint anExtraBytes = GLint(anImage->RowExtraBytes());
+        const GLint aPixelsWidth = GLint(anImage->SizeRowBytes() / anImage->SizePixelBytes());
+        const GLint aRowLength = (anExtraBytes >= anAligment) ? aPixelsWidth : 0;
+        glPixelStorei (GL_UNPACK_ROW_LENGTH, aRowLength);
+#else
+        Handle(Image_PixMap) aCopyImage = new Image_PixMap();
+        aCopyImage->InitTrash (theFormat, theSize, theSize);
+        for (unsigned int y = 0; y < theSize; ++y)
+        {
+          for (unsigned int x = 0; x < theSize; ++x)
+          {
+            for (unsigned int aByte = 0; aByte < anImage->SizePixelBytes(); ++aByte)
+            {
+              aCopyImage->ChangeRawValue (y, x)[aByte] = anImage->RawValue (y, x)[aByte];
+            }
+          }
+        }
+        anImage = aCopyImage;
+        const GLint anAligment = Min((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
+        glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
+#endif
+        aData = anImage->Data();
+      }
+      else
+      {
+        theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, TCollection_AsciiString() +
+          "Unable to get [" + i + "] side of cubemap");
+        Unbind (theCtx);
+        Release (theCtx.get());
+        return false;
+      }
+      theCubeMap->Next();
+    }
+
+    glTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0,
+                  aTextFormat,
+                  GLsizei(theSize), GLsizei(theSize),
+                  0, aPixelFormat, aDataType,
+                  aData);
+
+    OpenGl_UnpackAlignmentSentry::Reset();
+
+    if (glGetError() != GL_NO_ERROR)
+    {
+      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+        "Unable to initialize side of cubemap");
+      Unbind (theCtx);
+      Release (theCtx.get());
+      return false;
+    }
+  }
+
+  if (theToGenMipmap && theCtx->arbFBO != NULL)
+  {
+      theCtx->arbFBO->glGenerateMipmap (myTarget);
+
+      if (glGetError() != GL_NO_ERROR)
+      {
+        theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+          "Unable to generate mipmap of cubemap");
+        Unbind(theCtx);
+        Release(theCtx.get());
+        return false;
+      }
+  }
+
+  Unbind (theCtx.get());
+  return true;
+}
+
 // =======================================================================
 // function : PixelSizeOfPixelFormat
 // purpose  :