Skip to content
1 change: 1 addition & 0 deletions include/osg/Image
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ class OSG_EXPORT Image : public BufferData
void ensureValidSizeForTexturing(GLint maxTextureSize);

static bool isPackedType(GLenum type);
static bool isBPTC(GLenum pixelFormat);
static GLenum computePixelFormat(GLenum pixelFormat);
static GLenum computeFormatDataType(GLenum pixelFormat);

Expand Down
7 changes: 7 additions & 0 deletions include/osg/Texture
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@
#define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE
#endif

#ifndef GL_ARB_texture_compression_bptc
#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C
#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D
#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
#endif

#ifndef GL_IMG_texture_compression_pvrtc
#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
Expand Down
55 changes: 55 additions & 0 deletions src/osg/Image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,20 @@ bool Image::isPackedType(GLenum type)
}
}

bool Image::isBPTC(GLenum pixelFormat)
{
switch(pixelFormat)
{
case(GL_COMPRESSED_RGBA_BPTC_UNORM):
case(GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM):
case(GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT):
case(GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT):
return true;
default:
return false;
}
}


GLenum Image::computePixelFormat(GLenum format)
{
Expand Down Expand Up @@ -707,6 +721,11 @@ unsigned int Image::computeNumComponents(GLenum pixelFormat)
case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR) : return 4;
case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR) : return 4;
case (GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR) : return 4;
// BPTC (BC6H/BC7)
case (GL_COMPRESSED_RGBA_BPTC_UNORM) : return 4;
case (GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM) : return 4;
case (GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT) : return 3;
case (GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT) : return 3;
default:
{
OSG_WARN<<"error pixelFormat = "<<std::hex<<pixelFormat<<std::dec<<std::endl;
Expand All @@ -733,6 +752,11 @@ unsigned int Image::computePixelSizeInBits(GLenum format,GLenum type)
case(GL_COMPRESSED_RED_RGTC1_EXT): return 4;
case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT): return 8;
case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT): return 8;
// BPTC (BC6H/BC7) - 128 bits per 4x4 block = 8 bits per pixel
case(GL_COMPRESSED_RGBA_BPTC_UNORM): return 8;
case(GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM): return 8;
case(GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT): return 8;
case(GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT): return 8;
case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG): return 4;
case(GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG): return 2;
case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG): return 4;
Expand Down Expand Up @@ -892,6 +916,11 @@ osg::Vec3i Image::computeBlockFootprint(GLenum pixelFormat)
case(GL_COMPRESSED_RED_RGTC1_EXT) :
case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT) :
case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT) :
// BPTC (BC6H/BC7) - 4x4 blocks
case(GL_COMPRESSED_RGBA_BPTC_UNORM) :
case(GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM) :
case(GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT) :
case(GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT) :
case(GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG) :
case(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG) :
case(GL_ETC1_RGB8_OES) :
Expand Down Expand Up @@ -971,6 +1000,13 @@ unsigned int Image::computeBlockSize(GLenum pixelFormat, GLenum packing)
case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT):
return osg::maximum(16u,packing); // block size of 16

// BPTC (BC6H/BC7) - 16 bytes per block
case(GL_COMPRESSED_RGBA_BPTC_UNORM):
case(GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM):
case(GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT):
case(GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT):
return osg::maximum(16u,packing); // block size of 16

case(GL_COMPRESSED_RGB8_ETC2):
case(GL_COMPRESSED_SRGB8_ETC2):
case(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2):
Expand Down Expand Up @@ -1021,6 +1057,17 @@ unsigned int Image::computeBlockSize(GLenum pixelFormat, GLenum packing)

unsigned int Image::computeRowWidthInBytes(int width,GLenum pixelFormat,GLenum type,int packing)
{
// Handle block-compressed formats (S3TC, RGTC, BPTC, etc.)
// Prevents stride/pitch misalignment. Surprised this didn't come up sooner on the S3TC formats.
int blockSize = computeBlockSize(pixelFormat, 0);
if (blockSize > 0) {
osg::Vec3i footprint = computeBlockFootprint(pixelFormat);
int blocksWide = (width + footprint.x() - 1) / footprint.x();
unsigned int size = blockSize * blocksWide;
return roudUpToMultiple(size, packing);
}

// Non-compressed formats
unsigned int pixelSize = computePixelSizeInBits(pixelFormat,type);
int widthInBits = width*pixelSize;
int packingInBits = packing!=0 ? packing*8 : 8;
Expand Down Expand Up @@ -1822,6 +1869,14 @@ void Image::flipVertical()
return;
}

// BPTC (BC6H/BC7) textures cannot be flipped in compressed form due to complex per-block encoding.
// Callers should check isBPTC() and set TOP_LEFT origin instead of calling flipVertical().
if (Image::isBPTC(_pixelFormat))
{
OSG_WARN << "Image::flipVertical(): BPTC (BC6H/BC7) textures cannot be flipped in compressed form." << std::endl;
return;
}

unsigned int rowSize = getRowSizeInBytes();
unsigned int rowStep = getRowStepInBytes();

Expand Down
27 changes: 23 additions & 4 deletions src/osg/Texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,10 @@ InternalPixelRelations compressedInternalFormats[] = {
, { GL_COMPRESSED_SIGNED_RED_RGTC1_EXT , GL_RED , GL_COMPRESSED_SIGNED_RED_RGTC1_EXT }
// , { GL_COMPRESSED_RG_RGTC2 , GL_RG , GL_COMPRESSED_RG_RGTC2 }
// , { GL_COMPRESSED_SIGNED_RG_RGTC2 , GL_RG , GL_COMPRESSED_SIGNED_RG_RGTC2 }
// , { GL_COMPRESSED_RGBA_BPTC_UNORM , GL_RGBA , GL_COMPRESSED_RGBA_BPTC_UNORM }
// , { GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM , GL_RGBA , GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM }
// , { GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT , GL_RGB , GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT }
// , { GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT , GL_RGB , GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT }
, { GL_COMPRESSED_RGBA_BPTC_UNORM , GL_RGBA , GL_COMPRESSED_RGBA_BPTC_UNORM }
, { GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM , GL_RGBA , GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM }
, { GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT , GL_RGB , GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT }
, { GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT , GL_RGB , GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT }

, { GL_COMPRESSED_RGB_S3TC_DXT1_EXT , GL_RGB , GL_COMPRESSED_RGB_S3TC_DXT1_EXT }
, { GL_COMPRESSED_RGBA_S3TC_DXT1_EXT , GL_RGBA , GL_COMPRESSED_RGBA_S3TC_DXT1_EXT }
Expand Down Expand Up @@ -377,6 +377,12 @@ void Texture::TextureProfile::computeSize()
case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: numBitsPerTexel = 8; break;
case GL_COMPRESSED_RED_GREEN_RGTC2_EXT: numBitsPerTexel = 8; break;

// BPTC (BC6H/BC7)
case GL_COMPRESSED_RGBA_BPTC_UNORM: numBitsPerTexel = 8; break;
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: numBitsPerTexel = 8; break;
case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: numBitsPerTexel = 8; break;
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: numBitsPerTexel = 8; break;

case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: numBitsPerTexel = 2; break;
case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: numBitsPerTexel = 2; break;
case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: numBitsPerTexel = 4; break;
Expand Down Expand Up @@ -1898,6 +1904,11 @@ bool Texture::isCompressedInternalFormat(GLint internalFormat)
case (GL_COMPRESSED_RED_RGTC1_EXT):
case (GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT):
case (GL_COMPRESSED_RED_GREEN_RGTC2_EXT):
// BPTC (BC6H/BC7)
case (GL_COMPRESSED_RGBA_BPTC_UNORM):
case (GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM):
case (GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT):
case (GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT):
case (GL_ETC1_RGB8_OES):
case (GL_COMPRESSED_RGB8_ETC2):
case (GL_COMPRESSED_SRGB8_ETC2):
Expand Down Expand Up @@ -1969,6 +1980,9 @@ void Texture::getCompressedSize(GLenum internalFormat, GLint width, GLint height
blockSize = 8;
else if (internalFormat == GL_COMPRESSED_RED_GREEN_RGTC2_EXT || internalFormat == GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT)
blockSize = 16;
// BPTC (BC6H/BC7) - 128 bits per block
else if (internalFormat == GL_COMPRESSED_RGBA_BPTC_UNORM || internalFormat == GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM || internalFormat == GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT || internalFormat == GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT)
blockSize = 16;
else if (internalFormat == GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG || internalFormat == GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG)
{
blockSize = 8 * 4; // Pixel by pixel block size for 2bpp
Expand Down Expand Up @@ -2397,6 +2411,11 @@ void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* ima
case(GL_COMPRESSED_SIGNED_RG11_EAC):
case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
case GL_COMPRESSED_RED_GREEN_RGTC2_EXT: _internalFormat = GL_RG; break;
// BPTC (BC6H/BC7)
case GL_COMPRESSED_RGBA_BPTC_UNORM:
case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: _internalFormat = GL_RGBA; break;
case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: _internalFormat = GL_RGB; break;
}
}

Expand Down
30 changes: 29 additions & 1 deletion src/osgPlugins/dds/ReaderWriterDDS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,30 @@ osg::Image* ReadDDSFile(std::istream& _istream, bool flipDDSRead)
pixelFormat = GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT;
break;

case OSG_DXGI_FORMAT_BC6H_UF16:
internalFormat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT;
pixelFormat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT;
packing = 4; // 8 bits/pixel. 4 px = 4 bytes
break;

case OSG_DXGI_FORMAT_BC6H_SF16:
internalFormat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT;
pixelFormat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT;
packing = 4; // 8 bits/pixel. 4 px = 4 bytes
break;

case OSG_DXGI_FORMAT_BC7_UNORM:
internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM;
pixelFormat = GL_COMPRESSED_RGBA_BPTC_UNORM;
packing = 4; // 8 bits/pixel. 4 px = 4 bytes
break;

case OSG_DXGI_FORMAT_BC7_UNORM_SRGB:
internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
pixelFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
packing = 4; // 8 bits/pixel. 4 px = 4 bytes
break;

default:
OSG_WARN << "ReadDDSFile warning: unhandled DX10 pixel format 0x"
<< std::hex << std::setw(8) << std::setfill('0')
Expand Down Expand Up @@ -1100,7 +1124,11 @@ osg::Image* ReadDDSFile(std::istream& _istream, bool flipDDSRead)

if (mipmap_offsets.size()>0) osgImage->setMipmapLevels(mipmap_offsets);

if (flipDDSRead) {
osgImage->setOrigin(osg::Image::TOP_LEFT);

// BPTC (BC6H/BC7) textures cannot be flipped in compressed form
if (flipDDSRead && !osg::Image::isBPTC(internalFormat))
{
osgImage->setOrigin(osg::Image::BOTTOM_LEFT);
if (!isDXTC || ((s>4 && s%4==0 && t>4 && t%4==0) || s<=4)) // Flip may crash (access violation) or fail for non %4 dimensions (except for s<4). Tested with revision trunk 2013-02-22.
{
Expand Down