// Copyright (c) 2017-2019 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 <OpenGl_TextureFormat.hxx>

#include <Image_SupportedFormats.hxx>
#include <OpenGl_Context.hxx>

//=================================================================================================

TCollection_AsciiString OpenGl_TextureFormat::FormatFormat(GLint theInternalFormat)
{
  switch (theInternalFormat)
  {
    // RED variations (GL_RED, OpenGL 3.0+)
    case GL_RED:
      return "GL_RED";
    case GL_R8:
      return "GL_R8";
    case 0x822A:
      return "GL_R16";
    case GL_R16F:
      return "GL_R16F"; // half-float
    case GL_R32F:
      return "GL_R32F"; // float
    case GL_R32I:
      return "GL_R32I";
    case GL_RED_INTEGER:
      return "GL_RED_INTEGER";
    //
    case GL_RG:
      return "GL_RG";
    case GL_RG8:
      return "GL_RG8";
    case 0x822C:
      return "GL_RG16";
    case GL_RG16F:
      return "GL_RG16F";
    case GL_RG32F:
      return "GL_RG32F";
    case GL_RG32I:
      return "GL_RG32I";
    case GL_RG_INTEGER:
      return "GL_RG_INTEGER";
    // RGB variations
    case GL_RGB:
      return "GL_RGB";
    case 0x804F:
      return "GL_RGB4";
    case 0x8050:
      return "GL_RGB5";
    case GL_RGB8:
      return "GL_RGB8";
    case GL_SRGB8:
      return "GL_SRGB8";
    case GL_SRGB_EXT:
      return "GL_SRGB_EXT";
    case 0x8052:
      return "GL_RGB10";
    case 0x8053:
      return "GL_RGB12";
    case 0x8054:
      return "GL_RGB16";
    case GL_RGB16F:
      return "GL_RGB16F"; // half-float
    case GL_RGB32F:
      return "GL_RGB32F"; // float
    case GL_RGB32I:
      return "GL_RGB32I";
    // RGBA variations
    case GL_RGBA:
      return "GL_RGBA";
    case GL_RGBA8:
      return "GL_RGBA8";
    case GL_SRGB8_ALPHA8:
      return "GL_SRGB8_ALPHA8";
    case GL_SRGB_ALPHA_EXT:
      return "GL_SRGB_ALPHA_EXT";
    case GL_RGB10_A2:
      return "GL_RGB10_A2";
    case 0x805A:
      return "GL_RGBA12";
    case 0x805B:
      return "GL_RGBA16";
    case GL_RGBA16F:
      return "GL_RGBA16F"; // half-float
    case GL_RGBA32F:
      return "GL_RGBA32F"; // float
    case GL_RGBA32I:
      return "GL_RGBA32I";
    //
    case 0x80E0:
      return "GL_BGR";
    case GL_BGRA_EXT:
      return "GL_BGRA";
    // ALPHA variations (deprecated)
    case GL_ALPHA:
      return "GL_ALPHA";
    case 0x803C:
      return "GL_ALPHA8";
    case 0x803E:
      return "GL_ALPHA16";
    case GL_LUMINANCE:
      return "GL_LUMINANCE";
    case GL_LUMINANCE16:
      return "GL_LUMINANCE16";
    case GL_LUMINANCE_ALPHA:
      return "GL_LUMINANCE_ALPHA";
    //
    case GL_DEPTH_COMPONENT:
      return "GL_DEPTH_COMPONENT";
    case GL_DEPTH_COMPONENT16:
      return "GL_DEPTH_COMPONENT16";
    case GL_DEPTH_COMPONENT24:
      return "GL_DEPTH_COMPONENT24";
    case GL_DEPTH_COMPONENT32F:
      return "GL_DEPTH_COMPONENT32F";
    case GL_DEPTH_STENCIL:
      return "GL_DEPTH_STENCIL";
    case GL_DEPTH24_STENCIL8:
      return "GL_DEPTH24_STENCIL8";
    case GL_DEPTH32F_STENCIL8:
      return "GL_DEPTH32F_STENCIL8";
    //
    case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
      return "GL_COMPRESSED_RGB_S3TC_DXT1_EXT";
    case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
      return "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT";
    case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
      return "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT";
    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
      return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT";
    case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
      return "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT";
    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
      return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT";
    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
      return "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT";
    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
      return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT";
  }
  return OpenGl_Context::FormatGlEnumHex(theInternalFormat);
}

//=================================================================================================

TCollection_AsciiString OpenGl_TextureFormat::FormatDataType(GLint theDataType)
{
  switch (theDataType)
  {
    case GL_UNSIGNED_BYTE:
      return "GL_UNSIGNED_BYTE";
    case GL_UNSIGNED_SHORT:
      return "GL_UNSIGNED_SHORT";
    case GL_INT:
      return "GL_INT";
    case GL_UNSIGNED_INT:
      return "GL_UNSIGNED_INT";
    case GL_FLOAT:
      return "GL_FLOAT";
    case GL_HALF_FLOAT:
      return "GL_HALF_FLOAT";
    case 0x8D61:
      return "GL_HALF_FLOAT_OES";
    case GL_UNSIGNED_INT_24_8:
      return "GL_UNSIGNED_INT_24_8";
    case GL_UNSIGNED_INT_2_10_10_10_REV:
      return "GL_UNSIGNED_INT_2_10_10_10_REV";
    case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
      return "GL_FLOAT_32_UNSIGNED_INT_24_8_REV";
  }
  return OpenGl_Context::FormatGlEnumHex(theDataType);
}

//=================================================================================================

OpenGl_TextureFormat OpenGl_TextureFormat::FindFormat(const occ::handle<OpenGl_Context>& theCtx,
                                                      Image_Format                       theFormat,
                                                      bool theIsColorMap)
{
  OpenGl_TextureFormat aFormat;
  aFormat.SetImageFormat(theFormat);
  const bool useRedRedAlpha =
    theCtx->GraphicsLibrary() != Aspect_GraphicsLibrary_OpenGLES && theCtx->core11ffp == nullptr;
  switch (theFormat)
  {
    case Image_Format_GrayF: {
      aFormat.SetNbComponents(1);
      if (useRedRedAlpha)
      {
        aFormat.SetInternalFormat(theCtx->arbTexFloat ? GL_R32F : GL_R8);
        aFormat.SetPixelFormat(GL_RED);
      }
      else
      {
        aFormat.SetInternalFormat(theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES
                                    ? GL_LUMINANCE
                                    : GL_LUMINANCE8);
        aFormat.SetPixelFormat(GL_LUMINANCE);
      }
      aFormat.SetDataType(GL_FLOAT);
      return aFormat;
    }
    case Image_Format_AlphaF: {
      aFormat.SetNbComponents(1);
      if (useRedRedAlpha)
      {
        aFormat.SetInternalFormat(theCtx->arbTexFloat ? GL_R32F : GL_R8);
        aFormat.SetPixelFormat(GL_RED);
      }
      else
      {
        aFormat.SetInternalFormat(
          theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES ? GL_ALPHA : GL_ALPHA8);
        aFormat.SetPixelFormat(GL_ALPHA);
      }
      aFormat.SetDataType(GL_FLOAT);
      return aFormat;
    }
    case Image_Format_RGF: {
      if (!theCtx->arbTexRG)
      {
        return OpenGl_TextureFormat();
      }
      aFormat.SetNbComponents(2);
      aFormat.SetInternalFormat(theCtx->arbTexFloat ? GL_RG32F : GL_RG8);
      aFormat.SetPixelFormat(GL_RG);
      aFormat.SetDataType(GL_FLOAT);
      return aFormat;
    }
    case Image_Format_RGBAF: {
      aFormat.SetNbComponents(4);
      aFormat.SetInternalFormat(theCtx->arbTexFloat ? GL_RGBA32F : GL_RGBA8);
      aFormat.SetPixelFormat(GL_RGBA);
      aFormat.SetDataType(GL_FLOAT);
      return aFormat;
    }
    case Image_Format_BGRAF: {
      if (!theCtx->IsGlGreaterEqual(1, 2) && !theCtx->extBgra)
      {
        return OpenGl_TextureFormat();
      }
      aFormat.SetNbComponents(4);
      aFormat.SetInternalFormat(theCtx->arbTexFloat ? GL_RGBA32F : GL_RGBA8);
      aFormat.SetPixelFormat(GL_BGRA_EXT); // equals to GL_BGRA
      aFormat.SetDataType(GL_FLOAT);
      return aFormat;
    }
    case Image_Format_RGBF: {
      aFormat.SetNbComponents(3);
      aFormat.SetInternalFormat(theCtx->arbTexFloat ? GL_RGB32F : GL_RGB8);
      aFormat.SetPixelFormat(GL_RGB);
      aFormat.SetDataType(GL_FLOAT);
      return aFormat;
    }
    case Image_Format_BGRF: {
      if (theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES)
      {
        return OpenGl_TextureFormat();
      }

      aFormat.SetNbComponents(3);
      aFormat.SetInternalFormat(theCtx->arbTexFloat ? GL_RGB32F : GL_RGB8);
      aFormat.SetPixelFormat(GL_BGR); // equals to GL_BGR_EXT
      aFormat.SetDataType(GL_FLOAT);
      return aFormat;
    }
    case Image_Format_GrayF_half: {
      aFormat.SetNbComponents(1);
      aFormat.SetInternalFormat(GL_R16F);
      aFormat.SetPixelFormat(GL_RED);
      aFormat.SetDataType(GL_HALF_FLOAT);
      if (theCtx->hasHalfFloatBuffer == OpenGl_FeatureInExtensions
          && theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES)
      {
        aFormat.SetDataType(GL_HALF_FLOAT_OES);
      }
      return aFormat;
    }
    case Image_Format_RGF_half: {
      aFormat.SetNbComponents(2);
      aFormat.SetInternalFormat(GL_RG16F);
      aFormat.SetPixelFormat(GL_RG);
      aFormat.SetDataType(GL_HALF_FLOAT);
      if (theCtx->hasHalfFloatBuffer == OpenGl_FeatureInExtensions
          && theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES)
      {
        aFormat.SetDataType(GL_HALF_FLOAT_OES);
      }
      return aFormat;
    }
    case Image_Format_RGBAF_half: {
      aFormat.SetNbComponents(4);
      aFormat.SetInternalFormat(GL_RGBA16F);
      aFormat.SetPixelFormat(GL_RGBA);
      aFormat.SetDataType(GL_HALF_FLOAT);
      if (theCtx->hasHalfFloatBuffer == OpenGl_FeatureInExtensions
          && theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES)
      {
        aFormat.SetDataType(GL_HALF_FLOAT_OES);
      }
      return aFormat;
    }
    case Image_Format_RGBA: {
      aFormat.SetNbComponents(4);
      aFormat.SetInternalFormat(GL_RGBA8);
      aFormat.SetPixelFormat(GL_RGBA);
      aFormat.SetDataType(GL_UNSIGNED_BYTE);
      if (theIsColorMap && theCtx->ToRenderSRGB())
      {
        if (theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES
            && !theCtx->IsGlGreaterEqual(3, 0))
        {
          aFormat.SetPixelFormat(GL_SRGB_ALPHA_EXT);
        }
        aFormat.SetInternalFormat(GL_SRGB8_ALPHA8);
      }
      return aFormat;
    }
    case Image_Format_BGRA: {
      if (theCtx->GraphicsLibrary() != Aspect_GraphicsLibrary_OpenGLES)
      {
        if (!theCtx->IsGlGreaterEqual(1, 2) && !theCtx->extBgra)
        {
          return OpenGl_TextureFormat();
        }
        aFormat.SetNbComponents(4);
        aFormat.SetInternalFormat(GL_RGBA8);
        if (theIsColorMap && theCtx->ToRenderSRGB())
        {
          aFormat.SetInternalFormat(GL_SRGB8_ALPHA8);
        }
      }
      else
      {
        if (theIsColorMap && theCtx->ToRenderSRGB())
        {
          // GL_SRGB8_ALPHA8 with texture swizzling would be better
        }
        if (!theCtx->extBgra)
        {
          return OpenGl_TextureFormat();
        }
        aFormat.SetNbComponents(4);
        aFormat.SetInternalFormat(GL_BGRA_EXT);
      }
      aFormat.SetPixelFormat(GL_BGRA_EXT); // equals to GL_BGRA
      aFormat.SetDataType(GL_UNSIGNED_BYTE);
      return aFormat;
    }
    case Image_Format_RGB32: {
      if (theCtx->GraphicsLibrary() != Aspect_GraphicsLibrary_OpenGLES)
      {
        // ask driver to convert data to RGB8 to save memory
        aFormat.SetNbComponents(3);
        aFormat.SetInternalFormat(GL_RGB8);
        aFormat.SetPixelFormat(GL_RGBA);
        aFormat.SetDataType(GL_UNSIGNED_BYTE);
        if (theIsColorMap && theCtx->ToRenderSRGB())
        {
          aFormat.SetInternalFormat(GL_SRGB8);
        }
      }
      else
      {
        // conversion is not supported
        aFormat.SetNbComponents(4);
        aFormat.SetInternalFormat(GL_RGBA8);
        aFormat.SetPixelFormat(GL_RGBA);
        aFormat.SetDataType(GL_UNSIGNED_BYTE);
        if (theIsColorMap && theCtx->ToRenderSRGB())
        {
          if (!theCtx->IsGlGreaterEqual(3, 0))
          {
            aFormat.SetPixelFormat(GL_SRGB_ALPHA_EXT);
          }
          aFormat.SetInternalFormat(GL_SRGB8_ALPHA8);
        }
      }
      return aFormat;
    }
    case Image_Format_BGR32: {
      if (theCtx->GraphicsLibrary() != Aspect_GraphicsLibrary_OpenGLES)
      {
        if (!theCtx->IsGlGreaterEqual(1, 2) && !theCtx->extBgra)
        {
          return OpenGl_TextureFormat();
        }
        aFormat.SetNbComponents(3);
        aFormat.SetInternalFormat(GL_RGB8);
        if (theIsColorMap && theCtx->ToRenderSRGB())
        {
          aFormat.SetInternalFormat(GL_SRGB8);
        }
      }
      else
      {
        if (theIsColorMap && theCtx->ToRenderSRGB())
        {
          // GL_SRGB8_ALPHA8 with texture swizzling would be better
        }
        if (!theCtx->extBgra)
        {
          return OpenGl_TextureFormat();
        }
        aFormat.SetNbComponents(4);
        aFormat.SetInternalFormat(GL_BGRA_EXT);
      }
      aFormat.SetPixelFormat(GL_BGRA_EXT); // equals to GL_BGRA
      aFormat.SetDataType(GL_UNSIGNED_BYTE);
      return aFormat;
    }
    case Image_Format_RGB: {
      aFormat.SetNbComponents(3);
      aFormat.SetInternalFormat(GL_RGB8);
      aFormat.SetPixelFormat(GL_RGB);
      aFormat.SetDataType(GL_UNSIGNED_BYTE);
      if (theIsColorMap && theCtx->ToRenderSRGB())
      {
        if (theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES
            && !theCtx->IsGlGreaterEqual(3, 0))
        {
          aFormat.SetPixelFormat(GL_SRGB_EXT);
        }
        aFormat.SetInternalFormat(GL_SRGB8);
      }
      return aFormat;
    }
    case Image_Format_BGR: {
      if (theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES)
      {
        return OpenGl_TextureFormat();
      }

      if (!theCtx->IsGlGreaterEqual(1, 2) && !theCtx->extBgra)
      {
        return OpenGl_TextureFormat();
      }
      aFormat.SetNbComponents(3);
      aFormat.SetInternalFormat(GL_RGB8);
      aFormat.SetPixelFormat(GL_BGR); // equals to GL_BGR_EXT
      aFormat.SetDataType(GL_UNSIGNED_BYTE);
      if (theIsColorMap && theCtx->ToRenderSRGB())
      {
        aFormat.SetInternalFormat(GL_SRGB8);
      }
      return aFormat;
    }
    case Image_Format_Gray: {
      aFormat.SetNbComponents(1);
      if (useRedRedAlpha)
      {
        aFormat.SetInternalFormat(GL_R8);
        aFormat.SetPixelFormat(GL_RED);
      }
      else
      {
        aFormat.SetInternalFormat(theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES
                                    ? GL_LUMINANCE
                                    : GL_LUMINANCE8);
        aFormat.SetPixelFormat(GL_LUMINANCE);
      }
      aFormat.SetDataType(GL_UNSIGNED_BYTE);
      return aFormat;
    }
    case Image_Format_Alpha: {
      aFormat.SetNbComponents(1);
      if (useRedRedAlpha)
      {
        aFormat.SetInternalFormat(GL_R8);
        aFormat.SetPixelFormat(GL_RED);
      }
      else
      {
        aFormat.SetInternalFormat(
          theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES ? GL_ALPHA : GL_ALPHA8);
        aFormat.SetPixelFormat(GL_ALPHA);
      }
      aFormat.SetDataType(GL_UNSIGNED_BYTE);
      return aFormat;
    }
    case Image_Format_Gray16: {
      if (!theCtx->extTexR16)
      {
        return OpenGl_TextureFormat();
      }

      aFormat.SetNbComponents(1);
      if (useRedRedAlpha || theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES)
      {
        aFormat.SetInternalFormat(GL_R16);
        aFormat.SetPixelFormat(GL_RED);
      }
      else
      {
        aFormat.SetInternalFormat(GL_LUMINANCE16);
        aFormat.SetPixelFormat(GL_LUMINANCE);
      }
      aFormat.SetDataType(GL_UNSIGNED_SHORT);
      return aFormat;
    }
    case Image_Format_UNKNOWN: {
      return OpenGl_TextureFormat();
    }
  }
  return OpenGl_TextureFormat();
}

//=================================================================================================

OpenGl_TextureFormat OpenGl_TextureFormat::FindSizedFormat(
  const occ::handle<OpenGl_Context>& theCtx,
  GLint                              theSizedFormat)
{
  OpenGl_TextureFormat aFormat;
  switch (theSizedFormat)
  {
    case GL_RGBA32F: {
      aFormat.SetNbComponents(4);
      aFormat.SetInternalFormat(theSizedFormat);
      aFormat.SetPixelFormat(GL_RGBA);
      aFormat.SetDataType(GL_FLOAT);
      aFormat.SetImageFormat(Image_Format_RGBAF);
      return aFormat;
    }
    case GL_R32F: {
      aFormat.SetNbComponents(1);
      aFormat.SetInternalFormat(theSizedFormat);
      aFormat.SetPixelFormat(GL_RED);
      aFormat.SetDataType(GL_FLOAT);
      aFormat.SetImageFormat(Image_Format_GrayF);
      return aFormat;
    }
    case GL_RG32F: {
      aFormat.SetNbComponents(1);
      aFormat.SetInternalFormat(theSizedFormat);
      aFormat.SetPixelFormat(GL_RG);
      aFormat.SetDataType(GL_FLOAT);
      aFormat.SetImageFormat(Image_Format_RGF);
      return aFormat;
    }
    case GL_RGBA16F: {
      aFormat.SetNbComponents(4);
      aFormat.SetInternalFormat(theSizedFormat);
      aFormat.SetPixelFormat(GL_RGBA);
      aFormat.SetDataType(GL_HALF_FLOAT);
      aFormat.SetImageFormat(Image_Format_RGBAF_half);
      if (theCtx->hasHalfFloatBuffer == OpenGl_FeatureInExtensions)
      {
        aFormat.SetDataType(theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES
                              ? GL_HALF_FLOAT_OES
                              : GL_FLOAT);
      }
      return aFormat;
    }
    case GL_R16F: {
      aFormat.SetNbComponents(1);
      aFormat.SetInternalFormat(theSizedFormat);
      aFormat.SetPixelFormat(GL_RED);
      aFormat.SetDataType(GL_HALF_FLOAT);
      aFormat.SetImageFormat(Image_Format_GrayF_half);
      if (theCtx->hasHalfFloatBuffer == OpenGl_FeatureInExtensions)
      {
        aFormat.SetDataType(theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES
                              ? GL_HALF_FLOAT_OES
                              : GL_FLOAT);
      }
      return aFormat;
    }
    case GL_RG16F: {
      aFormat.SetNbComponents(2);
      aFormat.SetInternalFormat(theSizedFormat);
      aFormat.SetPixelFormat(GL_RG);
      aFormat.SetDataType(GL_HALF_FLOAT);
      aFormat.SetImageFormat(Image_Format_RGF_half);
      if (theCtx->hasHalfFloatBuffer == OpenGl_FeatureInExtensions)
      {
        aFormat.SetDataType(theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES
                              ? GL_HALF_FLOAT_OES
                              : GL_FLOAT);
      }
      return aFormat;
    }
    case GL_SRGB8_ALPHA8:
    case GL_SRGB_ALPHA_EXT:
    case GL_RGBA8:
    case GL_RGBA: {
      aFormat.SetNbComponents(4);
      aFormat.SetInternalFormat(theSizedFormat);
      aFormat.SetPixelFormat(GL_RGBA);
      aFormat.SetDataType(GL_UNSIGNED_BYTE);
      aFormat.SetImageFormat(Image_Format_RGBA);
      if ((theSizedFormat == GL_SRGB8_ALPHA8 || theSizedFormat == GL_SRGB_ALPHA_EXT))
      {
        if (theCtx->ToRenderSRGB())
        {
          if (theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES
              && !theCtx->IsGlGreaterEqual(3, 0))
          {
            aFormat.SetPixelFormat(GL_SRGB_ALPHA_EXT);
          }
        }
        else
        {
          aFormat.SetInternalFormat(GL_RGBA8); // fallback format
        }
      }
      return aFormat;
    }
    case GL_SRGB8:
    case GL_SRGB_EXT:
    case GL_RGB8:
    case GL_RGB: {
      aFormat.SetNbComponents(3);
      aFormat.SetInternalFormat(theSizedFormat);
      aFormat.SetPixelFormat(GL_RGB);
      aFormat.SetDataType(GL_UNSIGNED_BYTE);
      aFormat.SetImageFormat(Image_Format_RGB);
      if ((theSizedFormat == GL_SRGB8 || theSizedFormat == GL_SRGB_EXT))
      {
        if (theCtx->ToRenderSRGB())
        {
          if (theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES
              && !theCtx->IsGlGreaterEqual(3, 0))
          {
            aFormat.SetPixelFormat(GL_SRGB_EXT);
          }
        }
        else
        {
          aFormat.SetInternalFormat(GL_RGB8); // fallback format
        }
      }
      return aFormat;
    }
    case GL_RGB10_A2: {
      aFormat.SetNbComponents(4);
      aFormat.SetInternalFormat(theSizedFormat);
      aFormat.SetPixelFormat(GL_RGBA);
      aFormat.SetDataType(GL_UNSIGNED_INT_2_10_10_10_REV);
      aFormat.SetImageFormat(Image_Format_RGBA);
      return aFormat;
    }
    // integer types
    case GL_R32I: {
      aFormat.SetNbComponents(1);
      aFormat.SetInternalFormat(theSizedFormat);
      aFormat.SetPixelFormat(GL_RED_INTEGER);
      aFormat.SetDataType(GL_INT);
      return aFormat;
    }
    case GL_RG32I: {
      aFormat.SetNbComponents(2);
      aFormat.SetInternalFormat(theSizedFormat);
      aFormat.SetPixelFormat(GL_RG_INTEGER);
      aFormat.SetDataType(GL_INT);
      return aFormat;
    }
    // depth formats
    case GL_DEPTH24_STENCIL8: {
      aFormat.SetNbComponents(2);
      aFormat.SetInternalFormat(theSizedFormat);
      aFormat.SetPixelFormat(GL_DEPTH_STENCIL);
      aFormat.SetDataType(GL_UNSIGNED_INT_24_8);
      return aFormat;
    }
    case GL_DEPTH32F_STENCIL8: {
      aFormat.SetNbComponents(2);
      aFormat.SetInternalFormat(theSizedFormat);
      aFormat.SetPixelFormat(GL_DEPTH_STENCIL);
      aFormat.SetDataType(GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
      return aFormat;
    }
    case GL_DEPTH_COMPONENT16: {
      aFormat.SetNbComponents(1);
      aFormat.SetInternalFormat(theSizedFormat);
      aFormat.SetPixelFormat(GL_DEPTH_COMPONENT);
      aFormat.SetDataType(GL_UNSIGNED_SHORT);
      return aFormat;
    }
    case GL_DEPTH_COMPONENT24: {
      aFormat.SetNbComponents(1);
      aFormat.SetInternalFormat(theSizedFormat);
      aFormat.SetPixelFormat(GL_DEPTH_COMPONENT);
      aFormat.SetDataType(GL_UNSIGNED_INT);
      return aFormat;
    }
    case GL_DEPTH_COMPONENT32F: {
      aFormat.SetNbComponents(1);
      aFormat.SetInternalFormat(theSizedFormat);
      aFormat.SetPixelFormat(GL_DEPTH_COMPONENT);
      aFormat.SetDataType(GL_FLOAT);
      return aFormat;
    }
  }
  return aFormat;
}

//=================================================================================================

OpenGl_TextureFormat OpenGl_TextureFormat::FindCompressedFormat(
  const occ::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;
}
