0031478: Visualization, TKOpenGl - allow uploading Cubemap in compressed DDS format...
authorkgv <kgv@opencascade.com>
Fri, 15 May 2020 23:47:20 +0000 (02:47 +0300)
committerbugmaster <bugmaster@opencascade.com>
Fri, 22 May 2020 08:08:34 +0000 (11:08 +0300)
Graphic3d_TextureRoot::GetCompressedImage() - added new interface for fetching compressed texture image.
Default implementation detects DDS image files using Image_DDSParser parser.

Graphic3d_TextureRoot::GetImage() has been extended with new parameter
- the list of image formats supported by OpenGL driver.
Graphic3d_TextureRoot::convertToCompatible() implicitly converts
BGRA image to RGBA on OpenGL ES, which normally does not support BGR formats.

OpenGl_Caps::isTopDownTextureUV - new property defines how application defines
UV texture coordinates in primitive arrays.
OpenGl_Context::SetTextureMatrix() compares this flag with OpenGl_Texture::IsTopDown()
and automatically flips V coordinate in case of mismatch.

OpenGl_Texture now holds exact number of mipmap levels
instead of Boolean flag indicating that they are defined.
This allows loading DDS files with incomplete mipmap level set
by setting GL_TEXTURE_MAX_LEVEL to appropriate value instead of default 1000
(causing black textures in case if mipmap levels are not defined till 1x1).

Fixed order of texture coordinates transformation within GLSL program to match FFP matrix:
Rotate -> Translate -> Scale (previously Rotation was applied afterwards).

45 files changed:
samples/mfc/standard/Common/Primitive/Sample2D_Image.cpp
src/AIS/AIS_XRTrackedDevice.cxx
src/Aspect/Aspect_OpenVRSession.cxx
src/Graphic3d/Graphic3d_CubeMap.hxx
src/Graphic3d/Graphic3d_CubeMapPacked.cxx
src/Graphic3d/Graphic3d_CubeMapPacked.hxx
src/Graphic3d/Graphic3d_CubeMapSeparate.cxx
src/Graphic3d/Graphic3d_CubeMapSeparate.hxx
src/Graphic3d/Graphic3d_MediaTexture.cxx
src/Graphic3d/Graphic3d_MediaTexture.hxx
src/Graphic3d/Graphic3d_TextureParams.hxx
src/Graphic3d/Graphic3d_TextureRoot.cxx
src/Graphic3d/Graphic3d_TextureRoot.hxx
src/Image/FILES
src/Image/Image_CompressedFormat.hxx [new file with mode: 0644]
src/Image/Image_CompressedPixMap.hxx [new file with mode: 0644]
src/Image/Image_DDSParser.cxx [new file with mode: 0644]
src/Image/Image_DDSParser.hxx [new file with mode: 0644]
src/Image/Image_Format.hxx
src/Image/Image_PixMap.cxx
src/Image/Image_PixMap.hxx
src/Image/Image_SupportedFormats.cxx [new file with mode: 0644]
src/Image/Image_SupportedFormats.hxx [new file with mode: 0644]
src/Image/Image_Texture.cxx
src/Image/Image_Texture.hxx
src/OpenGl/OpenGl_Caps.cxx
src/OpenGl/OpenGl_Caps.hxx
src/OpenGl/OpenGl_Context.cxx
src/OpenGl/OpenGl_Context.hxx
src/OpenGl/OpenGl_GlFunctions.hxx
src/OpenGl/OpenGl_PrimitiveArray.cxx
src/OpenGl/OpenGl_Sampler.cxx
src/OpenGl/OpenGl_Sampler.hxx
src/OpenGl/OpenGl_ShaderManager.cxx
src/OpenGl/OpenGl_Texture.cxx
src/OpenGl/OpenGl_Texture.hxx
src/OpenGl/OpenGl_TextureFormat.cxx
src/OpenGl/OpenGl_TextureFormat.hxx
src/OpenGl/OpenGl_View.cxx
src/ViewerTest/ViewerTest_ViewerCommands.cxx
src/XCAFPrs/XCAFPrs_Texture.cxx
src/XCAFPrs/XCAFPrs_Texture.hxx
tests/v3d/glsl/cubemap_dds [new file with mode: 0644]
tests/v3d/glsl/texture_trsf2
tests/v3d/glsl/texture_trsf3 [new file with mode: 0644]

index 549790f..957791b 100755 (executable)
@@ -3,6 +3,7 @@
 #include "Sample2D_Image.h"
 
 #include <Graphic3d_Texture2Dmanual.hxx>
+#include <Image_AlienPixMap.hxx>
 
 IMPLEMENT_STANDARD_RTTIEXT(Sample2D_Image,AIS_Shape)
 
@@ -19,10 +20,13 @@ Sample2D_Image::Sample2D_Image(TCollection_AsciiString& aFileName,
 }
 void Sample2D_Image::MakeShape()
 {
-  Handle(Graphic3d_Texture1D) anImageTexture = 
-    new Graphic3d_Texture1Dsegment(myFilename);
-  Standard_Real coeff = (Standard_Real)(anImageTexture->GetImage()->Height())/
-    (anImageTexture->GetImage()->Width())*myScale;
+  Standard_Real coeff = 1.0;
+  Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap();
+  if (anImage->Load (myFilename))
+  {
+    coeff = Standard_Real(anImage->Height()) / Standard_Real(anImage->Width()) * myScale;
+  }
+
   TopoDS_Edge E1 = BRepBuilderAPI_MakeEdge(gp_Pnt(myX,myY,0.), gp_Pnt(100*myScale+myX,myY,0.));
   TopoDS_Edge E2 = BRepBuilderAPI_MakeEdge(gp_Pnt(100*myScale+myX,myY,0.), gp_Pnt(100*myScale+myX,100*coeff+myY,0.));
   TopoDS_Edge E3 = BRepBuilderAPI_MakeEdge(gp_Pnt(100*myScale+myX,100*coeff+myY,0.), gp_Pnt(myX,100*coeff+myY,0.));
index c60f4ad..345d63a 100644 (file)
@@ -43,7 +43,10 @@ public:
   }
 
   //! Image reader.
-  virtual Handle(Image_PixMap) GetImage() const Standard_OVERRIDE { return myImageSource->ReadImage(); }
+  virtual Handle(Image_PixMap) GetImage (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE
+  {
+    return myImageSource->ReadImage (theSupported);
+  }
 
 protected:
   Handle(Image_Texture) myImageSource;
index bd5888c..d04f729 100644 (file)
@@ -261,7 +261,7 @@ public:
 
 protected:
   //! Read image.
-  virtual Handle(Image_PixMap) ReadImage() const Standard_OVERRIDE
+  virtual Handle(Image_PixMap) ReadImage (const Handle(Image_SupportedFormats)& ) const Standard_OVERRIDE
   {
     Handle(VRImagePixmap) aPixmap = new VRImagePixmap();
     if (!aPixmap->Load (myVrTextureId, myVrModelName))
index 494ce29..52473ee 100644 (file)
@@ -31,7 +31,6 @@ public:
     Graphic3d_TextureMap (theFileName, Graphic3d_TOT_CUBEMAP),
     myCurrentSide  (Graphic3d_CMS_POS_X),
     myEndIsReached (false),
-    myIsTopDown    (true),
     myZIsInverted  (false),
     myHasMipmaps   (theToGenerateMipmaps)
   {}
@@ -42,7 +41,6 @@ public:
     Graphic3d_TextureMap (thePixmap, Graphic3d_TOT_CUBEMAP),
     myCurrentSide  (Graphic3d_CMS_POS_X),
     myEndIsReached (false),
-    myIsTopDown    (true),
     myZIsInverted  (false),
     myHasMipmaps   (theToGenerateMipmaps)
   {}
@@ -67,12 +65,6 @@ public:
     }
   }
 
-  //! Returns whether row's memory layout is top-down.
-  Standard_Boolean IsTopDown() const
-  {
-    return myIsTopDown;
-  }
-
   //! Sets Z axis inversion (vertical flipping).
   void SetZInversion (Standard_Boolean theZIsInverted)
   {
@@ -91,9 +83,13 @@ public:
   //! Sets whether to generate mipmaps of cubemap or not.
   void SetMipmapsGeneration (Standard_Boolean theToGenerateMipmaps) { myHasMipmaps = theToGenerateMipmaps; }
 
+  //! Returns current cubemap side as compressed PixMap.
+  //! Returns null handle if current side is invalid or if image is not in supported compressed format.
+  virtual Handle(Image_CompressedPixMap) CompressedValue (const Handle(Image_SupportedFormats)& theSupported) = 0;
+
   //! Returns PixMap containing current side of cubemap.
   //! Returns null handle if current side is invalid.
-  virtual Handle(Image_PixMap) Value() = 0;
+  virtual Handle(Image_PixMap) Value (const Handle(Image_SupportedFormats)& theSupported) = 0;
 
   //! Sets iterator state to +X cubemap side.
   Graphic3d_CubeMap& Reset()
@@ -110,7 +106,6 @@ protected:
 
   Graphic3d_CubeMapSide myCurrentSide;  //!< Iterator state
   Standard_Boolean      myEndIsReached; //!< Indicates whether end of iteration has been reached or hasn't
-  Standard_Boolean      myIsTopDown;    //!< Stores rows's memory layout
   Standard_Boolean      myZIsInverted;  //!< Indicates whether Z axis is inverted that allows to synchronize vertical flip of cubemap
   Standard_Boolean      myHasMipmaps;   //!< Indicates whether mipmaps of cubemap will be generated or not
 
index ac57c48..2f9e180 100644 (file)
@@ -13,7 +13,9 @@
 // commercial license or contractual agreement.
 
 #include <Graphic3d_CubeMapPacked.hxx>
+
 #include <Image_AlienPixMap.hxx>
+#include <Image_DDSParser.hxx>
 
 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_CubeMapPacked, Graphic3d_CubeMap)
 
@@ -40,17 +42,46 @@ Graphic3d_CubeMapPacked::Graphic3d_CubeMapPacked (const Handle(Image_PixMap)&
   myOrder           (theOrder),
   myTileNumberX     (1)
 {
-    if (checkImage (theImage, myTileNumberX))
+  if (checkImage (theImage, myTileNumberX))
+  {
+    myPixMap = theImage;
+  }
+}
+
+// =======================================================================
+// function : CompressedValue
+// purpose  :
+// =======================================================================
+Handle(Image_CompressedPixMap) Graphic3d_CubeMapPacked::CompressedValue (const Handle(Image_SupportedFormats)& theSupported)
+{
+  if (myTileNumberX == 0
+  || !myPixMap.IsNull())
+  {
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  TCollection_AsciiString aFilePath;
+  myPath.SystemName (aFilePath);
+  if (!aFilePath.IsEmpty())
+  {
+    const unsigned int aTileIndex = myOrder[myCurrentSide];
+    Handle(Image_CompressedPixMap) anImage = Image_DDSParser::Load (theSupported, aFilePath, (Standard_Integer )aTileIndex);
+    if (!anImage.IsNull()
+      && anImage->NbFaces() == 6
+      && anImage->SizeX() == anImage->SizeY())
     {
-      myPixMap = theImage;
+      myIsTopDown = anImage->IsTopDown();
+      return anImage;
     }
+  }
+  return Handle(Image_CompressedPixMap)();
 }
 
 // =======================================================================
 // function : Value
 // purpose  :
 // =======================================================================
-Handle(Image_PixMap) Graphic3d_CubeMapPacked::Value()
+Handle(Image_PixMap) Graphic3d_CubeMapPacked::Value (const Handle(Image_SupportedFormats)& theSupported)
 {
   if (myTileNumberX != 0)
   {
@@ -60,7 +91,7 @@ Handle(Image_PixMap) Graphic3d_CubeMapPacked::Value()
       myPath.SystemName (aFilePath);
       if (!aFilePath.IsEmpty())
       {
-        tryLoadImage (aFilePath);
+        tryLoadImage (theSupported, aFilePath);
       }
     }
 
@@ -183,13 +214,15 @@ Standard_Boolean Graphic3d_CubeMapPacked::checkImage (const Handle(Image_PixMap)
 // function : tryLoadImage
 // purpose  :
 // =======================================================================
-void Graphic3d_CubeMapPacked::tryLoadImage (const TCollection_AsciiString& theFilePath)
+void Graphic3d_CubeMapPacked::tryLoadImage (const Handle(Image_SupportedFormats)& theSupported,
+                                            const TCollection_AsciiString& theFilePath)
 {
   Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap;
   if (anImage->Load (theFilePath))
   {
     if (checkImage (anImage, myTileNumberX))
     {
+      convertToCompatible (theSupported, anImage);
       myPixMap = anImage;
     }
   }
index 4a6da46..41a4f94 100644 (file)
@@ -25,23 +25,26 @@ class Graphic3d_CubeMapPacked : public Graphic3d_CubeMap
   DEFINE_STANDARD_RTTIEXT(Graphic3d_CubeMapPacked, Graphic3d_CubeMap)
 public:
 
-  //! Initialization to load cubemef from file.
+  //! Initialization to load cubemap from file.
   //! @theFileName - path to the cubemap image
-  //! @theOrder - array conaining six different indexes of cubemap sides which maps tile grid to cubemap sides
+  //! @theOrder - array containing six different indexes of cubemap sides which maps tile grid to cubemap sides
   Standard_EXPORT Graphic3d_CubeMapPacked (const TCollection_AsciiString&        theFileName,
                                            const Graphic3d_ValidatedCubeMapOrder theOrder = Graphic3d_CubeMapOrder::Default());
 
   //! Initialization to set cubemap directly by PixMap.
   //! @thePixMap - origin PixMap
-  //! @theOrder - array conaining six different indexes of cubemap sides which maps tile grid to cubemap sides
+  //! @theOrder - array containing six different indexes of cubemap sides which maps tile grid to cubemap sides
   Standard_EXPORT Graphic3d_CubeMapPacked (const Handle(Image_PixMap)&           theImage,
                                            const Graphic3d_ValidatedCubeMapOrder theOrder = Graphic3d_CubeMapOrder::Default());
 
+  //! Returns current cubemap side as compressed PixMap.
+  Standard_EXPORT virtual Handle(Image_CompressedPixMap) CompressedValue (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE;
+
   //! Returns current cubemap side as PixMap.
   //! Resulting PixMap is memory wrapper over original image.
   //! Returns null handle if current side or whole cubemap is invalid.
   //! Origin image has to contain six quad tiles having one sizes without any gaps to be valid.  
-  Standard_EXPORT Handle(Image_PixMap) Value() Standard_OVERRIDE;
+  Standard_EXPORT virtual Handle(Image_PixMap) Value (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE;
 
   //! Empty destructor.
   ~Graphic3d_CubeMapPacked() {}
@@ -57,7 +60,8 @@ private:
 
   //! Tries to load image from file and checks it after that.
   //! Does nothing in case of fail.
-  void tryLoadImage (const TCollection_AsciiString &theFilePath);
+  void tryLoadImage (const Handle(Image_SupportedFormats)& theSupported,
+                     const TCollection_AsciiString &theFilePath);
 
 protected:
 
index 896c0ee..2646d2f 100644 (file)
@@ -13,7 +13,9 @@
 // commercial license or contractual agreement.
 
 #include <Graphic3d_CubeMapSeparate.hxx>
+
 #include <Image_AlienPixMap.hxx>
+#include <Image_DDSParser.hxx>
 #include <Message.hxx>
 #include <Message_Messenger.hxx>
 #include <OSD_File.hxx>
@@ -84,10 +86,54 @@ Graphic3d_CubeMapSeparate::Graphic3d_CubeMapSeparate (const NCollection_Array1<H
 }
 
 // =======================================================================
+// function : CompressedValue
+// purpose  :
+// =======================================================================
+Handle(Image_CompressedPixMap) Graphic3d_CubeMapSeparate::CompressedValue (const Handle(Image_SupportedFormats)& theSupported)
+{
+  if (!myImages[0].IsNull())
+  {
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  const Graphic3d_CubeMapOrder anOrder = Graphic3d_CubeMapOrder::Default();
+  TCollection_AsciiString aFilePath;
+  myPaths[anOrder[myCurrentSide]].SystemName(aFilePath);
+  if (aFilePath.IsEmpty())
+  {
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  Handle(Image_CompressedPixMap) anImage = Image_DDSParser::Load (theSupported, aFilePath, 0);
+  if (anImage.IsNull()
+   || anImage->SizeX() != anImage->SizeY())
+  {
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  if (myCurrentSide == 0)
+  {
+    mySize =   anImage->SizeX();
+    myFormat = anImage->BaseFormat();
+    myIsTopDown = anImage->IsTopDown();
+    return anImage;
+  }
+
+  if (anImage->BaseFormat() == myFormat
+   && anImage->SizeX() == (Standard_Integer )mySize)
+  {
+    return anImage;
+  }
+
+  Message::SendWarning (TCollection_AsciiString() + "'" + aFilePath + "' inconsistent image format or dimension in Graphic3d_CubeMapSeparate");
+  return Handle(Image_CompressedPixMap)();
+}
+
+// =======================================================================
 // function : Value
 // purpose  :
 // =======================================================================
-Handle(Image_PixMap) Graphic3d_CubeMapSeparate::Value()
+Handle(Image_PixMap) Graphic3d_CubeMapSeparate::Value (const Handle(Image_SupportedFormats)& theSupported)
 {
   Graphic3d_CubeMapOrder anOrder = Graphic3d_CubeMapOrder::Default();
   if (!myIsTopDown)
@@ -108,6 +154,7 @@ Handle(Image_PixMap) Graphic3d_CubeMapSeparate::Value()
       Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap;
       if (anImage->Load(aFilePath))
       {
+        convertToCompatible (theSupported, anImage);
         if (anImage->SizeX() == anImage->SizeY())
         {
           if (myCurrentSide == 0)
index 6f0012d..74f72c5 100644 (file)
@@ -33,13 +33,16 @@ public:
   //! @theImages - array if PixMaps (has to have size equal 6).
   Standard_EXPORT Graphic3d_CubeMapSeparate(const NCollection_Array1<Handle(Image_PixMap)>& theImages);
 
+  //! Returns current cubemap side as compressed PixMap.
+  Standard_EXPORT virtual Handle(Image_CompressedPixMap) CompressedValue (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE;
+
   //! Returns current side of cubemap as PixMap.
   //! Returns null handle if current side or whole cubemap is invalid.
   //! All origin images have to have the same sizes, format and quad shapes to form valid cubemap.
-  Standard_EXPORT Handle(Image_PixMap) Value() Standard_OVERRIDE;
+  Standard_EXPORT virtual Handle(Image_PixMap) Value (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE;
 
   //! Returns NULL.
-  virtual Handle(Image_PixMap) GetImage() const Standard_OVERRIDE
+  virtual Handle(Image_PixMap) GetImage (const Handle(Image_SupportedFormats)& ) Standard_OVERRIDE
   {
     return Handle(Image_PixMap)();
   }
index cb23f01..46a987c 100644 (file)
@@ -56,7 +56,7 @@ Graphic3d_MediaTexture::Graphic3d_MediaTexture (const Handle(Media_HMutex)& theM
 // Function : GetImage
 // Purpose  :
 // ================================================================
-Handle(Image_PixMap) Graphic3d_MediaTexture::GetImage() const
+Handle(Image_PixMap) Graphic3d_MediaTexture::GetImage (const Handle(Image_SupportedFormats)& )
 {
   Standard_Mutex::Sentry aLock (myMutex.get());
   if (myFrame.IsNull()
index bf74e92..c081e47 100644 (file)
@@ -34,7 +34,7 @@ public:
                                           Standard_Integer thePlane = -1);
 
   //! Image reader.
-  Standard_EXPORT virtual Handle(Image_PixMap) GetImage() const Standard_OVERRIDE;
+  Standard_EXPORT virtual Handle(Image_PixMap) GetImage (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE;
 
   //! Return the frame.
   const Handle(Media_Frame)& Frame() const { return myFrame; }
index e2c44b2..672275b 100644 (file)
@@ -72,22 +72,22 @@ public:
   //! @param theLevel level of anisontropy texture filter.
   Standard_EXPORT void SetAnisoFilter (const Graphic3d_LevelOfTextureAnisotropy theLevel);
   
-  //! @return rotation angle in degrees
-  //! Default value is 0.
+  //! Return rotation angle in degrees; 0 by default.
+  //! Complete transformation matrix: Rotation -> Translation -> Scale.
   Standard_ShortReal Rotation() const { return myRotAngle; }
   
   //! @param theAngleDegrees rotation angle.
   Standard_EXPORT void SetRotation (const Standard_ShortReal theAngleDegrees);
   
-  //! @return scale factor
-  //! Default value is no scaling (1.0; 1.0).
+  //! Return scale factor; (1.0; 1.0) by default, which means no scaling.
+  //! Complete transformation matrix: Rotation -> Translation -> Scale.
   const Graphic3d_Vec2& Scale() const { return myScale; }
   
   //! @param theScale scale factor.
   Standard_EXPORT void SetScale (const Graphic3d_Vec2 theScale);
-  
-  //! @return translation vector
-  //! Default value is no translation (0.0; 0.0).
+
+  //! Return translation vector; (0.0; 0.0), which means no translation.
+  //! Complete transformation matrix: Rotation -> Translation -> Scale.
   const Graphic3d_Vec2& Translation() const { return myTranslation; }
   
   //! @param theVec translation vector.
@@ -109,7 +109,8 @@ public:
   //! @return base texture mipmap level; 0 by default.
   Standard_Integer BaseLevel() const { return myBaseLevel; }
 
-  //! @return maximum texture mipmap array level; 1000 by default.
+  //! Return maximum texture mipmap array level; 1000 by default.
+  //! Real rendering limit will take into account mipmap generation flags and presence of mipmaps in loaded image.
   Standard_Integer MaxLevel() const { return myMaxLevel; }
 
   //! Setups texture mipmap array levels range.
index 919086c..21ec53f 100644 (file)
 #include <Graphic3d_GraphicDriver.hxx>
 #include <Graphic3d_TextureParams.hxx>
 #include <Image_AlienPixMap.hxx>
+#include <Image_DDSParser.hxx>
+#include <Image_SupportedFormats.hxx>
 #include <OSD_Directory.hxx>
 #include <OSD_Environment.hxx>
 #include <OSD_File.hxx>
+#include <OSD_OpenFile.hxx>
 #include <OSD_Protection.hxx>
 #include <Standard_Atomic.hxx>
 
@@ -90,7 +93,8 @@ Graphic3d_TextureRoot::Graphic3d_TextureRoot (const TCollection_AsciiString& the
   myPath     (theFileName),
   myRevision (0),
   myType     (theType),
-  myIsColorMap (true)
+  myIsColorMap (true),
+  myIsTopDown  (true)
 {
   generateId();
 }
@@ -105,7 +109,8 @@ Graphic3d_TextureRoot::Graphic3d_TextureRoot (const Handle(Image_PixMap)&   theP
   myPixMap   (thePixMap),
   myRevision (0),
   myType     (theType),
-  myIsColorMap (true)
+  myIsColorMap (true),
+  myIsTopDown  (true)
 {
   generateId();
 }
@@ -130,14 +135,56 @@ void Graphic3d_TextureRoot::generateId()
 }
 
 // =======================================================================
+// function : GetCompressedImage
+// purpose  :
+// =======================================================================
+Handle(Image_CompressedPixMap) Graphic3d_TextureRoot::GetCompressedImage (const Handle(Image_SupportedFormats)& theSupported)
+{
+  if (!myPixMap.IsNull())
+  {
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  // Case 2: texture source is specified as path
+  TCollection_AsciiString aFilePath;
+  myPath.SystemName (aFilePath);
+  if (aFilePath.IsEmpty())
+  {
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  TCollection_AsciiString aFilePathLower = aFilePath;
+  aFilePathLower.LowerCase();
+  if (!aFilePathLower.EndsWith (".dds"))
+  {
+    // do not waste time on file system access in case of wrong file extension
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  if (Handle(Image_CompressedPixMap) anImage = Image_DDSParser::Load (theSupported, aFilePath, 0))
+  {
+    myIsTopDown = anImage->IsTopDown();
+    return anImage;
+  }
+  return Handle(Image_CompressedPixMap)();
+}
+
+// =======================================================================
 // function : GetImage
 // purpose  :
 // =======================================================================
-Handle(Image_PixMap) Graphic3d_TextureRoot::GetImage() const
+Handle(Image_PixMap) Graphic3d_TextureRoot::GetImage (const Handle(Image_SupportedFormats)& theSupported)
 {
+  if (Handle(Image_PixMap) anOldImage = GetImage())
+  {
+    myIsTopDown = anOldImage->IsTopDown();
+    return anOldImage; // compatibility with old API
+  }
+
   // Case 1: texture source is specified as pixmap
   if (!myPixMap.IsNull())
   {
+    myIsTopDown = myPixMap->IsTopDown();
     return myPixMap;
   }
 
@@ -150,12 +197,38 @@ Handle(Image_PixMap) Graphic3d_TextureRoot::GetImage() const
   }
 
   Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap();
-  if (!anImage->Load (aFilePath))
+  if (anImage->Load (aFilePath))
   {
-    return Handle(Image_PixMap)();
+    myIsTopDown = anImage->IsTopDown();
+    convertToCompatible (theSupported, anImage);
+    return anImage;
+  }
+
+  return Handle(Image_PixMap)();
+}
+
+// =======================================================================
+// function : convertToCompatible
+// purpose  :
+// =======================================================================
+void Graphic3d_TextureRoot::convertToCompatible (const Handle(Image_SupportedFormats)& theSupported,
+                                                 const Handle(Image_PixMap)& theImage)
+{
+  if (theSupported.IsNull()
+   || theSupported->IsSupported (theImage->Format())
+   || theImage.IsNull())
+  {
+    return;
   }
 
-  return anImage;
+  if ((theImage->Format() == Image_Format_BGR32
+    || theImage->Format() == Image_Format_BGR32))
+  {
+    Image_PixMap::SwapRgbaBgra (*theImage);
+    theImage->SetFormat (theImage->Format() == Image_Format_BGR32
+                       ? Image_Format_RGB32
+                       : Image_Format_RGBA);
+  }
 }
 
 // =======================================================================
index 5cf14be..fb155c4 100644 (file)
@@ -25,6 +25,8 @@
 #include <Standard_Type.hxx>
 #include <TCollection_AsciiString.hxx>
 
+class Image_CompressedPixMap;
+class Image_SupportedFormats;
 class Graphic3d_TextureParams;
 
 //! This is the texture root class enable the dialog with the GraphicDriver allows the loading of texture.
@@ -80,13 +82,20 @@ public:
   void UpdateRevision() { ++myRevision; }
 
   //! This method will be called by graphic driver each time when texture resource should be created.
+  //! It is called in front of GetImage() for uploading compressed image formats natively supported by GPU.
+  //! @param theSupported [in] the list of supported compressed texture formats;
+  //!                          returning image in unsupported format will result in texture upload failure
+  //! @return compressed pixmap or NULL if image is not in supported compressed format
+  Standard_EXPORT virtual Handle(Image_CompressedPixMap) GetCompressedImage (const Handle(Image_SupportedFormats)& theSupported);
+
+  //! This method will be called by graphic driver each time when texture resource should be created.
   //! Default constructors allow defining the texture source as path to texture image or directly as pixmap.
   //! If the source is defined as path, then the image will be dynamically loaded when this method is called
   //! (and no copy will be preserved in this class instance).
   //! Inheritors may dynamically generate the image.
   //! Notice, image data should be in Bottom-Up order (see Image_PixMap::IsTopDown())!
   //! @return the image for texture.
-  Standard_EXPORT virtual Handle(Image_PixMap) GetImage() const;
+  Standard_EXPORT virtual Handle(Image_PixMap) GetImage (const Handle(Image_SupportedFormats)& theSupported);
 
   //! @return low-level texture parameters
   const Handle(Graphic3d_TextureParams)& GetParams() const { return myParams; }
@@ -104,6 +113,9 @@ public:
   //! Set flag indicating color nature of values within the texture.
   void SetColorMap (Standard_Boolean theIsColor) { myIsColorMap = theIsColor; }
 
+  //! Returns whether row's memory layout is top-down.
+  Standard_Boolean IsTopDown() const { return myIsTopDown; }
+
 protected:
 
   //! Creates a texture from a file
@@ -119,6 +131,13 @@ protected:
   //! Unconditionally generate new texture id. Should be called only within constructor.
   Standard_EXPORT void generateId();
 
+  //! Try converting image to compatible format.
+  Standard_EXPORT static void convertToCompatible (const Handle(Image_SupportedFormats)& theSupported,
+                                                   const Handle(Image_PixMap)& theImage);
+
+  //! Method for supporting old API; another GetImage() method should be implemented instead.
+  virtual Handle(Image_PixMap) GetImage() const { return Handle(Image_PixMap)(); }
+
 protected:
 
   Handle(Graphic3d_TextureParams) myParams;     //!< associated texture parameters
@@ -128,6 +147,8 @@ protected:
   Standard_Size                   myRevision;   //!< image revision - for signaling changes in the texture source (e.g. file update, pixmap update)
   Graphic3d_TypeOfTexture         myType;       //!< texture type
   Standard_Boolean                myIsColorMap; //!< flag indicating color nature of values within the texture
+  Standard_Boolean                myIsTopDown;  //!< Stores rows's memory layout
+
 
 };
 
index 8055875..f752166 100755 (executable)
@@ -1,6 +1,10 @@
 Image_AlienPixMap.cxx
 Image_AlienPixMap.hxx
 Image_Color.hxx
+Image_CompressedFormat.hxx
+Image_CompressedPixMap.hxx
+Image_DDSParser.cxx
+Image_DDSParser.hxx
 Image_Diff.cxx
 Image_Diff.hxx
 Image_Format.hxx
@@ -8,6 +12,8 @@ Image_PixMap.cxx
 Image_PixMap.hxx
 Image_PixMapData.hxx
 Image_PixMapTypedData.hxx
+Image_SupportedFormats.cxx
+Image_SupportedFormats.hxx
 Image_Texture.cxx
 Image_Texture.hxx
 Image_VideoRecorder.cxx
diff --git a/src/Image/Image_CompressedFormat.hxx b/src/Image/Image_CompressedFormat.hxx
new file mode 100644 (file)
index 0000000..2d8e697
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Image_CompressedFormat_HeaderFile
+#define _Image_CompressedFormat_HeaderFile
+
+#include <Image_Format.hxx>
+
+//! List of compressed pixel formats natively supported by various graphics hardware (e.g. for efficient decoding on-the-fly).
+//! It is defined as extension of Image_Format.
+enum Image_CompressedFormat
+{
+  Image_CompressedFormat_UNKNOWN = Image_Format_UNKNOWN,
+  Image_CompressedFormat_RGB_S3TC_DXT1 = Image_Format_NB,
+  Image_CompressedFormat_RGBA_S3TC_DXT1,
+  Image_CompressedFormat_RGBA_S3TC_DXT3,
+  Image_CompressedFormat_RGBA_S3TC_DXT5
+};
+enum { Image_CompressedFormat_NB = Image_CompressedFormat_RGBA_S3TC_DXT5 + 1 };
+
+#endif // _Image_CompressedFormat_HeaderFile
diff --git a/src/Image/Image_CompressedPixMap.hxx b/src/Image/Image_CompressedPixMap.hxx
new file mode 100644 (file)
index 0000000..541d5d8
--- /dev/null
@@ -0,0 +1,108 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Image_CompressedPixMap_HeaderFile
+#define _Image_CompressedPixMap_HeaderFile
+
+#include <Image_Format.hxx>
+#include <Image_CompressedFormat.hxx>
+#include <NCollection_Array1.hxx>
+#include <NCollection_Buffer.hxx>
+#include <Standard_Type.hxx>
+
+//! Compressed pixmap data definition.
+//! It is defined independently from Image_PixMap, which defines only uncompressed formats.
+class Image_CompressedPixMap : public Standard_Transient
+{
+  DEFINE_STANDARD_RTTIEXT(Image_CompressedPixMap, Standard_Transient)
+public:
+
+  //! Return base (uncompressed) pixel format.
+  Image_Format BaseFormat() const { return myBaseFormat; }
+
+  //! Set base (uncompressed) pixel format.
+  void SetBaseFormat (Image_Format theFormat) { myBaseFormat = theFormat; }
+
+  //! Return compressed format.
+  Image_CompressedFormat CompressedFormat() const { return myFormat; }
+
+  //! Set compressed format.
+  void SetCompressedFormat (Image_CompressedFormat theFormat) { myFormat = theFormat; }
+
+  //! Return raw (compressed) data.
+  const Handle(NCollection_Buffer)& FaceData() const { return myFaceData; }
+
+  //! Set raw (compressed) data.
+  void SetFaceData (const Handle(NCollection_Buffer)& theBuffer) { myFaceData = theBuffer; }
+
+  //! Return Array of mipmap sizes, including base level.
+  const NCollection_Array1<Standard_Integer>& MipMaps() const { return myMipMaps; }
+
+  //! Return Array of mipmap sizes, including base level.
+  NCollection_Array1<Standard_Integer>& ChangeMipMaps() { return myMipMaps; }
+
+  //! Return TRUE if complete mip map level set (up to 1x1 resolution).
+  Standard_Boolean IsCompleteMipMapSet() const { return myIsCompleteMips; }
+
+  //! Set if complete mip map level set (up to 1x1 resolution).
+  void SetCompleteMipMapSet (Standard_Boolean theIsComplete) { myIsCompleteMips = theIsComplete; }
+
+  //! Return surface length in bytes.
+  Standard_Size FaceBytes() const { return myFaceBytes; }
+
+  //! Set surface length in bytes.
+  void SetFaceBytes (Standard_Size theSize) { myFaceBytes = theSize; }
+
+  //! Return surface width.
+  Standard_Integer SizeX() const { return mySizeX; }
+
+  //! Return surface height.
+  Standard_Integer SizeY() const { return mySizeY; }
+
+  //! Set surface width x height.
+  void SetSize (Standard_Integer theSizeX, Standard_Integer theSizeY)
+  {
+    mySizeX = theSizeX;
+    mySizeY = theSizeY;
+  }
+
+  //! Return TRUE if image layout is top-down (always true).
+  bool IsTopDown() const { return true; }
+
+  //! Return number of faces in the file; should be 6 for cubemap.
+  Standard_Integer NbFaces() const { return myNbFaces; }
+
+  //! Set number of faces in the file.
+  void SetNbFaces (Standard_Integer theSize) { myNbFaces = theSize; }
+
+public:
+
+  //! Empty constructor.
+  Image_CompressedPixMap()
+  : myFaceBytes (0), myNbFaces (0), mySizeX (0), mySizeY (0), myBaseFormat (Image_Format_UNKNOWN), myFormat (Image_CompressedFormat_UNKNOWN), myIsCompleteMips (false)  {}
+
+protected:
+
+  NCollection_Array1<Standard_Integer> myMipMaps; //!< Array of mipmap sizes, including base level
+  Handle(NCollection_Buffer) myFaceData;          //!< raw compressed data
+  Standard_Size              myFaceBytes;         //!< surface length in bytes
+  Standard_Integer           myNbFaces;           //!< number of faces in the file
+  Standard_Integer           mySizeX;             //!< surface width
+  Standard_Integer           mySizeY;             //!< surface height
+  Image_Format               myBaseFormat;        //!< base (uncompressed) pixel format
+  Image_CompressedFormat     myFormat;            //!< compressed format
+  Standard_Boolean           myIsCompleteMips;    //!< flag indicating complete mip map level set (up to 1x1 resolution)
+
+};
+
+#endif // _Image_CompressedPixMap_HeaderFile
diff --git a/src/Image/Image_DDSParser.cxx b/src/Image/Image_DDSParser.cxx
new file mode 100644 (file)
index 0000000..7addc93
--- /dev/null
@@ -0,0 +1,255 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <Image_DDSParser.hxx>
+
+#include <Image_PixMap.hxx>
+#include <Image_SupportedFormats.hxx>
+#include <Message.hxx>
+#include <OSD_OpenFile.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(Image_CompressedPixMap, Standard_Transient)
+
+//! DDS Pixel Format structure.
+struct Image_DDSParser::DDSPixelFormat
+{
+  uint32_t Size;
+  uint32_t Flags;
+  uint32_t FourCC;
+  uint32_t RGBBitCount;
+  uint32_t RBitMask;
+  uint32_t GBitMask;
+  uint32_t BBitMask;
+  uint32_t ABitMask;
+};
+
+//! DDS File header structure.
+struct Image_DDSParser::DDSFileHeader
+{
+  //! Caps2 flag indicating complete (6 faces) cubemap.
+  enum { DDSCompleteCubemap = 0xFE00 };
+
+  //! Return TRUE if cubmap flag is set.
+  bool IscompleteCubemap() const { return (Caps2 & DDSFileHeader::DDSCompleteCubemap) == DDSFileHeader::DDSCompleteCubemap; }
+
+  uint32_t Size;
+  uint32_t Flags;
+  uint32_t Height;
+  uint32_t Width;
+  uint32_t PitchOrLinearSize;
+  uint32_t Depth;
+  uint32_t MipMapCount;
+  uint32_t Reserved1[11];
+  DDSPixelFormat PixelFormatDef;
+  uint32_t Caps;
+  uint32_t Caps2;
+  uint32_t Caps3;
+  uint32_t Caps4;
+  uint32_t Reserved2;
+};
+
+// =======================================================================
+// function : Load
+// purpose  :
+// =======================================================================
+Handle(Image_CompressedPixMap) Image_DDSParser::Load (const Handle(Image_SupportedFormats)& theSupported,
+                                                      const TCollection_AsciiString& theFile,
+                                                      const Standard_Integer theFaceIndex,
+                                                      const int64_t theFileOffset)
+{
+  std::ifstream aFile;
+  OSD_OpenStream (aFile, theFile.ToCString(), std::ios::in | std::ios::binary);
+
+  char aHeader[128] = {};
+  if (!aFile.is_open()
+   || !aFile.good())
+  {
+    return Handle(Image_CompressedPixMap)();
+  }
+  if (theFileOffset != 0)
+  {
+    aFile.seekg ((std::streamoff )theFileOffset, std::ios::beg);
+  }
+  aFile.read (aHeader, 128);
+  Standard_Size aNbReadBytes = (Standard_Size )aFile.gcount();
+  if (aNbReadBytes < 128
+   || ::memcmp (aHeader, "DDS ", 4) != 0)
+  {
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  Handle(Image_CompressedPixMap) aDef = parseHeader (*(const DDSFileHeader* )(aHeader + 4));
+  if (aDef.IsNull())
+  {
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  if (!theSupported.IsNull()
+   && !theSupported->IsSupported (aDef->CompressedFormat()))
+  {
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  if (theFaceIndex < 0)
+  {
+    return aDef;
+  }
+
+  if (theFaceIndex >= aDef->NbFaces()
+   || aDef->FaceBytes() == 0)
+  {
+    Message::SendFail (TCollection_AsciiString ("DDS Reader error - invalid face index #") + theFaceIndex + " within file\n" + theFile);
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  const Standard_Size anOffset = aDef->FaceBytes() * theFaceIndex;
+  if (anOffset != 0)
+  {
+    aFile.seekg ((std::streamoff )anOffset, std::ios::cur);
+  }
+  Handle(NCollection_Buffer) aBuffer = new NCollection_Buffer (Image_PixMap::DefaultAllocator(), aDef->FaceBytes());
+  aFile.read ((char* )aBuffer->ChangeData(), aDef->FaceBytes());
+  aNbReadBytes = (Standard_Size )aFile.gcount();
+  if (aNbReadBytes < aDef->FaceBytes())
+  {
+    Message::SendFail (TCollection_AsciiString ("DDS Reader error - unable to read face #") + theFaceIndex + " data from file\n" + theFile);
+    return Handle(Image_CompressedPixMap)();
+  }
+  aDef->SetFaceData (aBuffer);
+  return aDef;
+}
+
+// =======================================================================
+// function : Load
+// purpose  :
+// =======================================================================
+Handle(Image_CompressedPixMap) Image_DDSParser::Load (const Handle(Image_SupportedFormats)& theSupported,
+                                                      const Handle(NCollection_Buffer)& theBuffer,
+                                                      const Standard_Integer theFaceIndex)
+{
+  if (theBuffer.IsNull()
+   || theBuffer->Size() < 128
+   || ::memcmp (theBuffer->Data(), "DDS ", 4) != 0)
+  {
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  Handle(Image_CompressedPixMap) aDef = parseHeader (*(const DDSFileHeader* )(theBuffer->Data() + 4));
+  if (aDef.IsNull())
+  {
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  if (!theSupported.IsNull()
+   && !theSupported->IsSupported (aDef->CompressedFormat()))
+  {
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  if (theFaceIndex < 0)
+  {
+    return aDef;
+  }
+
+  if (theFaceIndex >= aDef->NbFaces()
+   || aDef->FaceBytes() == 0)
+  {
+    Message::SendFail (TCollection_AsciiString ("DDS Reader error - invalid face index #") + theFaceIndex + " within buffer");
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  const Standard_Size anOffset = aDef->FaceBytes() * theFaceIndex + 128;
+  if (theBuffer->Size() < anOffset + aDef->FaceBytes())
+  {
+    Message::SendFail (TCollection_AsciiString ("DDS Reader error - unable to read face #") + theFaceIndex + " data from buffer");
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  Handle(NCollection_Buffer) aBuffer = new NCollection_Buffer (Image_PixMap::DefaultAllocator(), aDef->FaceBytes());
+  memcpy (aBuffer->ChangeData(), theBuffer->Data() + anOffset, aDef->FaceBytes());
+  aDef->SetFaceData (aBuffer);
+  return aDef;
+}
+
+// =======================================================================
+// function : parseHeader
+// purpose  :
+// =======================================================================
+Handle(Image_CompressedPixMap) Image_DDSParser::parseHeader (const DDSFileHeader& theHeader)
+{
+  if (theHeader.Size != 124
+   || theHeader.Width  == 0
+   || theHeader.Height == 0
+   || theHeader.PixelFormatDef.Size != 32)
+  {
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  Image_Format aBaseFormat = Image_Format_UNKNOWN;
+  Image_CompressedFormat aFormat = Image_CompressedFormat_UNKNOWN;
+  Standard_Integer aBlockSize = 8;
+  const bool hasAlpha = (theHeader.PixelFormatDef.Flags & 0x1) != 0;
+  if (::memcmp (&theHeader.PixelFormatDef.FourCC, "DXT5", 4) == 0)
+  {
+    aBaseFormat = Image_Format_RGBA;
+    aFormat = Image_CompressedFormat_RGBA_S3TC_DXT5;
+    aBlockSize = 16;
+  }
+  else if (::memcmp (&theHeader.PixelFormatDef.FourCC, "DXT3", 4) == 0)
+  {
+    aBaseFormat = Image_Format_RGBA;
+    aFormat = Image_CompressedFormat_RGBA_S3TC_DXT3;
+    aBlockSize = 16;
+  }
+  else if (::memcmp (&theHeader.PixelFormatDef.FourCC, "DXT1", 4) == 0)
+  {
+    aBaseFormat = hasAlpha ? Image_Format_RGBA : Image_Format_RGB;
+    aFormat = hasAlpha ? Image_CompressedFormat_RGBA_S3TC_DXT1 : Image_CompressedFormat_RGB_S3TC_DXT1;
+    aBlockSize = 8;
+  }
+  if (aFormat == Image_CompressedFormat_UNKNOWN)
+  {
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  Handle(Image_CompressedPixMap) aDef = new Image_CompressedPixMap();
+  aDef->SetSize ((Standard_Integer )theHeader.Width, (Standard_Integer )theHeader.Height);
+  aDef->SetNbFaces (theHeader.IscompleteCubemap() != 0 ? 6 : 1);
+  aDef->SetBaseFormat (aBaseFormat);
+  aDef->SetCompressedFormat (aFormat);
+
+  const Standard_Integer aNbMipMaps = Max ((Standard_Integer )theHeader.MipMapCount, 1);
+  aDef->ChangeMipMaps().Resize (0, aNbMipMaps - 1, false);
+  {
+    Standard_Size aFaceSize = 0;
+    NCollection_Vec2<Standard_Integer> aMipSizeXY (aDef->SizeX(), aDef->SizeY());
+    for (Standard_Integer aMipIter = 0;; ++aMipIter)
+    {
+      const Standard_Integer aMipLength = ((aMipSizeXY.x() + 3) / 4) * ((aMipSizeXY.y() + 3) / 4) * aBlockSize;
+      aFaceSize += aMipLength;
+      aDef->ChangeMipMaps().SetValue (aMipIter, aMipLength);
+      if (aMipIter + 1 >= aNbMipMaps)
+      {
+        break;
+      }
+
+      aMipSizeXY /= 2;
+      if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
+      if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
+    }
+    aDef->SetCompleteMipMapSet (aMipSizeXY.x() == 1 && aMipSizeXY.y() == 1);
+    aDef->SetFaceBytes (aFaceSize);
+  }
+
+  return aDef;
+}
diff --git a/src/Image/Image_DDSParser.hxx b/src/Image/Image_DDSParser.hxx
new file mode 100644 (file)
index 0000000..7010697
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Image_DDSParser_HeaderFile
+#define _Image_DDSParser_HeaderFile
+
+#include <Image_CompressedPixMap.hxx>
+#include <NCollection_Buffer.hxx>
+
+class Image_SupportedFormats;
+
+//! Auxiliary tool for parsing DDS file structure (without decoding).
+class Image_DDSParser
+{
+public:
+
+  //! Load the face from DDS file.
+  //! @param theSupported [in] list of supported image formats
+  //! @param theFile      [in] file path
+  //! @param theFaceIndex [in] face index, within [0, Image_CompressedPixMap::NbFaces()) range;
+  //!                          use -1 to skip reading the face data
+  //! @param theFileOffset [in] offset to the DDS data
+  //! @return loaded face or NULL if file cannot be read or not valid DDS file
+  Standard_EXPORT static Handle(Image_CompressedPixMap) Load (const Handle(Image_SupportedFormats)& theSupported,
+                                                              const TCollection_AsciiString& theFile,
+                                                              const Standard_Integer theFaceIndex,
+                                                              const int64_t theFileOffset = 0);
+
+  //! Load the face from DDS file.
+  //! @param theSupported [in] list of supported image formats
+  //! @param theBuffer    [in] pre-loaded file data, should be at least of 128 bytes long defining DDS header.
+  //! @param theFaceIndex [in] face index, within [0, Image_CompressedPixMap::NbFaces()) range;
+  //!                          use -1 to skip reading the face data
+  //! @return loaded face or NULL if file cannot be read or not valid DDS file
+  Standard_EXPORT static Handle(Image_CompressedPixMap) Load (const Handle(Image_SupportedFormats)& theSupported,
+                                                              const Handle(NCollection_Buffer)& theBuffer,
+                                                              const Standard_Integer theFaceIndex);
+
+  
+private:
+
+  struct DDSPixelFormat;
+  struct DDSFileHeader;
+
+private:
+
+  //! Parse DDS header.
+  static Handle(Image_CompressedPixMap) parseHeader (const DDSFileHeader& theHeader);
+
+};
+
+#endif // _Image_DDSParser_HeaderFile
index 5842625..28bfcf4 100644 (file)
@@ -34,5 +34,6 @@ enum Image_Format
   Image_Format_RGBAF,       //!< 4 floats (16-bytes) RGBA image plane
   Image_Format_BGRAF,       //!< same as RGBAF but with different components order
 };
+enum { Image_Format_NB = Image_Format_BGRAF + 1 };
 
 #endif // _Image_Format_HeaderFile
index 57f76f1..6d9f002 100644 (file)
@@ -14,6 +14,7 @@
 // commercial license or contractual agreement.
 
 #include <Image_PixMap.hxx>
+
 #include <NCollection_AlignedAllocator.hxx>
 #include <Standard_ProgramError.hxx>
 
 IMPLEMENT_STANDARD_RTTIEXT(Image_PixMap,Standard_Transient)
 
 // =======================================================================
+// function : DefaultAllocator
+// purpose  :
+// =======================================================================
+const Handle(NCollection_BaseAllocator)& Image_PixMap::DefaultAllocator()
+{
+  static const Handle(NCollection_BaseAllocator) THE_ALLOC = new NCollection_AlignedAllocator (16);
+  return THE_ALLOC;
+}
+
+// =======================================================================
 // function : Image_PixMap
 // purpose  :
 // =======================================================================
@@ -40,6 +51,10 @@ Image_PixMap::~Image_PixMap()
   Clear();
 }
 
+// =======================================================================
+// function : SizePixelBytes
+// purpose  :
+// =======================================================================
 Standard_Size Image_PixMap::SizePixelBytes (const Image_Format thePixelFormat)
 {
   switch (thePixelFormat)
@@ -135,8 +150,7 @@ bool Image_PixMap::InitTrash (Image_Format        thePixelFormat,
 
   // use argument only if it greater
   const Standard_Size aSizeRowBytes = std::max (theSizeRowBytes, theSizeX * SizePixelBytes (thePixelFormat));
-  Handle(NCollection_BaseAllocator) anAlloc = new NCollection_AlignedAllocator (16);
-  myData.Init (anAlloc, Image_PixMap::SizePixelBytes (thePixelFormat),
+  myData.Init (DefaultAllocator(), Image_PixMap::SizePixelBytes (thePixelFormat),
                theSizeX, theSizeY, aSizeRowBytes, NULL);
   return !myData.IsEmpty();
 }
index 6323445..c7775e5 100644 (file)
@@ -48,6 +48,9 @@ public:
   //! Convert image to Black/White.
   Standard_EXPORT static void ToBlackWhite (Image_PixMap& theImage);
 
+  //! Return default image data allocator.
+  Standard_EXPORT static const Handle(NCollection_BaseAllocator)& DefaultAllocator();
+
 public: // high-level API
 
   Image_Format Format() const { return myImgFormat; }
diff --git a/src/Image/Image_SupportedFormats.cxx b/src/Image/Image_SupportedFormats.cxx
new file mode 100644 (file)
index 0000000..4522583
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <Image_SupportedFormats.hxx>
+
+IMPLEMENT_STANDARD_RTTIEXT(Image_SupportedFormats, Standard_Transient)
+
+// =======================================================================
+// function : Image_SupportedFormats
+// purpose  :
+// =======================================================================
+Image_SupportedFormats::Image_SupportedFormats()
+: myFormats (Image_Format_UNKNOWN, Image_CompressedFormat_NB - 1),
+  myHasCompressed (false)
+{
+  myFormats.Init (false);
+}
diff --git a/src/Image/Image_SupportedFormats.hxx b/src/Image/Image_SupportedFormats.hxx
new file mode 100644 (file)
index 0000000..91abe16
--- /dev/null
@@ -0,0 +1,63 @@
+// Copyright (c) 2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _Image_SupportedFormats_HeaderFile
+#define _Image_SupportedFormats_HeaderFile
+
+#include <Image_CompressedFormat.hxx>
+#include <NCollection_Array1.hxx>
+#include <Standard_Type.hxx>
+
+//! Structure holding information about supported texture formats.
+class Image_SupportedFormats : public Standard_Transient
+{
+  DEFINE_STANDARD_RTTIEXT(Image_SupportedFormats, Standard_Transient)
+public:
+
+  //! Empty constructor.
+  Standard_EXPORT Image_SupportedFormats();
+
+  //! Return TRUE if image format is supported.
+  bool IsSupported (Image_Format theFormat) const { return myFormats.Value (theFormat); }
+
+  //! Set if image format is supported or not.
+  void Add (Image_Format theFormat) { myFormats.SetValue (theFormat, true); }
+
+  //! Return TRUE if there are compressed image formats supported.
+  bool HasCompressed() const { return myHasCompressed; }
+
+  //! Return TRUE if compressed image format is supported.
+  bool IsSupported (Image_CompressedFormat theFormat) const { return myFormats.Value (theFormat); }
+
+  //! Set if compressed image format is supported or not.
+  void Add (Image_CompressedFormat theFormat)
+  {
+    myFormats.SetValue (theFormat, true);
+    myHasCompressed = true;
+  }
+
+  //! Reset flags.
+  void Clear()
+  {
+    myFormats.Init (false);
+    myHasCompressed = false;
+  }
+
+protected:
+
+  NCollection_Array1<bool> myFormats; //!< list of supported formats
+  Standard_Boolean   myHasCompressed; //!< flag indicating that some compressed image formats are supported
+
+};
+
+#endif // _Image_SupportedFormats_HeaderFile
index 63f1153..ce9d2a5 100644 (file)
@@ -15,6 +15,8 @@
 #include <Image_Texture.hxx>
 
 #include <Image_AlienPixMap.hxx>
+#include <Image_DDSParser.hxx>
+#include <Image_SupportedFormats.hxx>
 #include <Message.hxx>
 #include <Message_Messenger.hxx>
 #include <OSD_OpenFile.hxx>
@@ -74,10 +76,40 @@ Image_Texture::Image_Texture (const Handle(NCollection_Buffer)& theBuffer,
 }
 
 // ================================================================
+// Function : ReadCompressedImage
+// Purpose  :
+// ================================================================
+Handle(Image_CompressedPixMap) Image_Texture::ReadCompressedImage (const Handle(Image_SupportedFormats)& theSupported) const
+{
+  if (!theSupported->HasCompressed())
+  {
+    return Handle(Image_CompressedPixMap)();
+  }
+
+  if (!myBuffer.IsNull())
+  {
+    return Image_DDSParser::Load (theSupported, myBuffer, 0);
+  }
+  else if (myOffset >= 0)
+  {
+    return Image_DDSParser::Load (theSupported, myImagePath, 0, myOffset);
+  }
+
+  TCollection_AsciiString aFilePathLower = myImagePath;
+  aFilePathLower.LowerCase();
+  if (!aFilePathLower.EndsWith (".dds"))
+  {
+    // do not waste time on file system access in case of wrong file extension
+    return Handle(Image_CompressedPixMap)();
+  }
+  return Image_DDSParser::Load (theSupported, myImagePath, 0);
+}
+
+// ================================================================
 // Function : ReadImage
 // Purpose  :
 // ================================================================
-Handle(Image_PixMap) Image_Texture::ReadImage() const
+Handle(Image_PixMap) Image_Texture::ReadImage (const Handle(Image_SupportedFormats)& ) const
 {
   Handle(Image_PixMap) anImage;
   if (!myBuffer.IsNull())
@@ -240,6 +272,10 @@ TCollection_AsciiString Image_Texture::ProbeImageFileFormat() const
   {
     return "webp";
   }
+  else if (memcmp (aBuffer, "DDS ", 4) == 0)
+  {
+    return "dds";
+  }
   return "";
 }
 
index 688f0e1..7a6f53b 100644 (file)
@@ -18,6 +18,8 @@
 #include <NCollection_Buffer.hxx>
 #include <TCollection_AsciiString.hxx>
 
+class Image_CompressedPixMap;
+class Image_SupportedFormats;
 class Image_PixMap;
 
 //! Texture image definition.
@@ -57,8 +59,11 @@ public:
   //! Return image file format.
   Standard_EXPORT TCollection_AsciiString ProbeImageFileFormat() const;
 
+  //! Image reader without decoding data for formats supported natively by GPUs.
+  Standard_EXPORT virtual Handle(Image_CompressedPixMap) ReadCompressedImage (const Handle(Image_SupportedFormats)& theSupported) const;
+
   //! Image reader.
-  Standard_EXPORT virtual Handle(Image_PixMap) ReadImage() const;
+  Standard_EXPORT virtual Handle(Image_PixMap) ReadImage (const Handle(Image_SupportedFormats)& theSupported) const;
 
   //! Write image to specified file without decoding data.
   Standard_EXPORT virtual Standard_Boolean WriteImage (const TCollection_AsciiString& theFile);
index d352e9b..5f8c3d3 100755 (executable)
@@ -25,6 +25,7 @@ IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Caps,Standard_Transient)
 // =======================================================================
 OpenGl_Caps::OpenGl_Caps()
 : sRGBDisable       (Standard_False),
+  compressedTexturesDisable (Standard_False),
   vboDisable        (Standard_False),
   pntSpritesDisable (Standard_False),
   keepArrayData     (Standard_False),
@@ -54,6 +55,7 @@ OpenGl_Caps::OpenGl_Caps()
   contextNoExtensions (Standard_False),
   contextMajorVersionUpper (-1),
   contextMinorVersionUpper (-1),
+  isTopDownTextureUV(Standard_False),
   glslWarnings      (Standard_False),
   suppressExtraMsg  (Standard_True),
   glslDumpLevel     (OpenGl_ShaderProgramDumpLevel_Off)
@@ -68,6 +70,7 @@ OpenGl_Caps::OpenGl_Caps()
 OpenGl_Caps& OpenGl_Caps::operator= (const OpenGl_Caps& theCopy)
 {
   sRGBDisable       = theCopy.sRGBDisable;
+  compressedTexturesDisable = theCopy.compressedTexturesDisable;
   vboDisable        = theCopy.vboDisable;
   pntSpritesDisable = theCopy.pntSpritesDisable;
   keepArrayData     = theCopy.keepArrayData;
@@ -83,6 +86,7 @@ OpenGl_Caps& OpenGl_Caps::operator= (const OpenGl_Caps& theCopy)
   contextNoExtensions = theCopy.contextNoExtensions;
   contextMajorVersionUpper = theCopy.contextMajorVersionUpper;
   contextMinorVersionUpper = theCopy.contextMinorVersionUpper;
+  isTopDownTextureUV = theCopy.isTopDownTextureUV;
   glslWarnings      = theCopy.glslWarnings;
   suppressExtraMsg  = theCopy.suppressExtraMsg;
   glslDumpLevel     = theCopy.glslDumpLevel;
index e0b123c..6a1a386 100755 (executable)
@@ -28,6 +28,7 @@ class OpenGl_Caps : public Standard_Transient
 public: //! @name flags to disable particular functionality, should be used only for testing purposes!
 
   Standard_Boolean sRGBDisable;       //!< Disables sRGB rendering (OFF by default)
+  Standard_Boolean compressedTexturesDisable; //!< Disables uploading of compressed texture formats native to GPU (OFF by default)
   Standard_Boolean vboDisable;        //!< disallow VBO usage for debugging purposes (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)
@@ -125,6 +126,19 @@ public: //! @name context creation parameters
   Standard_Integer contextMajorVersionUpper;
   Standard_Integer contextMinorVersionUpper;
 
+  /**
+   * Define if 2D texture UV coordinates are defined top-down or bottom-up. FALSE by default.
+   *
+   * Proper rendering requires image texture uploading and UV texture coordinates being consistent,
+   * otherwise texture mapping might appear vertically flipped.
+   * Historically, OCCT used image library loading images bottom-up,
+   * so that applications have to generate UV accordingly (flip V when necessary, V' = 1.0 - V).
+   *
+   * Graphic driver now compares this flag with image layout reported by Image_PixMap::IsTopDown(),
+   * and in case of mismatch applies implicit texture coordinates conversion in GLSL program.
+   */
+  Standard_Boolean isTopDownTextureUV;
+
 public: //! @name flags to activate verbose output
 
   //! Print GLSL program compilation/linkage warnings, if any. OFF by default.
index f47bcc7..531d4fd 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <Graphic3d_TransformUtils.hxx>
 #include <Graphic3d_RenderingParams.hxx>
+#include <Image_SupportedFormats.hxx>
 #include <Message_Messenger.hxx>
 #include <NCollection_Vector.hxx>
 #include <Standard_ProgramError.hxx>
@@ -188,6 +189,7 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   myClippingState (),
   myGlLibHandle (NULL),
   myFuncs (new OpenGl_GlFunctions()),
+  mySupportedFormats (new Image_SupportedFormats()),
   myAnisoMax   (1),
   myTexClamp   (GL_CLAMP_TO_EDGE),
   myMaxTexDim  (1024),
@@ -1319,6 +1321,14 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   myVendor = (const char* )::glGetString (GL_VENDOR);
   myVendor.LowerCase();
 
+  // standard formats
+  mySupportedFormats->Clear();
+  mySupportedFormats->Add (Image_PixMap::ImgGray);
+  mySupportedFormats->Add (Image_PixMap::ImgAlpha);
+  mySupportedFormats->Add (Image_PixMap::ImgRGB);
+  mySupportedFormats->Add (Image_PixMap::ImgRGB32);
+  mySupportedFormats->Add (Image_PixMap::ImgRGBA);
+
   if (caps->contextMajorVersionUpper != -1)
   {
     // synthetically restrict OpenGL version for testing
@@ -1467,6 +1477,13 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   }
 #endif
 
+  if (extBgra)
+  {
+    // no BGR on OpenGL ES - only BGRA as extension
+    mySupportedFormats->Add (Image_PixMap::ImgBGR32);
+    mySupportedFormats->Add (Image_PixMap::ImgBGRA);
+  }
+
   core11fwd = (OpenGl_GlCore11Fwd* )(&(*myFuncs));
   if (IsGlGreaterEqual (2, 0))
   {
@@ -1613,7 +1630,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   myTexClamp = IsGlGreaterEqual (1, 2) ? GL_CLAMP_TO_EDGE : GL_CLAMP;
 
   hasTexRGBA8 = Standard_True;
-  hasTexSRGB       = IsGlGreaterEqual (2, 0);
+  hasTexSRGB       = IsGlGreaterEqual (2, 1);
   hasFboSRGB       = IsGlGreaterEqual (2, 1);
   hasSRGBControl   = hasFboSRGB;
   arbDrawBuffers   = CheckExtension ("GL_ARB_draw_buffers");
@@ -1622,12 +1639,20 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
                   || CheckExtension ("GL_ARB_texture_float");
   hasTexFloatLinear = arbTexFloat;
   arbSampleShading = CheckExtension ("GL_ARB_sample_shading");
-  extBgra          = CheckExtension ("GL_EXT_bgra");
+  extBgra          = IsGlGreaterEqual (1, 2)
+                  || CheckExtension ("GL_EXT_bgra");
   extAnis          = CheckExtension ("GL_EXT_texture_filter_anisotropic");
   extPDS           = CheckExtension ("GL_EXT_packed_depth_stencil");
   atiMem           = CheckExtension ("GL_ATI_meminfo");
   nvxMem           = CheckExtension ("GL_NVX_gpu_memory_info");
 
+  if (extBgra)
+  {
+    mySupportedFormats->Add (Image_PixMap::ImgBGR);
+    mySupportedFormats->Add (Image_PixMap::ImgBGR32);
+    mySupportedFormats->Add (Image_PixMap::ImgBGRA);
+  }
+
   hasDrawBuffers = IsGlGreaterEqual (2, 0) ? OpenGl_FeatureInCore :
                    arbDrawBuffers ? OpenGl_FeatureInExtensions 
                                   : OpenGl_FeatureNotAvailable;
@@ -2974,6 +2999,59 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
     }
   }
 
+  if (arbTexFloat)
+  {
+    mySupportedFormats->Add (Image_Format_GrayF);
+    mySupportedFormats->Add (Image_Format_AlphaF);
+    mySupportedFormats->Add (Image_Format_RGBF);
+    mySupportedFormats->Add (Image_Format_RGBAF);
+    if (arbTexRG)
+    {
+      mySupportedFormats->Add (Image_Format_RGF);
+    }
+    if (extBgra)
+    {
+    #if !defined(GL_ES_VERSION_2_0)
+      mySupportedFormats->Add (Image_Format_BGRF);
+    #endif
+      mySupportedFormats->Add (Image_Format_BGRAF);
+    }
+  }
+
+#ifdef __EMSCRIPTEN__
+  if (checkEnableWebGlExtension (*this, "GL_WEBGL_compressed_texture_s3tc")) // GL_WEBGL_compressed_texture_s3tc_srgb for sRGB formats
+  {
+    mySupportedFormats->Add (Image_CompressedFormat_RGB_S3TC_DXT1);
+    mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT1);
+    mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT3);
+    mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT5);
+  }
+#else
+  if (CheckExtension ("GL_EXT_texture_compression_s3tc")) // GL_EXT_texture_sRGB for sRGB formats
+  {
+    mySupportedFormats->Add (Image_CompressedFormat_RGB_S3TC_DXT1);
+    mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT1);
+    mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT3);
+    mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT5);
+  }
+  else
+  {
+    if (CheckExtension ("GL_EXT_texture_compression_dxt1"))
+    {
+      mySupportedFormats->Add (Image_CompressedFormat_RGB_S3TC_DXT1);
+      mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT1);
+    }
+    if (CheckExtension ("GL_ANGLE_texture_compression_dxt3"))
+    {
+      mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT3);
+    }
+    if (CheckExtension ("GL_ANGLE_texture_compression_dxt5"))
+    {
+      mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT5);
+    }
+  }
+#endif
+
   // check whether PBR shading model is supported
   myHasPBR = arbFBO != NULL
           && myMaxTexCombined >= 4
@@ -3461,7 +3539,7 @@ Handle(OpenGl_TextureSet) OpenGl_Context::BindTextures (const Handle(OpenGl_Text
           }
           else
           {
-            OpenGl_Sampler::applySamplerParams (aThisCtx, aTextureNew->Sampler()->Parameters(), aTextureNew->Sampler().get(), aTextureNew->GetTarget(), aTextureNew->HasMipmaps());
+            OpenGl_Sampler::applySamplerParams (aThisCtx, aTextureNew->Sampler()->Parameters(), aTextureNew->Sampler().get(), aTextureNew->GetTarget(), aTextureNew->MaxMipmapLevel());
           }
         }
       #if !defined(GL_ES_VERSION_2_0)
@@ -3791,13 +3869,17 @@ void OpenGl_Context::SetLineWidth (const Standard_ShortReal theWidth)
 // function : SetTextureMatrix
 // purpose  :
 // =======================================================================
-void OpenGl_Context::SetTextureMatrix (const Handle(Graphic3d_TextureParams)& theParams)
+void OpenGl_Context::SetTextureMatrix (const Handle(Graphic3d_TextureParams)& theParams,
+                                       const Standard_Boolean theIsTopDown)
 {
   if (theParams.IsNull())
   {
     return;
   }
-  else if (!myActiveProgram.IsNull())
+
+  const Graphic3d_Vec2& aScale = theParams->Scale();
+  const Graphic3d_Vec2& aTrans = theParams->Translation();
+  if (!myActiveProgram.IsNull())
   {
     const GLint aUniLoc = myActiveProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_TRSF2D);
     if (aUniLoc == OpenGl_ShaderProgram::INVALID_LOCATION)
@@ -3808,14 +3890,17 @@ void OpenGl_Context::SetTextureMatrix (const Handle(Graphic3d_TextureParams)& th
     // pack transformation parameters
     OpenGl_Vec4 aTrsf[2] =
     {
-      OpenGl_Vec4 (-theParams->Translation().x(),
-                   -theParams->Translation().y(),
-                    theParams->Scale().x(),
-                    theParams->Scale().y()),
+      OpenGl_Vec4 (-aTrans.x(), -aTrans.y(), aScale.x(), aScale.y()),
       OpenGl_Vec4 (static_cast<float> (std::sin (-theParams->Rotation() * M_PI / 180.0)),
                    static_cast<float> (std::cos (-theParams->Rotation() * M_PI / 180.0)),
                    0.0f, 0.0f)
     };
+    if (caps->isTopDownTextureUV != theIsTopDown)
+    {
+      // flip V
+      aTrsf[0].y() = -aTrans.y() + 1.0f / aScale.y();
+      aTrsf[0].w() = -aScale.y();
+    }
     myActiveProgram->SetUniform (this, aUniLoc, 2, aTrsf);
     return;
   }
@@ -3828,11 +3913,18 @@ void OpenGl_Context::SetTextureMatrix (const Handle(Graphic3d_TextureParams)& th
 
     core11->glMatrixMode (GL_TEXTURE);
     OpenGl_Mat4 aTextureMat;
-    const Graphic3d_Vec2& aScale = theParams->Scale();
-    const Graphic3d_Vec2& aTrans = theParams->Translation();
-    Graphic3d_TransformUtils::Scale     (aTextureMat,  aScale.x(),  aScale.y(), 1.0f);
-    Graphic3d_TransformUtils::Translate (aTextureMat, -aTrans.x(), -aTrans.y(), 0.0f);
-    Graphic3d_TransformUtils::Rotate    (aTextureMat, -theParams->Rotation(), 0.0f, 0.0f, 1.0f);
+    if (caps->isTopDownTextureUV != theIsTopDown)
+    {
+      // flip V
+      Graphic3d_TransformUtils::Scale     (aTextureMat,  aScale.x(), -aScale.y(), 1.0f);
+      Graphic3d_TransformUtils::Translate (aTextureMat, -aTrans.x(), -aTrans.y() + 1.0f / aScale.y(), 0.0f);
+    }
+    else
+    {
+      Graphic3d_TransformUtils::Scale     (aTextureMat,  aScale.x(),  aScale.y(), 1.0f);
+      Graphic3d_TransformUtils::Translate (aTextureMat, -aTrans.x(), -aTrans.y(), 0.0f);
+    }
+    Graphic3d_TransformUtils::Rotate (aTextureMat, -theParams->Rotation(), 0.0f, 0.0f, 1.0f);
     core11->glLoadMatrixf (aTextureMat);
     core11->glMatrixMode (aMatrixMode);
   }
index 3806df4..7ba13a9 100644 (file)
@@ -506,6 +506,9 @@ public:
   #endif
   }
 
+  //! Return map of supported texture formats.
+  const Handle(Image_SupportedFormats)& SupportedTextureFormats() const { return mySupportedFormats; }
+
   //! @return maximum degree of anisotropy texture filter
   Standard_Integer MaxDegreeOfAnisotropy() const { return myAnisoMax; }
 
@@ -911,7 +914,10 @@ public: //! @name methods to alter or retrieve current state
   Standard_EXPORT void SetPointSpriteOrigin();
 
   //! Setup texture matrix to active GLSL program or to FFP global state using glMatrixMode (GL_TEXTURE).
-  Standard_EXPORT void SetTextureMatrix (const Handle(Graphic3d_TextureParams)& theParams);
+  //! @param theParams    [in] texture parameters
+  //! @param theIsTopDown [in] texture top-down flag
+  Standard_EXPORT void SetTextureMatrix (const Handle(Graphic3d_TextureParams)& theParams,
+                                         const Standard_Boolean theIsTopDown);
 
   //! Bind default Vertex Array Object
   Standard_EXPORT void BindDefaultVao();
@@ -1040,7 +1046,7 @@ public: //! @name extensions
   Standard_Boolean       hasUintIndex;       //!< GLuint for index buffer is supported (always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_element_index_uint)
   Standard_Boolean       hasTexRGBA8;        //!< always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_rgb8_rgba8
   Standard_Boolean       hasTexFloatLinear;  //!< texture-filterable state for 32-bit floating texture formats (always on desktop, GL_OES_texture_float_linear within OpenGL ES)
-  Standard_Boolean       hasTexSRGB;         //!< sRGB texture    formats (desktop OpenGL 2.0, OpenGL ES 3.0 or GL_EXT_texture_sRGB)
+  Standard_Boolean       hasTexSRGB;         //!< sRGB texture    formats (desktop OpenGL 2.1, OpenGL ES 3.0 or GL_EXT_texture_sRGB)
   Standard_Boolean       hasFboSRGB;         //!< sRGB FBO render targets (desktop OpenGL 2.1, OpenGL ES 3.0)
   Standard_Boolean       hasSRGBControl;     //!< sRGB write control (any desktop OpenGL, OpenGL ES + GL_EXT_sRGB_write_control extension)
   OpenGl_FeatureFlag     hasFlatShading;     //!< Complex flag indicating support of Flat shading (Graphic3d_TOSM_FACET) (always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_standard_derivatives)
@@ -1116,6 +1122,8 @@ private: // context info
   void*            myGlLibHandle;          //!< optional handle to GL library
   NCollection_Handle<OpenGl_GlFunctions>
                    myFuncs;                //!< mega structure for all GL functions
+  Handle(Image_SupportedFormats)
+                   mySupportedFormats;     //!< map of supported texture formats
   Standard_Integer myAnisoMax;             //!< maximum level of anisotropy texture filter
   Standard_Integer myTexClamp;             //!< either GL_CLAMP_TO_EDGE (1.2+) or GL_CLAMP (1.1)
   Standard_Integer myMaxTexDim;            //!< value for GL_MAX_TEXTURE_SIZE
index 6cc1c66..0c3136e 100644 (file)
   #define GL_TRIANGLES_ADJACENCY        0x000C
   #define GL_TRIANGLE_STRIP_ADJACENCY   0x000D
   #define GL_PATCHES                    0x000E
+
+  // GL_EXT_texture_compression_s3tc extension
+  #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT  0x83F0
+  #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+  #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
+  #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
+  //
+  #define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT  0x8C4C
+  #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D
+  #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E
+  #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F
 #endif
 
 #if !defined(HAVE_EGL) && (defined(__ANDROID__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(HAVE_GLES2) || defined(OCCT_UWP))
@@ -191,87 +202,87 @@ public: //! @name OpenGL ES 1.1
 
 #if defined(GL_ES_VERSION_2_0)
 
-  inline void glActiveTexture (GLenum texture)
+  inline void glActiveTexture (GLenum texture) const
   {
     ::glActiveTexture (texture);
   }
 
-  inline void glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data)
+  inline void glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) const
   {
     ::glCompressedTexImage2D (target, level, internalformat, width, height, border, imageSize, data);
   }
 
-  inline void glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data)
+  inline void glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) const
   {
     ::glCompressedTexSubImage2D (target, level, xoffset, yoffset, width, height, format, imageSize, data);
   }
 
-  inline void glBindBuffer (GLenum target, GLuint buffer)
+  inline void glBindBuffer (GLenum target, GLuint buffer) const
   {
     ::glBindBuffer (target, buffer);
   }
 
-  inline void glBufferData (GLenum target, GLsizeiptr size, const void* data, GLenum usage)
+  inline void glBufferData (GLenum target, GLsizeiptr size, const void* data, GLenum usage) const
   {
     ::glBufferData (target, size, data, usage);
   }
 
-  inline void glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void* data)
+  inline void glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void* data) const
   {
     ::glBufferSubData (target, offset, size, data);
   }
 
-  inline void glDeleteBuffers (GLsizei n, const GLuint *buffers)
+  inline void glDeleteBuffers (GLsizei n, const GLuint *buffers) const
   {
     ::glDeleteBuffers (n, buffers);
   }
 
-  inline void glDeleteTextures (GLsizei n, const GLuint *textures)
+  inline void glDeleteTextures (GLsizei n, const GLuint *textures) const
   {
     ::glDeleteTextures (n, textures);
   }
 
-  inline void glDepthFunc (GLenum func)
+  inline void glDepthFunc (GLenum func) const
   {
     ::glDepthFunc (func);
   }
 
-  inline void glDepthMask (GLboolean flag)
+  inline void glDepthMask (GLboolean flag) const
   {
     ::glDepthMask (flag);
   }
 
-  inline void glDepthRangef (GLfloat n, GLfloat f)
+  inline void glDepthRangef (GLfloat n, GLfloat f) const
   {
     ::glDepthRangef (n, f);
   }
 
-  inline void glGenBuffers (GLsizei n, GLuint *buffers)
+  inline void glGenBuffers (GLsizei n, GLuint *buffers) const
   {
     ::glGenBuffers (n, buffers);
   }
 
-  inline void glGenTextures (GLsizei n, GLuint *textures)
+  inline void glGenTextures (GLsizei n, GLuint *textures) const
   {
     ::glGenTextures (n, textures);
   }
 
-  inline void glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params)
+  inline void glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params) const
   {
     ::glGetBufferParameteriv (target, pname, params);
   }
 
-  inline GLboolean glIsBuffer (GLuint buffer)
+  inline GLboolean glIsBuffer (GLuint buffer) const
   {
     return ::glIsBuffer (buffer);
   }
 
-  inline void glSampleCoverage (GLfloat value, GLboolean invert)
+  inline void glSampleCoverage (GLfloat value, GLboolean invert) const
   {
     ::glSampleCoverage (value, invert);
   }
 
-  inline void glMultiDrawElements (GLenum theMode, const GLsizei* theCount, GLenum theType, const void* const* theIndices, GLsizei theDrawCount)
+  inline void glMultiDrawElements (GLenum theMode, const GLsizei* theCount, GLenum theType, const void* const* theIndices, GLsizei theDrawCount) const
   {
     if (theCount   == NULL
      || theIndices == NULL)
@@ -290,422 +301,422 @@ public: //! @name OpenGL ES 1.1
 public: //! @name OpenGL ES 2.0
 
 #if defined(GL_ES_VERSION_2_0)
-  inline void glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+  inline void glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) const
   {
     ::glBlendColor (red, green, blue, alpha);
   }
 
-  inline void glBlendEquation (GLenum mode)
+  inline void glBlendEquation (GLenum mode) const
   {
     ::glBlendEquation (mode);
   }
 
-  inline void glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha)
+  inline void glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) const
   {
     ::glBlendFuncSeparate (sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
   }
 
-  inline void glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha)
+  inline void glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha) const
   {
     ::glBlendEquationSeparate (modeRGB, modeAlpha);
   }
 
-  inline void glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass)
+  inline void glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) const
   {
     ::glStencilOpSeparate (face, sfail, dpfail, dppass);
   }
 
-  inline void glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask)
+  inline void glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask) const
   {
     ::glStencilFuncSeparate (face, func, ref, mask);
   }
 
-  inline void glStencilMaskSeparate (GLenum face, GLuint mask)
+  inline void glStencilMaskSeparate (GLenum face, GLuint mask) const
   {
     ::glStencilMaskSeparate (face, mask);
   }
 
-  inline void glAttachShader (GLuint program, GLuint shader)
+  inline void glAttachShader (GLuint program, GLuint shader) const
   {
     ::glAttachShader (program, shader);
   }
 
-  inline void glBindAttribLocation (GLuint program, GLuint index, const GLchar *name)
+  inline void glBindAttribLocation (GLuint program, GLuint index, const GLchar *name) const
   {
     ::glBindAttribLocation (program, index, name);
   }
 
-  inline void glBindFramebuffer (GLenum target, GLuint framebuffer)
+  inline void glBindFramebuffer (GLenum target, GLuint framebuffer) const
   {
     ::glBindFramebuffer (target, framebuffer);
   }
 
-  inline void glBindRenderbuffer (GLenum target, GLuint renderbuffer)
+  inline void glBindRenderbuffer (GLenum target, GLuint renderbuffer) const
   {
     ::glBindRenderbuffer (target, renderbuffer);
   }
 
-  inline GLenum glCheckFramebufferStatus (GLenum target)
+  inline GLenum glCheckFramebufferStatus (GLenum target) const
   {
     return ::glCheckFramebufferStatus (target);
   }
 
-  inline void glCompileShader (GLuint shader)
+  inline void glCompileShader (GLuint shader) const
   {
     ::glCompileShader (shader);
   }
 
-  inline GLuint glCreateProgram()
+  inline GLuint glCreateProgram() const
   {
     return ::glCreateProgram();
   }
 
-  inline GLuint glCreateShader (GLenum type)
+  inline GLuint glCreateShader (GLenum type) const
   {
     return ::glCreateShader (type);
   }
 
-  inline void glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers)
+  inline void glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers) const
   {
     ::glDeleteFramebuffers (n, framebuffers);
   }
 
-  inline void glDeleteProgram (GLuint program)
+  inline void glDeleteProgram (GLuint program) const
   {
     ::glDeleteProgram (program);
   }
 
-  inline void glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers)
+  inline void glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers) const
   {
     ::glDeleteRenderbuffers (n, renderbuffers);
   }
 
-  inline void glDeleteShader (GLuint shader)
+  inline void glDeleteShader (GLuint shader) const
   {
     ::glDeleteShader (shader);
   }
 
-  inline void glDetachShader (GLuint program, GLuint shader)
+  inline void glDetachShader (GLuint program, GLuint shader) const
   {
     ::glDetachShader (program, shader);
   }
 
-  inline void glDisableVertexAttribArray (GLuint index)
+  inline void glDisableVertexAttribArray (GLuint index) const
   {
     ::glDisableVertexAttribArray (index);
   }
 
-  inline void glEnableVertexAttribArray (GLuint index)
+  inline void glEnableVertexAttribArray (GLuint index) const
   {
     ::glEnableVertexAttribArray (index);
   }
 
-  inline void glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+  inline void glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) const
   {
     ::glFramebufferRenderbuffer (target, attachment, renderbuffertarget, renderbuffer);
   }
 
-  inline void glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+  inline void glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) const
   {
     ::glFramebufferTexture2D (target, attachment, textarget, texture, level);
   }
 
-  inline void glGenerateMipmap (GLenum target)
+  inline void glGenerateMipmap (GLenum target) const
   {
     ::glGenerateMipmap (target);
   }
 
-  inline void glGenFramebuffers (GLsizei n, GLuint *framebuffers)
+  inline void glGenFramebuffers (GLsizei n, GLuint *framebuffers) const
   {
     ::glGenFramebuffers (n, framebuffers);
   }
 
-  inline void glGenRenderbuffers (GLsizei n, GLuint *renderbuffers)
+  inline void glGenRenderbuffers (GLsizei n, GLuint *renderbuffers) const
   {
     ::glGenRenderbuffers (n, renderbuffers);
   }
 
-  inline void glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint* size, GLenum *type, GLchar *name)
+  inline void glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint* size, GLenum *type, GLchar *name) const
   {
     ::glGetActiveAttrib (program, index, bufSize, length, size, type, name);
   }
 
-  inline void glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint* size, GLenum *type, GLchar *name)
+  inline void glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint* size, GLenum *type, GLchar *name) const
   {
     ::glGetActiveUniform (program, index, bufSize, length, size, type, name);
   }
 
-  inline void glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders)
+  inline void glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders) const
   {
     ::glGetAttachedShaders (program, maxCount, count, shaders);
   }
 
-  inline GLint glGetAttribLocation (GLuint program, const GLchar *name)
+  inline GLint glGetAttribLocation (GLuint program, const GLchar *name) const
   {
     return ::glGetAttribLocation (program, name);
   }
 
-  inline void glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params)
+  inline void glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params) const
   {
     ::glGetFramebufferAttachmentParameteriv (target, attachment, pname, params);
   }
 
-  inline void glGetProgramiv (GLuint program, GLenum pname, GLint* params)
+  inline void glGetProgramiv (GLuint program, GLenum pname, GLint* params) const
   {
     ::glGetProgramiv (program, pname, params);
   }
 
-  inline void glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog)
+  inline void glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) const
   {
     ::glGetProgramInfoLog (program, bufSize, length, infoLog);
   }
 
-  inline void glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params)
+  inline void glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params) const
   {
     ::glGetRenderbufferParameteriv (target, pname, params);
   }
 
-  inline void glGetShaderiv (GLuint shader, GLenum pname, GLint* params)
+  inline void glGetShaderiv (GLuint shader, GLenum pname, GLint* params) const
   {
     ::glGetShaderiv (shader, pname, params);
   }
 
-  inline void glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog)
+  inline void glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) const
   {
     ::glGetShaderInfoLog (shader, bufSize, length, infoLog);
   }
 
-  inline void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+  inline void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) const
   {
     ::glGetShaderPrecisionFormat (shadertype, precisiontype, range, precision);
   }
 
-  inline void glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source)
+  inline void glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source) const
   {
     ::glGetShaderSource (shader, bufSize, length, source);
   }
 
-  inline void glGetUniformfv (GLuint program, GLint location, GLfloat* params)
+  inline void glGetUniformfv (GLuint program, GLint location, GLfloat* params) const
   {
     ::glGetUniformfv (program, location, params);
   }
 
-  inline void glGetUniformiv (GLuint program, GLint location, GLint* params)
+  inline void glGetUniformiv (GLuint program, GLint location, GLint* params) const
   {
     ::glGetUniformiv (program, location, params);
   }
 
-  GLint glGetUniformLocation (GLuint program, const GLchar *name)
+  GLint glGetUniformLocation (GLuint program, const GLchar *name) const
   {
     return ::glGetUniformLocation (program, name);
   }
 
-  inline void glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params)
+  inline void glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params) const
   {
     ::glGetVertexAttribfv (index, pname, params);
   }
 
-  inline void glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params)
+  inline void glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params) const
   {
     ::glGetVertexAttribiv (index, pname, params);
   }
 
-  inline void glGetVertexAttribPointerv (GLuint index, GLenum pname, void* *pointer)
+  inline void glGetVertexAttribPointerv (GLuint index, GLenum pname, void* *pointer) const
   {
     ::glGetVertexAttribPointerv (index, pname, pointer);
   }
 
-  inline GLboolean glIsFramebuffer (GLuint framebuffer)
+  inline GLboolean glIsFramebuffer (GLuint framebuffer) const
   {
     return ::glIsFramebuffer (framebuffer);
   }
 
-  inline GLboolean glIsProgram (GLuint program)
+  inline GLboolean glIsProgram (GLuint program) const
   {
     return ::glIsProgram (program);
   }
 
-  inline GLboolean glIsRenderbuffer (GLuint renderbuffer)
+  inline GLboolean glIsRenderbuffer (GLuint renderbuffer) const
   {
     return ::glIsRenderbuffer (renderbuffer);
   }
 
-  inline GLboolean glIsShader (GLuint shader)
+  inline GLboolean glIsShader (GLuint shader) const
   {
     return ::glIsShader (shader);
   }
 
-  inline void glLinkProgram (GLuint program)
+  inline void glLinkProgram (GLuint program) const
   {
     ::glLinkProgram (program);
   }
 
-  inline void glReleaseShaderCompiler()
+  inline void glReleaseShaderCompiler() const
   {
     ::glReleaseShaderCompiler();
   }
 
-  inline void glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+  inline void glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height) const
   {
     ::glRenderbufferStorage (target, internalformat, width, height);
   }
 
-  inline void glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void* binary, GLsizei length)
+  inline void glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void* binary, GLsizei length) const
   {
     ::glShaderBinary (count, shaders, binaryformat, binary, length);
   }
 
-  inline void glShaderSource (GLuint shader, GLsizei count, const GLchar** string, const GLint* length)
+  inline void glShaderSource (GLuint shader, GLsizei count, const GLchar** string, const GLint* length) const
   {
     ::glShaderSource (shader, count, string, length);
   }
 
-  inline void glUniform1f (GLint location, GLfloat v0)
+  inline void glUniform1f (GLint location, GLfloat v0) const
   {
     ::glUniform1f (location, v0);
   }
 
-  inline void glUniform1fv (GLint location, GLsizei count, const GLfloat* value)
+  inline void glUniform1fv (GLint location, GLsizei count, const GLfloat* value) const
   {
     ::glUniform1fv (location, count, value);
   }
 
-  inline void glUniform1i (GLint location, GLint v0)
+  inline void glUniform1i (GLint location, GLint v0) const
   {
     ::glUniform1i (location, v0);
   }
 
-  inline void glUniform1iv (GLint location, GLsizei count, const GLint* value)
+  inline void glUniform1iv (GLint location, GLsizei count, const GLint* value) const
   {
     ::glUniform1iv (location, count, value);
   }
 
-  inline void glUniform2f (GLint location, GLfloat v0, GLfloat v1)
+  inline void glUniform2f (GLint location, GLfloat v0, GLfloat v1) const
   {
     ::glUniform2f (location, v0, v1);
   }
 
-  inline void glUniform2fv (GLint location, GLsizei count, const GLfloat* value)
+  inline void glUniform2fv (GLint location, GLsizei count, const GLfloat* value) const
   {
     ::glUniform2fv (location, count, value);
   }
 
-  inline void glUniform2i (GLint location, GLint v0, GLint v1)
+  inline void glUniform2i (GLint location, GLint v0, GLint v1) const
   {
     ::glUniform2i (location, v0, v1);
   }
 
-  inline void glUniform2iv (GLint location, GLsizei count, const GLint* value)
+  inline void glUniform2iv (GLint location, GLsizei count, const GLint* value) const
   {
     ::glUniform2iv (location, count, value);
   }
 
-  inline void glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2)
+  inline void glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2) const
   {
     ::glUniform3f (location, v0, v1, v2);
   }
 
-  inline void glUniform3fv (GLint location, GLsizei count, const GLfloat* value)
+  inline void glUniform3fv (GLint location, GLsizei count, const GLfloat* value) const
   {
     ::glUniform3fv (location, count, value);
   }
 
-  inline void glUniform3i (GLint location, GLint v0, GLint v1, GLint v2)
+  inline void glUniform3i (GLint location, GLint v0, GLint v1, GLint v2) const
   {
     ::glUniform3i (location, v0, v1, v2);
   }
 
-  inline void glUniform3iv (GLint location, GLsizei count, const GLint* value)
+  inline void glUniform3iv (GLint location, GLsizei count, const GLint* value) const
   {
     ::glUniform3iv (location, count, value);
   }
 
-  inline void glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
+  inline void glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) const
   {
     ::glUniform4f (location, v0, v1, v2, v3);
   }
 
-  inline void glUniform4fv (GLint location, GLsizei count, const GLfloat* value)
+  inline void glUniform4fv (GLint location, GLsizei count, const GLfloat* value) const
   {
     ::glUniform4fv (location, count, value);
   }
 
-  inline void glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3)
+  inline void glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3) const
   {
     ::glUniform4i (location, v0, v1, v2, v3);
   }
 
-  inline void glUniform4iv (GLint location, GLsizei count, const GLint* value)
+  inline void glUniform4iv (GLint location, GLsizei count, const GLint* value) const
   {
     ::glUniform4iv (location, count, value);
   }
 
-  inline void glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  inline void glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) const
   {
     ::glUniformMatrix2fv (location, count, transpose, value);
   }
 
-  inline void glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  inline void glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) const
   {
     ::glUniformMatrix3fv (location, count, transpose, value);
   }
 
-  inline void glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  inline void glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) const
   {
     ::glUniformMatrix4fv (location, count, transpose, value);
   }
 
-  inline void glUseProgram (GLuint program)
+  inline void glUseProgram (GLuint program) const
   {
     ::glUseProgram (program);
   }
 
-  inline void glValidateProgram (GLuint program)
+  inline void glValidateProgram (GLuint program) const
   {
     ::glValidateProgram (program);
   }
 
-  inline void glVertexAttrib1f (GLuint index, GLfloat x)
+  inline void glVertexAttrib1f (GLuint index, GLfloat x) const
   {
     ::glVertexAttrib1f (index, x);
   }
 
-  inline void glVertexAttrib1fv (GLuint index, const GLfloat* v)
+  inline void glVertexAttrib1fv (GLuint index, const GLfloat* v) const
   {
     ::glVertexAttrib1fv (index, v);
   }
 
-  inline void glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y)
+  inline void glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y) const
   {
     ::glVertexAttrib2f (index, x, y);
   }
 
-  inline void glVertexAttrib2fv (GLuint index, const GLfloat* v)
+  inline void glVertexAttrib2fv (GLuint index, const GLfloat* v) const
   {
     ::glVertexAttrib2fv (index, v);
   }
 
-  inline void glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z)
+  inline void glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z) const
   {
     ::glVertexAttrib3f (index, x, y, z);
   }
 
-  inline void glVertexAttrib3fv (GLuint index, const GLfloat* v)
+  inline void glVertexAttrib3fv (GLuint index, const GLfloat* v) const
   {
     ::glVertexAttrib3fv (index, v);
   }
 
-  inline void glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+  inline void glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) const
   {
     ::glVertexAttrib4f (index, x, y, z, w);
   }
 
-  inline void glVertexAttrib4fv (GLuint index, const GLfloat* v)
+  inline void glVertexAttrib4fv (GLuint index, const GLfloat* v) const
   {
     ::glVertexAttrib4fv (index, v);
   }
 
-  inline void glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer)
+  inline void glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer) const
   {
     ::glVertexAttribPointer (index, size, type, normalized, stride, pointer);
   }
index 38f0475..2b8cb2f 100644 (file)
@@ -1020,7 +1020,7 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
     {
       if (const Handle(OpenGl_Texture)& aFirstTexture = aTextureSet->First())
       {
-        aCtx->SetTextureMatrix (aFirstTexture->Sampler()->Parameters());
+        aCtx->SetTextureMatrix (aFirstTexture->Sampler()->Parameters(), aFirstTexture->IsTopDown());
       }
     }
     aCtx->SetSampleAlphaToCoverage (aCtx->ShaderManager()->MaterialState().HasAlphaCutoff());
index 6e7bb10..3ec1e07 100644 (file)
@@ -105,7 +105,7 @@ Standard_Boolean OpenGl_Sampler::Init (const Handle(OpenGl_Context)& theCtx,
     }
     else if (!myIsImmutable)
     {
-      applySamplerParams (theCtx, myParams, this, theTexture.GetTarget(), theTexture.HasMipmaps());
+      applySamplerParams (theCtx, myParams, this, theTexture.GetTarget(), theTexture.MaxMipmapLevel());
       return Standard_True;
     }
     Release (theCtx.get());
@@ -116,7 +116,7 @@ Standard_Boolean OpenGl_Sampler::Init (const Handle(OpenGl_Context)& theCtx,
     return Standard_False;
   }
 
-  applySamplerParams (theCtx, myParams, this, theTexture.GetTarget(), theTexture.HasMipmaps());
+  applySamplerParams (theCtx, myParams, this, theTexture.GetTarget(), theTexture.MaxMipmapLevel());
   return Standard_True;
 }
 
@@ -187,7 +187,7 @@ void OpenGl_Sampler::applySamplerParams (const Handle(OpenGl_Context)& theCtx,
                                          const Handle(Graphic3d_TextureParams)& theParams,
                                          OpenGl_Sampler* theSampler,
                                          const GLenum theTarget,
-                                         const bool theHasMipMaps)
+                                         const Standard_Integer theMaxMipLevels)
 {
   if (theSampler != NULL && theSampler->Parameters() == theParams)
   {
@@ -197,7 +197,7 @@ void OpenGl_Sampler::applySamplerParams (const Handle(OpenGl_Context)& theCtx,
   // setup texture filtering
   const GLenum aFilter = (theParams->Filter() == Graphic3d_TOTF_NEAREST) ? GL_NEAREST : GL_LINEAR;
   GLenum aFilterMin = aFilter;
-  if (theHasMipMaps)
+  if (theMaxMipLevels > 0)
   {
     aFilterMin = GL_NEAREST_MIPMAP_NEAREST;
     if (theParams->Filter() == Graphic3d_TOTF_BILINEAR)
@@ -266,8 +266,9 @@ void OpenGl_Sampler::applySamplerParams (const Handle(OpenGl_Context)& theCtx,
   if (theCtx->HasTextureBaseLevel()
    && (theSampler == NULL || !theSampler->isValidSampler()))
   {
+    const Standard_Integer aMaxLevel = Min (theMaxMipLevels, theParams->MaxLevel());
     setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_BASE_LEVEL, theParams->BaseLevel());
-    setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_MAX_LEVEL,  theParams->MaxLevel());
+    setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_MAX_LEVEL,  aMaxLevel);
   }
 }
 
index bb74235..8a2b91e 100644 (file)
@@ -129,13 +129,17 @@ protected:
                                             GLint  theValue);
 
   //! Apply sampler parameters.
-  //! If Sampler Object is not NULL and valid resource, the parameters will be set to it (and it is not required Sampler Object being bound).
-  //! Otherwise, parameters will be applied to currently bound Texture object.
+  //! @param theCtx     [in] active OpenGL context
+  //! @param theParams  [in] texture parameters to apply
+  //! @param theSampler [in] apply parameters to Texture object (NULL)
+  //!                        or to specified Sampler object (non-NULL, sampler is not required to be bound)
+  //! @param theTarget  [in] OpenGL texture target
+  //! @param theMaxMipLevel [in] maximum mipmap level defined within the texture
   Standard_EXPORT static void applySamplerParams (const Handle(OpenGl_Context)& theCtx,
                                                   const Handle(Graphic3d_TextureParams)& theParams,
                                                   OpenGl_Sampler* theSampler,
                                                   const GLenum theTarget,
-                                                  const bool theHasMipMaps);
+                                                  const Standard_Integer theMaxMipLevel);
 
   //! Apply global texture state for deprecated OpenGL functionality.
   Standard_EXPORT static void applyGlobalTextureParams (const Handle(OpenGl_Context)& theCtx,
index 651ceed..06e352b 100644 (file)
@@ -58,10 +58,9 @@ namespace
 const char THE_VARY_TexCoord_Trsf[] =
   EOL"  float aRotSin = occTextureTrsf_RotationSin();"
   EOL"  float aRotCos = occTextureTrsf_RotationCos();"
-  EOL"  vec2  aTex2   = (occTexCoord.xy + occTextureTrsf_Translation()) * occTextureTrsf_Scale();"
-  EOL"  vec2  aCopy   = aTex2;"
-  EOL"  aTex2.x = aCopy.x * aRotCos - aCopy.y * aRotSin;"
-  EOL"  aTex2.y = aCopy.x * aRotSin + aCopy.y * aRotCos;"
+  EOL"  vec2  aTex2   = vec2 (occTexCoord.x * aRotCos - occTexCoord.y * aRotSin,"
+  EOL"                        occTexCoord.x * aRotSin + occTexCoord.y * aRotCos);"
+  EOL"  aTex2 = (aTex2 + occTextureTrsf_Translation()) * occTextureTrsf_Scale();"
   EOL"  TexCoord = vec4(aTex2, occTexCoord.zw);";
 
 //! Auxiliary function to flip gl_PointCoord vertically
index aa01fac..383e7f5 100644 (file)
 #include <Graphic3d_TextureParams.hxx>
 #include <TCollection_ExtendedString.hxx>
 #include <Standard_Assert.hxx>
+#include <Image_CompressedPixMap.hxx>
 #include <Image_PixMap.hxx>
+#include <Image_SupportedFormats.hxx>
 
 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_NamedResource)
 
+namespace
+{
+
 //! Simple class to reset unpack alignment settings
 struct OpenGl_UnpackAlignmentSentry
 {
@@ -47,6 +52,43 @@ struct OpenGl_UnpackAlignmentSentry
 
 };
 
+//! Compute the upper mipmap level for complete mipmap set (e.g. till the 1x1 level).
+static Standard_Integer computeUpperMipMapLevel (Standard_Integer theSize)
+{
+  for (Standard_Integer aMipIter = 0;; ++aMipIter, theSize /= 2)
+  {
+    if (theSize <= 1)
+    {
+      return aMipIter;
+    }
+  }
+}
+
+//! Compute the upper mipmap level for complete mipmap set (e.g. till the 1x1 level).
+static Standard_Integer computeUpperMipMapLevel (Standard_Integer theSizeX, Standard_Integer theSizeY)
+{
+  return computeUpperMipMapLevel (Max (theSizeX, theSizeY));
+}
+
+//! Compute size of the smallest defined mipmap level (for verbose messages).
+static Graphic3d_Vec2i computeSmallestMipMapSize (const Graphic3d_Vec2i& theBaseSize, Standard_Integer theMaxLevel)
+{
+  Graphic3d_Vec2i aMipSizeXY = theBaseSize;
+  for (Standard_Integer aMipIter = 0;; ++aMipIter)
+  {
+    if (aMipIter > theMaxLevel)
+    {
+      return aMipSizeXY;
+    }
+
+    aMipSizeXY /= 2;
+    if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
+    if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
+  }
+}
+
+}
+
 // =======================================================================
 // function : OpenGl_Texture
 // purpose  :
@@ -64,8 +106,9 @@ OpenGl_Texture::OpenGl_Texture (const TCollection_AsciiString& theResourceId,
   myTextFormat (GL_RGBA),
   mySizedFormat(GL_RGBA8),
   myNbSamples  (1),
-  myHasMipmaps (Standard_False),
-  myIsAlpha    (false)
+  myMaxMipLevel(0),
+  myIsAlpha    (false),
+  myIsTopDown  (true)
 {
   //
 }
@@ -130,10 +173,10 @@ void OpenGl_Texture::Release (OpenGl_Context* theGlCtx)
 // =======================================================================
 void OpenGl_Texture::applyDefaultSamplerParams (const Handle(OpenGl_Context)& theCtx)
 {
-  OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), NULL, myTarget, myHasMipmaps);
+  OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), NULL, myTarget, myMaxMipLevel);
   if (mySampler->IsValid() && !mySampler->IsImmutable())
   {
-    OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), mySampler.get(), myTarget, myHasMipmaps);
+    OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), mySampler.get(), myTarget, myMaxMipLevel);
   }
 }
 
@@ -203,11 +246,10 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
 #else
   const GLenum aTarget = GL_TEXTURE_2D;
 #endif
-  const Standard_Boolean toCreateMipMaps = (theType == Graphic3d_TOT_2D_MIPMAP);
   const bool toPatchExisting = IsValid()
                             && myTextFormat == theFormat.PixelFormat()
                             && myTarget == aTarget
-                            && myHasMipmaps == toCreateMipMaps
+                            && HasMipmaps() == (theType == Graphic3d_TOT_2D_MIPMAP)
                             && mySizeX  == theSizeXY.x()
                             && (mySizeY == theSizeXY.y() || theType == Graphic3d_TOT_1D);
   if (!Create (theCtx))
@@ -220,16 +262,19 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
   {
     myIsAlpha = theImage->Format() == Image_Format_Alpha
              || theImage->Format() == Image_Format_AlphaF;
+    myIsTopDown = theImage->IsTopDown();
   }
   else
   {
     myIsAlpha = theFormat.PixelFormat() == GL_ALPHA;
   }
 
-  myHasMipmaps             = toCreateMipMaps;
-  myTextFormat             = theFormat.PixelFormat();
-  mySizedFormat            = theFormat.InternalFormat();
-  myNbSamples              = 1;
+  myMaxMipLevel = theType == Graphic3d_TOT_2D_MIPMAP && theCtx->arbFBO != NULL
+                ? computeUpperMipMapLevel (theSizeXY.x(), theSizeXY.y())
+                : 0;
+  myTextFormat  = theFormat.PixelFormat();
+  mySizedFormat = theFormat.InternalFormat();
+  myNbSamples   = 1;
 #if !defined(GL_ES_VERSION_2_0)
   const GLint anIntFormat  = theFormat.InternalFormat();
 #else
@@ -294,8 +339,7 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
 #endif
 
 #if !defined(GL_ES_VERSION_2_0)
-  GLint aTestWidth  = 0;
-  GLint aTestHeight = 0;
+  GLint aTestWidth  = 0, aTestHeight = 0;
 #endif
   GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL;
 
@@ -369,58 +413,6 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
     #endif
     }
     case Graphic3d_TOT_2D:
-    {
-      Bind (theCtx);
-      applyDefaultSamplerParams (theCtx);
-      if (toPatchExisting)
-      {
-        glTexSubImage2D (GL_TEXTURE_2D, 0,
-                         0, 0,
-                         theSizeXY.x(), theSizeXY.y(),
-                         theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
-        Unbind (theCtx);
-        return true;
-      }
-
-    #if !defined(GL_ES_VERSION_2_0)
-      // use proxy to check texture could be created or not
-      glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
-                    theSizeXY.x(), theSizeXY.y(), 0,
-                    theFormat.PixelFormat(), theFormat.DataType(), NULL);
-      glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,  &aTestWidth);
-      glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
-      glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
-      if (aTestWidth == 0 || aTestHeight == 0)
-      {
-        // no memory or broken input parameters
-        Unbind (theCtx);
-        Release (theCtx.get());
-        return false;
-      }
-    #endif
-
-      glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
-                    theSizeXY.x(), theSizeXY.y(), 0,
-                    theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
-      const GLenum anErr = glGetError();
-      if (anErr != GL_NO_ERROR)
-      {
-        theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
-                             TCollection_AsciiString ("Error: 2D texture ") + theSizeXY.x() + "x" + theSizeXY.y()
-                                                   + " IF: " + int(anIntFormat) + " PF: " + int(theFormat.PixelFormat())
-                                                   + " DT: " + int(theFormat.DataType())
-                                                   + " can not be created with error " + int(anErr) + ".");
-        Unbind (theCtx);
-        Release (theCtx.get());
-        return false;
-      }
-
-      mySizeX = theSizeXY.x();
-      mySizeY = theSizeXY.y();
-
-      Unbind (theCtx);
-      return true;
-    }
     case Graphic3d_TOT_2D_MIPMAP:
     {
       Bind (theCtx);
@@ -431,15 +423,14 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
                          0, 0,
                          theSizeXY.x(), theSizeXY.y(),
                          theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
-        if (theCtx->arbFBO != NULL)
+
+        if (myMaxMipLevel > 0)
         {
           // generate mipmaps
           theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
           if (glGetError() != GL_NO_ERROR)
           {
-            Unbind (theCtx);
-            Release (theCtx.get());
-            return false;
+            myMaxMipLevel = 0;
           }
         }
 
@@ -464,18 +455,17 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
       }
     #endif
 
-      // upload main picture
       glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
                     theSizeXY.x(), theSizeXY.y(), 0,
-                    theFormat.PixelFormat(), theFormat.DataType(), theImage->Data());
-      const GLenum aTexImgErr = glGetError();
-      if (aTexImgErr != GL_NO_ERROR)
+                    theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
+      GLenum anErr = glGetError();
+      if (anErr != GL_NO_ERROR)
       {
         theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
                              TCollection_AsciiString ("Error: 2D texture ") + theSizeXY.x() + "x" + theSizeXY.y()
-                                                    + " IF: " + int(anIntFormat) + " PF: " + int(theFormat.PixelFormat())
-                                                    + " DT: " + int(theFormat.DataType())
-                                                    + " can not be created with error " + int(aTexImgErr) + ".");
+                                                   + " IF: " + int(anIntFormat) + " PF: " + int(theFormat.PixelFormat())
+                                                   + " DT: " + int(theFormat.DataType())
+                                                   + " can not be created with error " + int(anErr) + ".");
         Unbind (theCtx);
         Release (theCtx.get());
         return false;
@@ -484,27 +474,19 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
       mySizeX = theSizeXY.x();
       mySizeY = theSizeXY.y();
 
-      if (theCtx->arbFBO != NULL)
+      if (myMaxMipLevel > 0)
       {
         // generate mipmaps
         //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
         theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
-
-        if (glGetError() != GL_NO_ERROR)
+        anErr = glGetError();
+        if (anErr != GL_NO_ERROR)
         {
-          Unbind (theCtx);
-          Release (theCtx.get());
-          return false;
+          myMaxMipLevel = 0;
+          theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
+                               "Warning: generating mipmaps requires GL_ARB_framebuffer_object extension which is missing.");
         }
       }
-      else
-      {
-        theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
-                             "Warning: generating mipmaps requires GL_ARB_framebuffer_object extension which is missing.");
-        Unbind (theCtx);
-        Release (theCtx.get());
-        return false;
-      }
 
       Unbind (theCtx);
       return true;
@@ -568,7 +550,16 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)&       theCtx,
     }
     default:
     {
-      Handle(Image_PixMap) anImage = theTextureMap->GetImage();
+      if (theCtx->SupportedTextureFormats()->HasCompressed()
+      && !theCtx->caps->compressedTexturesDisable)
+      {
+        if (Handle(Image_CompressedPixMap) aCompressed = theTextureMap->GetCompressedImage (theCtx->SupportedTextureFormats()))
+        {
+          return InitCompressed (theCtx, *aCompressed, theTextureMap->IsColorMap());
+        }
+      }
+
+      Handle(Image_PixMap) anImage = theTextureMap->GetImage (theCtx->SupportedTextureFormats());
       if (anImage.IsNull())
       {
         return false;
@@ -579,6 +570,106 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)&       theCtx,
 }
 
 // =======================================================================
+// function : InitCompressed
+// purpose  :
+// =======================================================================
+bool OpenGl_Texture::InitCompressed (const Handle(OpenGl_Context)& theCtx,
+                                     const Image_CompressedPixMap& theImage,
+                                     const Standard_Boolean        theIsColorMap)
+{
+  if (theImage.SizeX() < 1
+   || theImage.SizeY() < 1
+   || theImage.FaceData().IsNull())
+  {
+    theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                         "Error: texture of 0 size cannot be created.");
+    Release (theCtx.get());
+    return false;
+  }
+  if (theImage.SizeX() > theCtx->MaxTextureSize()
+   || theImage.SizeY() > theCtx->MaxTextureSize())
+  {
+    theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                         TCollection_AsciiString ("Error: Texture dimension - ") + theImage.SizeX() + "x" + theImage.SizeY()
+                       + " exceeds hardware limits (" + theCtx->MaxTextureSize() + "x" + theCtx->MaxTextureSize() + ")");
+    Release (theCtx.get());
+    return false;
+  }
+
+  const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindCompressedFormat (theCtx, theImage.CompressedFormat(), theIsColorMap);
+  if (!aFormat.IsValid())
+  {
+    Release (theCtx.get());
+    return false;
+  }
+
+  if (!Create (theCtx))
+  {
+    return false;
+  }
+
+  myTarget = GL_TEXTURE_2D;
+  myNbSamples = 1;
+  myTextFormat  = aFormat.Format();
+  mySizedFormat = aFormat.Internal();
+  myIsTopDown = theImage.IsTopDown();
+  mySizeX = theImage.SizeX();
+  mySizeY = theImage.SizeY();
+  myMaxMipLevel = Max (theImage.MipMaps().Size() - 1, 0);
+  if (myMaxMipLevel > 0
+  && !theImage.IsCompleteMipMapSet())
+  {
+    const Graphic3d_Vec2i aMipSize = computeSmallestMipMapSize (Graphic3d_Vec2i (mySizeX, mySizeY), myMaxMipLevel);
+    if (!theCtx->HasTextureBaseLevel())
+    {
+      myMaxMipLevel = 0;
+      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_MEDIUM,
+                           TCollection_AsciiString ("Warning: compressed 2D texture ") + myResourceId + " " + mySizeX + "x" + mySizeY
+                           + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y() + "; mipmaps will be ignored");
+    }
+    else
+    {
+      Message::SendTrace (TCollection_AsciiString ("Warning: compressed 2D texture ") + myResourceId + " " + mySizeX + "x" + mySizeY
+                          + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y());
+    }
+  }
+
+  Bind (theCtx);
+  applyDefaultSamplerParams (theCtx);
+
+  // setup the alignment
+  OpenGl_UnpackAlignmentSentry::Reset();
+
+  Graphic3d_Vec2i aMipSizeXY (theImage.SizeX(), theImage.SizeY());
+  const Standard_Byte* aData = theImage.FaceData()->Data();
+  for (Standard_Integer aMipIter = 0; aMipIter <= myMaxMipLevel; ++aMipIter)
+  {
+    const Standard_Integer aMipLength = theImage.MipMaps().Value (aMipIter);
+    theCtx->Functions()->glCompressedTexImage2D (GL_TEXTURE_2D, aMipIter, mySizedFormat, aMipSizeXY.x(), aMipSizeXY.y(), 0, aMipLength, aData);
+    const GLenum aTexImgErr = glGetError();
+    if (aTexImgErr != GL_NO_ERROR)
+    {
+      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                           TCollection_AsciiString ("Error: 2D compressed texture ") + aMipSizeXY.x() + "x" + aMipSizeXY.y()
+                           + " IF: " + int(aFormat.Internal()) + " PF: " + int(aFormat.PixelFormat())
+                           + " DT: " + int(aFormat.DataType())
+                           + " can not be created with error " + int(aTexImgErr) + ".");
+      Unbind (theCtx);
+      Release (theCtx.get());
+      return false;
+    }
+
+    aData += aMipLength;
+    aMipSizeXY /= 2;
+    if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
+    if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
+  }
+
+  Unbind (theCtx);
+  return true;
+}
+
+// =======================================================================
 // function : Init2DMultisample
 // purpose  :
 // =======================================================================
@@ -597,7 +688,7 @@ bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
 
   myNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples());
   myTarget = GL_TEXTURE_2D_MULTISAMPLE;
-  myHasMipmaps = false;
+  myMaxMipLevel = 0;
   if(theSizeX > theCtx->MaxTextureSize()
   || theSizeY > theCtx->MaxTextureSize())
   {
@@ -649,7 +740,7 @@ bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
 #if !defined(GL_ES_VERSION_2_0)
   myTarget = GL_TEXTURE_RECTANGLE;
   myNbSamples = 1;
-  myHasMipmaps = false;
+  myMaxMipLevel = 0;
 
   const GLsizei aSizeX    = Min (theCtx->MaxTextureSize(), theSizeX);
   const GLsizei aSizeY    = Min (theCtx->MaxTextureSize(), theSizeY);
@@ -726,7 +817,7 @@ bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
 
   myTarget = GL_TEXTURE_3D;
   myNbSamples = 1;
-  myHasMipmaps = false;
+  myMaxMipLevel = 0;
 
   const Graphic3d_Vec3i aSizeXYZ = theSizeXYZ.cwiseMin (Graphic3d_Vec3i (theCtx->MaxTextureSize()));
   if (aSizeXYZ != theSizeXYZ)
@@ -809,24 +900,80 @@ bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)&    theCtx,
     return false;
   }
 
+  Handle(Image_PixMap) anImage;
+  Handle(Image_CompressedPixMap) aCompImage;
+  OpenGl_TextureFormat aFormat;
   if (!theCubeMap.IsNull())
   {
-    theToGenMipmap = theCubeMap->HasMipmaps();
-    if (Handle(Image_PixMap) anImage = theCubeMap->Reset().Value())
+    theCubeMap->Reset();
+    if (theCtx->SupportedTextureFormats()->HasCompressed()
+    && !theCtx->caps->compressedTexturesDisable)
     {
-      theSize   = anImage->SizeX();
-      theFormat = anImage->Format();
+      aCompImage = theCubeMap->CompressedValue (theCtx->SupportedTextureFormats());
     }
-    else
+    if (!aCompImage.IsNull())
     {
-      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;
+      aFormat = OpenGl_TextureFormat::FindCompressedFormat (theCtx, aCompImage->CompressedFormat(), theIsColorMap);
+      if (aFormat.IsValid())
+      {
+        theToGenMipmap = false;
+        theSize   = aCompImage->SizeX();
+        theFormat = aCompImage->BaseFormat();
+        myMaxMipLevel = Max (aCompImage->MipMaps().Size() - 1, 0);
+        if (myMaxMipLevel > 0
+        && !aCompImage->IsCompleteMipMapSet())
+        {
+          const Graphic3d_Vec2i aMipSize = computeSmallestMipMapSize (Graphic3d_Vec2i (aCompImage->SizeX(), aCompImage->SizeY()), myMaxMipLevel);
+          if (!theCtx->HasTextureBaseLevel())
+          {
+            myMaxMipLevel = 0;
+            theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_MEDIUM,
+                                 TCollection_AsciiString ("Warning: Cubemap compressed texture ") + theCubeMap->GetId() + " " + aCompImage->SizeX() + "x" + aCompImage->SizeX()
+                                 + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y() + "; mipmaps will be ignored");
+          }
+          else
+          {
+            Message::SendTrace (TCollection_AsciiString ("Warning: Cubemap compressed texture ") + theCubeMap->GetId() + " " + aCompImage->SizeX() + "x" + aCompImage->SizeX()
+                                + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y());
+          }
+        }
+
+        OpenGl_UnpackAlignmentSentry::Reset();
+      }
+      else
+      {
+        aCompImage.Nullify();
+      }
+    }
+
+    if (!aFormat.IsValid())
+    {
+      anImage = theCubeMap->Reset().Value (theCtx->SupportedTextureFormats());
+      if (anImage.IsNull())
+      {
+        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;
+      }
+
+      theSize   = anImage->SizeX();
+      theFormat = anImage->Format();
+      theToGenMipmap = theCubeMap->HasMipmaps();
+      myMaxMipLevel = theToGenMipmap ? computeUpperMipMapLevel ((Standard_Integer )theSize) : 0;
     }
+
+    myIsTopDown = theCubeMap->IsTopDown();
+  }
+  else
+  {
+    myMaxMipLevel = theToGenMipmap ? computeUpperMipMapLevel ((Standard_Integer )theSize) : 0;
   }
 
-  OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theFormat, theIsColorMap);
+  if (!aFormat.IsValid())
+  {
+    aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theFormat, theIsColorMap);
+  }
   if (!aFormat.IsValid())
   {
     Unbind(theCtx);
@@ -835,21 +982,62 @@ bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)&    theCtx,
   }
 
   myTarget = GL_TEXTURE_CUBE_MAP;
-  myHasMipmaps = theToGenMipmap;
   myNbSamples = 1;
   mySizeX = (GLsizei )theSize;
   mySizeY = (GLsizei )theSize;
+  myTextFormat  = aFormat.Format();
+  mySizedFormat = aFormat.Internal();
   Bind (theCtx);
   applyDefaultSamplerParams (theCtx);
 
   for (Standard_Integer i = 0; i < 6; ++i)
   {
-    const void* aData = NULL;
-    Handle(Image_PixMap) anImage;
+    const Standard_Byte* aData = NULL;
 
     if (!theCubeMap.IsNull())
     {
-      anImage = theCubeMap->Value();
+      if (i != 0)
+      {
+        if (!aCompImage.IsNull())
+        {
+          aCompImage = theCubeMap->CompressedValue (theCtx->SupportedTextureFormats());
+        }
+        else
+        {
+          anImage = theCubeMap->Value (theCtx->SupportedTextureFormats());
+        }
+      }
+      if (!aCompImage.IsNull())
+      {
+        Graphic3d_Vec2i aMipSizeXY (mySizeX, mySizeY);
+        aData = aCompImage->FaceData()->Data();
+        for (Standard_Integer aMipIter = 0; aMipIter <= myMaxMipLevel; ++aMipIter)
+        {
+          const Standard_Integer aMipLength = aCompImage->MipMaps().Value (aMipIter);
+          theCtx->Functions()->glCompressedTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, aMipIter, mySizedFormat, aMipSizeXY.x(), aMipSizeXY.y(), 0, aMipLength, aData);
+          const GLenum aTexImgErr = glGetError();
+          if (aTexImgErr != GL_NO_ERROR)
+          {
+            theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                                 TCollection_AsciiString ("Error: cubemap compressed texture ") + aMipSizeXY.x() + "x" + aMipSizeXY.y()
+                                 + " IF: " + int(aFormat.Internal()) + " PF: " + int(aFormat.PixelFormat())
+                                 + " DT: " + int(aFormat.DataType())
+                                 + " can not be created with error " + int(aTexImgErr) + ".");
+            Unbind (theCtx);
+            Release (theCtx.get());
+            return false;
+          }
+
+          aData += aMipLength;
+          aMipSizeXY /= 2;
+          if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
+          if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
+        }
+
+        theCubeMap->Next();
+        continue;
+      }
+
       if (!anImage.IsNull())
       {
 #if !defined(GL_ES_VERSION_2_0)
@@ -970,8 +1158,18 @@ Standard_Size OpenGl_Texture::PixelSizeOfPixelFormat (Standard_Integer theIntern
     case GL_DEPTH_COMPONENT16:  return 2;
     case GL_DEPTH_COMPONENT24:  return 3;
     case GL_DEPTH_COMPONENT32F: return 4;
+    // compressed
+    case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:  // DXT1 uses circa half a byte per pixel (64 bits per 4x4 block)
+    case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+    case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+    case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: // DXT3/5 uses circa 1 byte per pixel (128 bits per 4x4 block)
+    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
+    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
+      return 1;
   }
-  return 0;
+  return 1;
 }
 
 // =======================================================================
@@ -998,7 +1196,7 @@ Standard_Size OpenGl_Texture::EstimatedDataSize() const
   {
     aSize *= 6; // cube sides
   }
-  if (myHasMipmaps)
+  if (myMaxMipLevel > 0)
   {
     aSize = aSize + aSize / 3;
   }
index e7ffd82..8fe1db9 100644 (file)
@@ -72,10 +72,17 @@ public:
   //! Return true for GL_RED and GL_ALPHA formats.
   bool IsAlpha() const { return myIsAlpha; }
 
-  //! Setup to interprete the format as Alpha by Shader Manager
+  //! Setup to interpret the format as Alpha by Shader Manager
   //! (should be GL_ALPHA within compatible context or GL_RED otherwise).
   void SetAlpha (const bool theValue) { myIsAlpha = theValue; }
 
+  //! Return if 2D surface is defined top-down (TRUE) or bottom-up (FALSE).
+  //! Normally set from Image_PixMap::IsTopDown() within texture initialization.
+  bool IsTopDown() const { return myIsTopDown; }
+
+  //! Set if 2D surface is defined top-down (TRUE) or bottom-up (FALSE).
+  void SetTopDown (bool theIsTopDown) { myIsTopDown = theIsTopDown; }
+
   //! Creates Texture id if not yet generated.
   //! Data should be initialized by another method.
   Standard_EXPORT bool Create (const Handle(OpenGl_Context)& theCtx);
@@ -144,6 +151,11 @@ public:
   Standard_EXPORT bool Init (const Handle(OpenGl_Context)&       theCtx,
                              const Handle(Graphic3d_TextureMap)& theTextureMap);
 
+  //! Initialize the texture with Image_CompressedPixMap.
+  Standard_EXPORT bool InitCompressed (const Handle(OpenGl_Context)& theCtx,
+                                       const Image_CompressedPixMap& theImage,
+                                       const Standard_Boolean        theIsColorMap);
+
   //! Initialize the 2D multisampling texture using glTexImage2DMultisample().
   Standard_EXPORT bool Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
                                           const GLsizei                 theNbSamples,
@@ -165,7 +177,10 @@ public:
                                const void*                   thePixels);
 
   //! @return true if texture was generated within mipmaps
-  Standard_Boolean HasMipmaps() const { return myHasMipmaps; }
+  Standard_Boolean HasMipmaps() const { return myMaxMipLevel > 0; }
+
+  //! Return upper mipmap level index (0 means no mipmaps).
+  Standard_Integer MaxMipmapLevel() const { return myMaxMipLevel; }
 
   //! Returns estimated GPU memory usage for holding data without considering overheads and allocation alignment rules.
   Standard_EXPORT virtual Standard_Size EstimatedDataSize() const Standard_OVERRIDE;
@@ -278,8 +293,9 @@ protected:
   GLenum           myTextFormat; //!< texture format - GL_RGB, GL_RGBA,...
   GLint            mySizedFormat;//!< internal (sized) texture format
   Standard_Integer myNbSamples;  //!< number of MSAA samples
-  Standard_Boolean myHasMipmaps; //!< flag indicates that texture was uploaded with mipmaps
+  Standard_Integer myMaxMipLevel;//!< upper mipmap level index (0 means no mipmaps)
   bool             myIsAlpha;    //!< indicates alpha format
+  bool             myIsTopDown;  //!< indicates if 2D surface is defined top-down (TRUE) or bottom-up (FALSE)
 
 };
 
index 30c7018..19d4002 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <OpenGl_TextureFormat.hxx>
 
+#include <Image_SupportedFormats.hxx>
 #include <OpenGl_Context.hxx>
 
 // =======================================================================
@@ -157,7 +158,7 @@ OpenGl_TextureFormat OpenGl_TextureFormat::FindFormat (const Handle(OpenGl_Conte
         return OpenGl_TextureFormat();
       }
       aFormat.SetNbComponents (4);
-         aFormat.SetInternalFormat (GL_BGRA_EXT);
+      aFormat.SetInternalFormat (GL_BGRA_EXT);
     #endif
       aFormat.SetPixelFormat (GL_BGRA_EXT); // equals to GL_BGRA
       aFormat.SetDataType (GL_UNSIGNED_BYTE);
@@ -449,3 +450,79 @@ OpenGl_TextureFormat OpenGl_TextureFormat::FindSizedFormat (const Handle(OpenGl_
   }
   return aFormat;
 }
+
+// =======================================================================
+// function : FindCompressedFormat
+// purpose  :
+// =======================================================================
+OpenGl_TextureFormat OpenGl_TextureFormat::FindCompressedFormat (const Handle(OpenGl_Context)& theCtx,
+                                                                 Image_CompressedFormat theFormat,
+                                                                 bool theIsColorMap)
+{
+  OpenGl_TextureFormat aFormat;
+  if (!theCtx->SupportedTextureFormats()->IsSupported (theFormat))
+  {
+    return aFormat;
+  }
+
+  switch (theFormat)
+  {
+    case Image_CompressedFormat_UNKNOWN:
+    {
+      return aFormat;
+    }
+    case Image_CompressedFormat_RGB_S3TC_DXT1:
+    {
+      aFormat.SetNbComponents (3);
+      aFormat.SetPixelFormat (GL_RGB);
+      aFormat.SetDataType (GL_UNSIGNED_BYTE);
+      aFormat.SetInternalFormat (GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
+      if (theIsColorMap
+       && theCtx->ToRenderSRGB())
+      {
+        aFormat.SetInternalFormat (GL_COMPRESSED_SRGB_S3TC_DXT1_EXT);
+      }
+      return aFormat;
+    }
+    case Image_CompressedFormat_RGBA_S3TC_DXT1:
+    {
+      aFormat.SetNbComponents (4);
+      aFormat.SetPixelFormat (GL_RGBA);
+      aFormat.SetDataType (GL_UNSIGNED_BYTE);
+      aFormat.SetInternalFormat (GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
+      if (theIsColorMap
+       && theCtx->ToRenderSRGB())
+      {
+        aFormat.SetInternalFormat (GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT);
+      }
+      return aFormat;
+    }
+    case Image_CompressedFormat_RGBA_S3TC_DXT3:
+    {
+      aFormat.SetNbComponents (4);
+      aFormat.SetPixelFormat (GL_RGBA);
+      aFormat.SetDataType (GL_UNSIGNED_BYTE);
+      aFormat.SetInternalFormat (GL_COMPRESSED_RGBA_S3TC_DXT3_EXT);
+      if (theIsColorMap
+       && theCtx->ToRenderSRGB())
+      {
+        aFormat.SetInternalFormat (GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT);
+      }
+      return aFormat;
+    }
+    case Image_CompressedFormat_RGBA_S3TC_DXT5:
+    {
+      aFormat.SetNbComponents (4);
+      aFormat.SetPixelFormat (GL_RGBA);
+      aFormat.SetDataType (GL_UNSIGNED_BYTE);
+      aFormat.SetInternalFormat (GL_COMPRESSED_RGBA_S3TC_DXT5_EXT);
+      if (theIsColorMap
+       && theCtx->ToRenderSRGB())
+      {
+        aFormat.SetInternalFormat (GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT);
+      }
+      return aFormat;
+    }
+  }
+  return aFormat;
+}
index 244f641..bb4eb69 100644 (file)
@@ -14,6 +14,7 @@
 #ifndef _OpenGl_TextureFormat_HeaderFile
 #define _OpenGl_TextureFormat_HeaderFile
 
+#include <Image_CompressedFormat.hxx>
 #include <Image_Format.hxx>
 #include <OpenGl_GlCore13.hxx>
 #include <Standard_Handle.hxx>
@@ -47,6 +48,14 @@ public:
   Standard_EXPORT static OpenGl_TextureFormat FindSizedFormat (const Handle(OpenGl_Context)& theCtx,
                                                                GLint theSizedFormat);
 
+  //! Find texture format suitable to specified compressed texture format.
+  //! @param theCtx [in] OpenGL context defining supported texture formats
+  //! @param theFormat [in] compressed texture format
+  //! @return found format or invalid format
+  Standard_EXPORT static OpenGl_TextureFormat FindCompressedFormat (const Handle(OpenGl_Context)& theCtx,
+                                                                    Image_CompressedFormat theFormat,
+                                                                    bool theIsColorMap);
+
 public:
 
   //! Empty constructor (invalid texture format).
index ac79137..c6c3e97 100644 (file)
@@ -282,7 +282,7 @@ void OpenGl_View::initTextureEnv (const Handle(OpenGl_Context)& theContext)
   }
 
   Handle(OpenGl_Texture) aTextureEnv = new OpenGl_Texture (myTextureEnvData->GetId(), myTextureEnvData->GetParams());
-  if (Handle(Image_PixMap) anImage = myTextureEnvData->GetImage())
+  if (Handle(Image_PixMap) anImage = myTextureEnvData->GetImage (theContext->SupportedTextureFormats()))
   {
     aTextureEnv->Init (theContext, *anImage, myTextureEnvData->Type(), true);
   }
index dcc828f..6e92439 100644 (file)
@@ -6808,6 +6808,7 @@ static int VCaps (Draw_Interpretor& theDI,
     theDI << "WinBuffer: " << (aCaps->useSystemBuffer ? "1" : "0") << "\n";
     theDI << "NoExt:"    << (aCaps->contextNoExtensions ? "1" : "0") << "\n";
     theDI << "MaxVersion:" << aCaps->contextMajorVersionUpper << "." << aCaps->contextMinorVersionUpper << "\n";
+    theDI << "CompressTextures: " << (aCaps->compressedTexturesDisable ? "0" : "1") << "\n";
     return 0;
   }
 
@@ -6862,6 +6863,16 @@ static int VCaps (Draw_Interpretor& theDI,
       }
       aCaps->sRGBDisable = !toEnable;
     }
+    else if (anArgCase == "-compressedtextures")
+    {
+      Standard_Boolean toEnable = Standard_True;
+      if (++anArgIter < theArgNb
+      && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable))
+      {
+        --anArgIter;
+      }
+      aCaps->compressedTexturesDisable = !toEnable;
+    }
     else if (anArgCase == "-vbo")
     {
       Standard_Boolean toEnable = Standard_True;
@@ -14374,7 +14385,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     __FILE__, VStereo, group);
   theCommands.Add ("vcaps",
             "vcaps [-sRGB {0|1}] [-vbo {0|1}] [-sprites {0|1}] [-ffp {0|1}] [-polygonMode {0|1}]"
-    "\n\t\t:       [-compatibleProfile {0|1}]"
+    "\n\t\t:       [-compatibleProfile {0|1}] [-compressedTextures {0|1}]"
     "\n\t\t:       [-vsync {0|1}] [-useWinBuffer {0|1}]"
     "\n\t\t:       [-quadBuffer {0|1}] [-stereo {0|1}]"
     "\n\t\t:       [-softMode {0|1}] [-noupdate|-update]"
@@ -14385,6 +14396,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands)
     "\n\t\t:             built-in GLSL programs"
     "\n\t\t:            (requires compatible profile)"
     "\n\t\t:  polygonMode - use Polygon Mode instead of built-in GLSL programs"
+    "\n\t\t:  compressedTexture - allow uploading of GPU-supported compressed texture formats"
     "\n\t\t:  VBO      - use Vertex Buffer Object (copy vertex"
     "\n\t\t:             arrays to GPU memory)"
     "\n\t\t:  sprite   - use textured sprites instead of bitmaps"
index 798cbab..3c5519c 100644 (file)
@@ -36,10 +36,21 @@ XCAFPrs_Texture::XCAFPrs_Texture (const Image_Texture& theImageSource,
 }
 
 //=======================================================================
+//function : GetCompressedImage
+//purpose  :
+//=======================================================================
+Handle(Image_CompressedPixMap) XCAFPrs_Texture::GetCompressedImage (const Handle(Image_SupportedFormats)& theSupported)
+{
+  return myImageSource.ReadCompressedImage (theSupported);
+}
+
+//=======================================================================
 //function : GetImage
 //purpose  :
 //=======================================================================
-Handle(Image_PixMap) XCAFPrs_Texture::GetImage() const
+Handle(Image_PixMap) XCAFPrs_Texture::GetImage (const Handle(Image_SupportedFormats)& theSupported)
 {
-  return myImageSource.ReadImage();
+  Handle(Image_PixMap) anImage = myImageSource.ReadImage (theSupported);
+  convertToCompatible (theSupported, anImage);
+  return anImage;
 }
index ff8efa8..f950139 100644 (file)
@@ -31,7 +31,10 @@ public:
                                             const Graphic3d_TextureUnit theUnit);
 
   //! Image reader.
-  Standard_EXPORT virtual Handle(Image_PixMap) GetImage() const Standard_OVERRIDE;
+  Standard_EXPORT virtual Handle(Image_CompressedPixMap) GetCompressedImage (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE;
+
+  //! Image reader.
+  Standard_EXPORT virtual Handle(Image_PixMap) GetImage (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE;
 
   //! Return image source.
   const Image_Texture& GetImageSource() const { return myImageSource; }
diff --git a/tests/v3d/glsl/cubemap_dds b/tests/v3d/glsl/cubemap_dds
new file mode 100644 (file)
index 0000000..9f701fd
--- /dev/null
@@ -0,0 +1,25 @@
+puts "============"
+puts "0031478: Visualization, TKOpenGl - allow uploading Cubemap in compressed DDS format when supported by GPU"
+puts "============"
+puts ""
+
+set aCubeMapPNG [locate_data_file cubemap_labels.png]
+set aCubeMapDDS [locate_data_file cubemap_labels.dds]
+
+box b 1 2 3
+psphere s 1
+
+vclear
+vinit View1 -w 512 -h 512
+vcamera -fovy 100
+vzbufftrihedron
+#vdisplay -dispMode 1 b
+vdisplay -dispMode 1 s
+vfit
+
+vrenderparams -shadingModel pbr
+vbackground -cubemap $aCubeMapPNG -invertedz
+vdump $imagedir/${casename}_png.png
+
+vbackground -cubemap $aCubeMapDDS -invertedz
+vdump $imagedir/${casename}_dds.png
index a5c6027..18aab87 100644 (file)
@@ -28,12 +28,15 @@ for { set aPass 0 } { $aPass < 2 } { incr aPass } {
   vtexture b_6 $aTexture -modulate off
   vdump $::imagedir/${::casename}_identity_${aSuffix}.png
 
-  vtexture b_6 $aTexture -trsfTranslate 0.0 0.0 -trsfScale 0.8 2.0
+  vtexture b_6 $aTexture -trsfTranslate 0.0 0.0 -trsfScale 0.8 2.0 -trsfAngle 0
   vdump $::imagedir/${::casename}_scale_${aSuffix}.png
 
-  vtexture b_6 $aTexture -trsfTranslate 0.25 -0.25 -trsfScale 1.0 1.0
+  vtexture b_6 $aTexture -trsfTranslate 0.25 -0.25 -trsfScale 1.0 1.0 -trsfAngle 0
   vdump $::imagedir/${::casename}_translate_${aSuffix}.png
 
-  vtexture b_6 $aTexture -trsfTranslate 0.25 -0.25 -trsfScale 1.1 0.8
+  vtexture b_6 $aTexture -trsfTranslate 0.0 0.1 -trsfScale 1 1.1 -trsfAngle 30
+  vdump $::imagedir/${::casename}_rotate_${aSuffix}.png
+
+  vtexture b_6 $aTexture -trsfTranslate 0.25 -0.25 -trsfScale 1.1 0.8 -trsfAngle 0
   vdump $::imagedir/${::casename}_${aSuffix}.png
 }
diff --git a/tests/v3d/glsl/texture_trsf3 b/tests/v3d/glsl/texture_trsf3
new file mode 100644 (file)
index 0000000..b719cce
--- /dev/null
@@ -0,0 +1,42 @@
+puts "========"
+puts "Texture 2D transformation (presentation trsf) on DDS texture"
+puts "========"
+
+set aTexture [locate_data_file bug31478_texture_trsf_ref_dxt3.dds]
+pload MODELING VISUALIZATION
+box b 1 1 1
+explode b F
+
+for { set aPass 0 } { $aPass < 2 } { incr aPass } {
+  vclear
+  vclose ALL
+
+  set aSuffix ""
+  if { $aPass == 0 } {
+    set aSuffix "ffp"
+    vcaps -ffp 1
+  } else {
+    set aSuffix "glsl"
+    vcaps -ffp 0
+  }
+
+  vinit View1 w=512 h=512
+  vtop
+  vdisplay -dispMode 1 b_6
+  vfit
+
+  vtexture b_6 $aTexture -modulate off
+  vdump $::imagedir/${::casename}_identity_${aSuffix}.png
+
+  vtexture b_6 $aTexture -trsfTranslate 0.0 0.0 -trsfScale 0.8 2.0 -trsfAngle 0
+  vdump $::imagedir/${::casename}_scale_${aSuffix}.png
+
+  vtexture b_6 $aTexture -trsfTranslate 0.25 -0.25 -trsfScale 1.0 1.0 -trsfAngle 0
+  vdump $::imagedir/${::casename}_translate_${aSuffix}.png
+
+  vtexture b_6 $aTexture -trsfTranslate 0.0 0.1 -trsfScale 1 1.1 -trsfAngle 30
+  vdump $::imagedir/${::casename}_rotate_${aSuffix}.png
+
+  vtexture b_6 $aTexture -trsfTranslate 0.25 -0.25 -trsfScale 1.1 0.8 -trsfAngle 0
+  vdump $::imagedir/${::casename}_${aSuffix}.png
+}