Image_Format_BGRF, //!< same as RGBF but with different components order
Image_Format_RGBAF, //!< 4 floats (16-bytes) RGBA image plane
Image_Format_BGRAF, //!< same as RGBAF but with different components order
+ Image_Format_RGF_half, //!< 2 half-floats (4-bytes) RG image plane
+ Image_Format_RGBAF_half, //!< 4 half-floats (8-bytes) RGBA image plane
};
-enum { Image_Format_NB = Image_Format_BGRAF + 1 };
+enum { Image_Format_NB = Image_Format_RGBAF_half + 1 };
#endif // _Image_Format_HeaderFile
ImageFormatInfo(BGRF, 3, sizeof(float) * 3),
ImageFormatInfo(RGBAF, 4, sizeof(float) * 4),
ImageFormatInfo(BGRAF, 4, sizeof(float) * 4),
+ ImageFormatInfo(RGF_half, 2, sizeof(uint16_t) * 2),
+ ImageFormatInfo(RGBAF_half, 4, sizeof(uint16_t) * 4),
CompressedImageFormatInfo(RGB_S3TC_DXT1, 3, 1), // DXT1 uses circa half a byte per pixel (64 bits per 4x4 block)
CompressedImageFormatInfo(RGBA_S3TC_DXT1, 4, 1),
CompressedImageFormatInfo(RGBA_S3TC_DXT3, 4, 1), // DXT3/5 uses circa 1 byte per pixel (128 bits per 4x4 block)
const Image_ColorBGRF& aPixel = Value<Image_ColorBGRF> (theY, theX);
return Quantity_ColorRGBA (NCollection_Vec4<float> (aPixel.r(), aPixel.g(), aPixel.b(), 1.0f)); // opaque
}
+ case Image_Format_RGF_half:
+ {
+ const NCollection_Vec2<uint16_t>& aPixel = Value<NCollection_Vec2<uint16_t>> (theY, theX);
+ return Quantity_ColorRGBA (NCollection_Vec4<float> (ConvertFromHalfFloat (aPixel.x()), ConvertFromHalfFloat (aPixel.y()), 0.0f, 1.0f));
+ }
+ case Image_Format_RGBAF_half:
+ {
+ const NCollection_Vec4<uint16_t>& aPixel = Value<NCollection_Vec4<uint16_t>> (theY, theX);
+ return Quantity_ColorRGBA (NCollection_Vec4<float> (ConvertFromHalfFloat (aPixel.r()), ConvertFromHalfFloat (aPixel.g()),
+ ConvertFromHalfFloat (aPixel.b()), ConvertFromHalfFloat (aPixel.a())));
+ }
case Image_Format_RGBA:
{
const Image_ColorRGBA& aPixel = Value<Image_ColorRGBA> (theY, theX);
aPixel.b() = aColor.b();
return;
}
+ case Image_Format_RGF_half:
+ {
+ NCollection_Vec2<uint16_t>& aPixel = ChangeValue<NCollection_Vec2<uint16_t>> (theY, theX);
+ aPixel.x() = ConvertToHalfFloat (aColor.r());
+ aPixel.y() = ConvertToHalfFloat (aColor.g());
+ return;
+ }
+ case Image_Format_RGBAF_half:
+ {
+ NCollection_Vec4<uint16_t>& aPixel = ChangeValue<NCollection_Vec4<uint16_t>> (theY, theX);
+ aPixel.r() = ConvertToHalfFloat (aColor.r());
+ aPixel.g() = ConvertToHalfFloat (aColor.g());
+ aPixel.b() = ConvertToHalfFloat (aColor.b());
+ aPixel.a() = ConvertToHalfFloat (aColor.a());
+ return;
+ }
case Image_Format_RGBA:
{
Image_ColorRGBA& aPixel = ChangeValue<Image_ColorRGBA> (theY, theX);
return myData.ChangeValue (theRow, theCol);
}
+public:
+
+ //! Convert 16-bit half-float value into 32-bit float (simple conversion).
+ static float ConvertFromHalfFloat (const uint16_t theHalf)
+ {
+ union FloatUint32 { float Float32; uint32_t UInt32; };
+
+ const uint32_t e = (theHalf & 0x7C00) >> 10; // exponent
+ const uint32_t m = (theHalf & 0x03FF) << 13; // mantissa
+ FloatUint32 mf, aRes;
+ mf.Float32 = (float )m;
+ const uint32_t v = mf.UInt32 >> 23; // evil log2 bit hack to count leading zeros in denormalized format
+ aRes.UInt32 = (theHalf & 0x8000)<<16 | (e != 0) * ((e + 112) << 23 | m) | ((e == 0) & (m != 0)) * ((v - 37) << 23 | ((m << (150 - v)) & 0x007FE000)); // sign : normalized : denormalized
+ return aRes.Float32;
+ }
+
+ //! Convert 32-bit float value into IEEE-754 16-bit floating-point format without infinity:
+ //! 1-5-10, exp-15, +-131008.0, +-6.1035156E-5, +-5.9604645E-8, 3.311 digits.
+ static uint16_t ConvertToHalfFloat (const float theFloat)
+ {
+ union FloatUint32 { float Float32; uint32_t UInt32; };
+ FloatUint32 anInput;
+ anInput.Float32 = theFloat;
+ const uint32_t b = anInput.UInt32 + 0x00001000; // round-to-nearest-even: add last bit after truncated mantissa
+ const uint32_t e = (b & 0x7F800000) >> 23; // exponent
+ const uint32_t m = b & 0x007FFFFF; // mantissa; in line below: 0x007FF000 = 0x00800000-0x00001000 = decimal indicator flag - initial rounding
+ return (uint16_t)((b & 0x80000000) >> 16 | (e > 112) * ((((e - 112) << 10) & 0x7C00) | m >> 13)
+ | ((e < 113) & (e > 101)) * ((((0x007FF000 + m) >> (125 - e)) + 1) >> 1) | (e > 143) * 0x7FFF); // sign : normalized : denormalized : saturate
+ }
+
protected:
Image_PixMapData myData; //!< data buffer
case Image_Format_RGBF:
case Image_Format_BGRAF:
case Image_Format_BGRF:
+ case Image_Format_RGF_half:
+ case Image_Format_RGBAF_half:
case Image_Format_UNKNOWN:
return AV_PIX_FMT_NONE; // unsupported
}
mySupportedFormats->Add (Image_Format_AlphaF);
mySupportedFormats->Add (Image_Format_RGBF);
mySupportedFormats->Add (Image_Format_RGBAF);
+ if (hasHalfFloatBuffer)
+ {
+ mySupportedFormats->Add (Image_Format_RGBAF_half);
+ }
if (arbTexRG)
{
mySupportedFormats->Add (Image_Format_RGF);
+ if (hasHalfFloatBuffer)
+ {
+ mySupportedFormats->Add (Image_Format_RGF_half);
+ }
}
if (extBgra)
{
&& arbTexFloat
&& (IsGlGreaterEqual (3, 0)
#if defined(GL_ES_VERSION_2_0)
- || true // || CheckExtension ("GL_EXT_shader_texture_lod") fallback is used when extension is unavailable
+ || hasHighp
+ // || CheckExtension ("GL_EXT_shader_texture_lod") fallback is used when extension is unavailable
#else
|| (IsGlGreaterEqual (2, 1) && CheckExtension ("GL_EXT_gpu_shader4"))
#endif
aFormat = GL_RGBA;
aType = GL_FLOAT;
break;
+ case Image_Format_RGBAF_half:
+ aFormat = GL_RGBA;
+ aType = GL_HALF_FLOAT;
+ break;
case Image_Format_Alpha:
case Image_Format_AlphaF:
return Standard_False; // GL_ALPHA is no more supported in core context
+ case Image_Format_RGF_half:
case Image_Format_UNKNOWN:
return Standard_False;
}
return OpenGl_TextureFormat();
#endif
}
+ 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)
+ {
+ #if defined(GL_ES_VERSION_2_0)
+ aFormat.SetDataType (GL_HALF_FLOAT_OES);
+ #endif
+ }
+ 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)
+ {
+ #if defined(GL_ES_VERSION_2_0)
+ aFormat.SetDataType (GL_HALF_FLOAT_OES);
+ #endif
+ }
+ return aFormat;
+ }
case Image_Format_RGBA:
{
aFormat.SetNbComponents (4);
aFormat.SetInternalFormat (theSizedFormat);
aFormat.SetPixelFormat (GL_RGBA);
aFormat.SetDataType (GL_HALF_FLOAT);
- aFormat.SetImageFormat (Image_Format_RGBAF);
+ aFormat.SetImageFormat (Image_Format_RGBAF_half);
if (theCtx->hasHalfFloatBuffer == OpenGl_FeatureInExtensions)
{
#if defined(GL_ES_VERSION_2_0)
}
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)
+ {
+ #if defined(GL_ES_VERSION_2_0)
+ aFormat.SetDataType (GL_HALF_FLOAT_OES);
+ #else
+ aFormat.SetDataType (GL_FLOAT);
+ #endif
+ }
+ return aFormat;
+ }
case GL_SRGB8_ALPHA8:
case GL_RGBA8:
case GL_RGBA:
static const TCollection_AsciiString THE_SHARED_ENV_LUT_KEY("EnvLUT");
if (!aCtx->GetResource (THE_SHARED_ENV_LUT_KEY, anEnvLUT))
{
- Handle(Graphic3d_TextureParams) aParams = new Graphic3d_TextureParams();
- aParams->SetFilter (Graphic3d_TOTF_BILINEAR);
- aParams->SetRepeat (Standard_False);
- aParams->SetTextureUnit (aCtx->PBREnvLUTTexUnit());
- anEnvLUT = new OpenGl_Texture(THE_SHARED_ENV_LUT_KEY, aParams);
- Handle(Image_PixMap) aPixMap = new Image_PixMap();
+ bool toConvertHalfFloat = false;
+ #if defined(GL_ES_VERSION_2_0)
+ // GL_RG32F is not texture-filterable format in OpenGL ES without OES_texture_float_linear extension.
+ // GL_RG16F is texture-filterable since OpenGL ES 3.0 or OpenGL ES 2.0 + OES_texture_half_float_linear.
+ // OpenGL ES 3.0 allows initialization of GL_RG16F from 32-bit float data, but OpenGL ES 2.0 + OES_texture_half_float does not.
+ // Note that it is expected that GL_RG16F has enough precision for this table, so that it can be used also on desktop OpenGL.
+ const bool hasHalfFloat = aCtx->IsGlGreaterEqual (3, 0) || aCtx->CheckExtension ("GL_OES_texture_half_float_linear");
+ toConvertHalfFloat = !aCtx->IsGlGreaterEqual (3, 0) && hasHalfFloat;
+ #endif
+ Image_Format anImgFormat = Image_Format_UNKNOWN;
if (aCtx->arbTexRG)
+ {
+ anImgFormat = toConvertHalfFloat ? Image_Format_RGF_half : Image_Format_RGF;
+ }
+ else
+ {
+ anImgFormat = toConvertHalfFloat ? Image_Format_RGBAF_half : Image_Format_RGBAF;
+ }
+
+ Handle(Image_PixMap) aPixMap = new Image_PixMap();
+ if (anImgFormat == Image_Format_RGF)
{
aPixMap->InitWrapper (Image_Format_RGF, (Standard_Byte*)Textures_EnvLUT, Textures_EnvLUTSize, Textures_EnvLUTSize);
}
else
{
+ aPixMap->InitZero (anImgFormat, Textures_EnvLUTSize, Textures_EnvLUTSize);
Image_PixMap aPixMapRG;
aPixMapRG.InitWrapper (Image_Format_RGF, (Standard_Byte*)Textures_EnvLUT, Textures_EnvLUTSize, Textures_EnvLUTSize);
- aPixMap->InitZero (Image_Format_RGBAF, Textures_EnvLUTSize, Textures_EnvLUTSize);
for (Standard_Size aRowIter = 0; aRowIter < aPixMapRG.SizeY(); ++aRowIter)
{
for (Standard_Size aColIter = 0; aColIter < aPixMapRG.SizeX(); ++aColIter)
{
const Image_ColorRGF& aPixelRG = aPixMapRG.Value<Image_ColorRGF> (aRowIter, aColIter);
- Image_ColorRGBAF& aPixelRGBA = aPixMap->ChangeValue<Image_ColorRGBAF> (aRowIter, aColIter);
- aPixelRGBA.r() = aPixelRG.r();
- aPixelRGBA.g() = aPixelRG.g();
+ if (toConvertHalfFloat)
+ {
+ NCollection_Vec2<uint16_t>& aPixelRGBA = aPixMap->ChangeValue<NCollection_Vec2<uint16_t>> (aRowIter, aColIter);
+ aPixelRGBA.x() = Image_PixMap::ConvertToHalfFloat (aPixelRG.r());
+ aPixelRGBA.y() = Image_PixMap::ConvertToHalfFloat (aPixelRG.g());
+ }
+ else
+ {
+ Image_ColorRGBAF& aPixelRGBA = aPixMap->ChangeValue<Image_ColorRGBAF> (aRowIter, aColIter);
+ aPixelRGBA.r() = aPixelRG.r();
+ aPixelRGBA.g() = aPixelRG.g();
+ }
}
}
}
OpenGl_TextureFormat aTexFormat = OpenGl_TextureFormat::FindFormat (aCtx, aPixMap->Format(), false);
#if defined(GL_ES_VERSION_2_0)
- // GL_RG32F is not texture-filterable format on OpenGL ES without OES_texture_float_linear extension.
- // GL_RG16F is texture-filterable since OpenGL ES 3.0 and can be initialized from 32-bit floats.
- // Note that it is expected that GL_RG16F has enough precision for this table, so that it can be used also on desktop OpenGL.
- //if (!aCtx->hasTexFloatLinear)
- aTexFormat.SetInternalFormat (aCtx->arbTexRG ? GL_RG16F : GL_RGBA16F);
+ if (aTexFormat.IsValid()
+ && hasHalfFloat)
+ {
+ aTexFormat.SetInternalFormat (aCtx->arbTexRG ? GL_RG16F : GL_RGBA16F);
+ }
#endif
+
+ Handle(Graphic3d_TextureParams) aParams = new Graphic3d_TextureParams();
+ aParams->SetFilter (Graphic3d_TOTF_BILINEAR);
+ aParams->SetRepeat (Standard_False);
+ aParams->SetTextureUnit (aCtx->PBREnvLUTTexUnit());
+ anEnvLUT = new OpenGl_Texture(THE_SHARED_ENV_LUT_KEY, aParams);
if (!aTexFormat.IsValid()
|| !anEnvLUT->Init (aCtx, aTexFormat, Graphic3d_Vec2i((Standard_Integer)Textures_EnvLUTSize), Graphic3d_TOT_2D, aPixMap.get()))
{