Skip to content

Commit

Permalink
Merge pull request #23 from Capostrophic/bc4bc5
Browse files Browse the repository at this point in the history
Support BC4- and BC5-compressed DDS images
  • Loading branch information
psi29a authored Mar 29, 2024
2 parents 2ad03d6 + 6664a6c commit 673f30a
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 21 deletions.
7 changes: 4 additions & 3 deletions src/osg/Image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1826,13 +1826,14 @@ void Image::flipVertical()
unsigned int rowStep = getRowStepInBytes();

const bool dxtc(dxtc_tool::isDXTC(_pixelFormat));
const bool rgtc(dxtc_tool::isRGTC(_pixelFormat));
if (_mipmapData.empty())
{
// no mipmaps,
// so we can safely handle 3d textures
for(int r=0;r<_r;++r)
{
if (dxtc)
if (dxtc || rgtc)
{
if (!dxtc_tool::VerticalFlip(_s,_t,_pixelFormat,data(0,0,r)))
{
Expand All @@ -1852,7 +1853,7 @@ void Image::flipVertical()
}
else if (_r==1)
{
if (dxtc)
if (dxtc || rgtc)
{
if (!dxtc_tool::VerticalFlip(_s,_t,_pixelFormat,_data))
{
Expand All @@ -1879,7 +1880,7 @@ void Image::flipVertical()
t >>= 1;
if (s==0) s=1;
if (t==0) t=1;
if (dxtc)
if (dxtc || rgtc)
{
if (!dxtc_tool::VerticalFlip(s,t,_pixelFormat,_data+_mipmapData[i]))
{
Expand Down
62 changes: 62 additions & 0 deletions src/osg/dxtctool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace dxtc_tool {
const size_t dxtc_pixels::BSIZE_DXT1 = 8;
const size_t dxtc_pixels::BSIZE_DXT3 = 16;
const size_t dxtc_pixels::BSIZE_DXT5 = 16;
const size_t dxtc_pixels::BSIZE_RGTC1 = 8;
const size_t dxtc_pixels::BSIZE_RGTC2 = 16;
const size_t dxtc_pixels::BSIZE_ALPHA_DXT3 = 8;
const size_t dxtc_pixels::BSIZE_ALPHA_DXT5 = 8;

Expand Down Expand Up @@ -68,6 +70,10 @@ bool dxtc_pixels::VFlip() const
VFlip_DXT3();
else if (DXT5())
VFlip_DXT5();
else if (RGTC1())
VFlip_RGTC1();
else if (RGTC2())
VFlip_RGTC2();
else
return false; // We should never get there

Expand Down Expand Up @@ -155,6 +161,48 @@ void dxtc_pixels::VFlip_DXT5() const
}
}

void dxtc_pixels::VFlip_RGTC1() const
{
if (m_Height == 2)
for (size_t j = 0; j < (m_Width + 3) / 4; ++j) {
BVF_Alpha_DXT5_H2(((dxtc_int8 * ) m_pPixels) + (j * BSIZE_RGTC1));
}

if (m_Height == 4)
for (size_t j = 0; j < (m_Width + 3) / 4; ++j) {
BVF_Alpha_DXT5_H4(((dxtc_int8 * ) m_pPixels) + (j * BSIZE_RGTC1));
}

if (m_Height > 4)
for (size_t i = 0; i < ((m_Height + 7) / 8); ++i)
for (size_t j = 0; j < (m_Width + 3) / 4; ++j) {
const size_t TargetRow = ((m_Height + 3) / 4) - (i + 1);
BVF_Alpha_DXT5(GetBlock(i, j, BSIZE_RGTC1), GetBlock(TargetRow, j, BSIZE_RGTC1));
}
}

void dxtc_pixels::VFlip_RGTC2() const
{
if (m_Height == 2)
for (size_t j = 0; j < (m_Width + 3) / 4; ++j) {
BVF_Alpha_DXT5_H2(((dxtc_int8 * ) m_pPixels) + (j * BSIZE_RGTC2));
BVF_Alpha_DXT5_H2(((dxtc_int8 * ) m_pPixels) + (j * BSIZE_RGTC2) + BSIZE_RGTC2 / 2);
}

if (m_Height == 4)
for (size_t j = 0; j < (m_Width + 3) / 4; ++j) {
BVF_Alpha_DXT5_H4(((dxtc_int8 * ) m_pPixels) + (j * BSIZE_RGTC2));
BVF_Alpha_DXT5_H4(((dxtc_int8 * ) m_pPixels) + (j * BSIZE_RGTC2) + BSIZE_RGTC2 / 2);
}

if (m_Height > 4)
for (size_t i = 0; i < ((m_Height + 7) / 8); ++i)
for (size_t j = 0; j < (m_Width + 3) / 4; ++j) {
const size_t TargetRow = ((m_Height + 3) / 4) - (i + 1);
BVF_Color_RGTC2(GetBlock(i, j, BSIZE_RGTC2), GetBlock(TargetRow, j, BSIZE_RGTC2));
}
}

//
// Structure of a DXT-1 compressed texture block
// see page "Opaque and 1-Bit Alpha Textures (Direct3D 9)" on http://msdn.microsoft.com
Expand Down Expand Up @@ -184,6 +232,18 @@ struct DXT5TexelsBlock
unsigned int texels4x4; // interpolated colors (2 bits per texel)
};

struct RGTC1TexelsBlock
{
unsigned char color_0; // colors at their
unsigned char color_1; // extreme
unsigned char color3[6]; // color index values (3 bits per texel)
};

struct RGTC2TexelsBlock
{
RGTC1TexelsBlock channels[2];
};

bool isCompressedImageTranslucent(size_t width, size_t height, GLenum format, void * imageData)
{
// OSG_NOTICE<<"isCompressedImageTranslucent("<<width<<", "<<height<<", "<<format<<", "<<imageData<<")"<<std::endl;
Expand Down Expand Up @@ -475,6 +535,7 @@ bool CompressedImageGetColor(unsigned char color[4], unsigned int s, unsigned in
}
break;
}
// TODO: add RGTC support
default:
return false;
}
Expand Down Expand Up @@ -579,6 +640,7 @@ void compressedBlockOrientationConversion(const GLenum format, const unsigned ch
}
break;
}
// TODO: add RGTC support
default:
return;
}//switch
Expand Down
90 changes: 72 additions & 18 deletions src/osg/dxtctool.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
// Current version: 1.00 BETA 1 (27/08/2002)
//
// Comment: Only works with DXTC mode supported by OpenGL.
// (currently: DXT1/DXT3/DXT5)
// (currently: DXT1/DXT3/DXT5/RGTC1/RGTC2)
//
// History: -
//
Expand Down Expand Up @@ -77,6 +77,8 @@ namespace dxtc_tool {
// C-like function wrappers
bool isDXTC(GLenum pixelFormat);

bool isRGTC(GLenum pixelFormat);

bool VerticalFlip(size_t Width, size_t Height, GLenum Format, void * pPixels);

bool isCompressedImageTranslucent(size_t Width, size_t Height, GLenum Format, void * pPixels);
Expand Down Expand Up @@ -108,13 +110,17 @@ class dxtc_pixels
inline bool DXT1() const;
inline bool DXT3() const;
inline bool DXT5() const;
inline bool RGTC1() const;
inline bool RGTC2() const;
inline bool OpenGLSize() const;
inline bool SupportedFormat() const;

// Vertical flipping functions
void VFlip_DXT1() const;
void VFlip_DXT3() const;
void VFlip_DXT5() const;
void VFlip_RGTC1() const;
void VFlip_RGTC2() const;

// Block vertical flipping functions
inline void BVF_Color_H2(void * const pBlock) const; // V. flip one color block with its virtual height == 2
Expand All @@ -126,6 +132,7 @@ class dxtc_pixels
inline void BVF_Alpha_DXT5_H2(void * const pBlock) const; // V. flip one alpha (DXT5) block with its virtual height == 2
inline void BVF_Alpha_DXT5_H4(void * const pBlock) const; // V. flip one alpha (DXT5) block with its virtual height == 4
inline void BVF_Alpha_DXT5(void * const pBlock1, void * const pBlock2) const; // V. flip and swap two alpha (DXT5) blocks, with their virtual height == 4
inline void BVF_Color_RGTC2(void * const pBlock1, void * const pBlock2) const; // V. flip and swap two red-green (RGTC2) blocks, with their virtual height == 4

// Block localization functions
inline void * GetBlock(size_t i, size_t j, size_t BlockSize) const;
Expand All @@ -134,6 +141,8 @@ class dxtc_pixels
static const size_t BSIZE_DXT1;
static const size_t BSIZE_DXT3;
static const size_t BSIZE_DXT5;
static const size_t BSIZE_RGTC1;
static const size_t BSIZE_RGTC2;
static const size_t BSIZE_ALPHA_DXT3;
static const size_t BSIZE_ALPHA_DXT5;

Expand All @@ -158,16 +167,30 @@ inline bool isDXTC(GLenum pixelFormat)
case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT):
case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT):
case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT):
case(GL_COMPRESSED_SRGB_S3TC_DXT1_EXT):
case(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT):
case(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT):
case(GL_COMPRESSED_SRGB_S3TC_DXT1_EXT):
case(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT):
case(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT):
case(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT):
return true;
default:
return false;
}
}

inline bool isRGTC(GLenum pixelFormat)
{
switch(pixelFormat)
{
case(GL_COMPRESSED_RED_RGTC1_EXT):
case(GL_COMPRESSED_SIGNED_RED_RGTC1_EXT):
case(GL_COMPRESSED_RED_GREEN_RGTC2_EXT):
case(GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT):
return true;
default:
return false;
}
}

inline bool VerticalFlip(size_t Width, size_t Height, GLenum Format, void * pPixels) {
return (dxtc_pixels(Width, Height, Format, pPixels)).VFlip();
}
Expand All @@ -182,24 +205,32 @@ inline dxtc_pixels::dxtc_pixels(size_t Width, size_t Height, GLenum Format, void
m_Width(Width), m_Height(Height), m_Format(Format), m_pPixels(pPixels) { }


inline bool dxtc_pixels::DXT1() const {
return ((m_Format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) || (m_Format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
|| (m_Format == GL_COMPRESSED_SRGB_S3TC_DXT1_EXT) || (m_Format == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT));
}


inline bool dxtc_pixels::DXT3() const {
return ((m_Format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) || (m_Format == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT));
}


inline bool dxtc_pixels::DXT5() const {
return ((m_Format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) || (m_Format == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT));
inline bool dxtc_pixels::DXT1() const {
return ((m_Format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) || (m_Format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
|| (m_Format == GL_COMPRESSED_SRGB_S3TC_DXT1_EXT) || (m_Format == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT));
}


inline bool dxtc_pixels::DXT3() const {
return ((m_Format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) || (m_Format == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT));
}


inline bool dxtc_pixels::DXT5() const {
return ((m_Format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) || (m_Format == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT));
}

inline bool dxtc_pixels::RGTC1() const {
return ((m_Format == GL_COMPRESSED_RED_RGTC1_EXT) || (m_Format == GL_COMPRESSED_SIGNED_RED_RGTC1_EXT));
}

inline bool dxtc_pixels::RGTC2() const {
return ((m_Format == GL_COMPRESSED_RED_GREEN_RGTC2_EXT) || (m_Format == GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT));
}


inline bool dxtc_pixels::SupportedFormat() const {
return (DXT1() || DXT3() || DXT5());
return (DXT1() || DXT3() || DXT5() || RGTC1() || RGTC2());
}


Expand Down Expand Up @@ -317,6 +348,29 @@ inline void dxtc_pixels::BVF_Alpha_DXT5(void * const pBlock1, void * const pBloc
}


inline void dxtc_pixels::BVF_Color_RGTC2(void * const pBlock1, void * const pBlock2) const {
dxtc_int64 * pB1 = (dxtc_int64 * ) pBlock1;
dxtc_int64 * pB2 = (dxtc_int64 * ) pBlock2;

for (int i = 0; i < 2; i++) {
dxtc_int64 TmpQWord1 = (pB1[i] & HEX_0x000000000000FFFF);
TmpQWord1 |= (pB1[i] & HEX_0x000000000FFF0000) << 36;
TmpQWord1 |= (pB1[i] & HEX_0x000000FFF0000000) << 12;
TmpQWord1 |= (pB1[i] & HEX_0x000FFF0000000000) >> 12;
TmpQWord1 |= (pB1[i] & HEX_0xFFF0000000000000) >> 36;

dxtc_int64 TmpQWord2 = (pB2[i] & HEX_0x000000000000FFFF);
TmpQWord2 |= (pB2[i] & HEX_0x000000000FFF0000) << 36;
TmpQWord2 |= (pB2[i] & HEX_0x000000FFF0000000) << 12;
TmpQWord2 |= (pB2[i] & HEX_0x000FFF0000000000) >> 12;
TmpQWord2 |= (pB2[i] & HEX_0xFFF0000000000000) >> 36;

pB1[i] = TmpQWord2;
pB2[i] = TmpQWord1;
}
}


inline void * dxtc_pixels::GetBlock(size_t i, size_t j, size_t BlockSize) const {
const dxtc_int8 * pPixels = (const dxtc_int8 *) m_pPixels;

Expand Down
44 changes: 44 additions & 0 deletions src/osgPlugins/dds/ReaderWriterDDS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,11 @@ struct DXT1TexelsBlock
* FOURCC codes for 3dc compressed-texture pixel formats
*/
#define FOURCC_ATI1 (MAKEFOURCC('A','T','I','1'))
#define FOURCC_BC4U (MAKEFOURCC('B','C','4','U'))
#define FOURCC_BC4S (MAKEFOURCC('B','C','4','S'))
#define FOURCC_ATI2 (MAKEFOURCC('A','T','I','2'))
#define FOURCC_BC5U (MAKEFOURCC('B','C','5','U'))
#define FOURCC_BC5S (MAKEFOURCC('B','C','5','S'))

/*
* FOURCC codes for DX10 files
Expand Down Expand Up @@ -517,11 +521,31 @@ osg::Image* ReadDDSFile(std::istream& _istream, bool flipDDSRead)
internalFormat = GL_COMPRESSED_RED_RGTC1_EXT;
pixelFormat = GL_COMPRESSED_RED_RGTC1_EXT;
break;
case FOURCC_BC4U:
OSG_INFO << "ReadDDSFile info : format = BC4U" << std::endl;
internalFormat = GL_COMPRESSED_RED_RGTC1_EXT;
pixelFormat = GL_COMPRESSED_RED_RGTC1_EXT;
break;
case FOURCC_BC4S:
OSG_INFO << "ReadDDSFile info : format = BC4S" << std::endl;
internalFormat = GL_COMPRESSED_SIGNED_RED_RGTC1_EXT;
pixelFormat = GL_COMPRESSED_SIGNED_RED_RGTC1_EXT;
break;
case FOURCC_ATI2:
OSG_INFO << "ReadDDSFile info : format = ATI2" << std::endl;
internalFormat = GL_COMPRESSED_RED_GREEN_RGTC2_EXT;
pixelFormat = GL_COMPRESSED_RED_GREEN_RGTC2_EXT;
break;
case FOURCC_BC5U:
OSG_INFO << "ReadDDSFile info : format = BC5U" << std::endl;
internalFormat = GL_COMPRESSED_RED_GREEN_RGTC2_EXT;
pixelFormat = GL_COMPRESSED_RED_GREEN_RGTC2_EXT;
break;
case FOURCC_BC5S:
OSG_INFO << "ReadDDSFile info : format = BC5S" << std::endl;
internalFormat = GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT;
pixelFormat = GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT;
break;
case 0x00000024: // A16B16G16R16
OSG_INFO << "ReadDDSFile info : format = A16B16G16R16" << std::endl;
internalFormat = GL_RGBA;
Expand Down Expand Up @@ -770,6 +794,26 @@ osg::Image* ReadDDSFile(std::istream& _istream, bool flipDDSRead)
dataType = GL_SHORT;
break;

case OSG_DXGI_FORMAT_BC4_UNORM:
internalFormat = GL_COMPRESSED_RED_RGTC1_EXT;
pixelFormat = GL_COMPRESSED_RED_RGTC1_EXT;
break;

case OSG_DXGI_FORMAT_BC4_SNORM:
internalFormat = GL_COMPRESSED_SIGNED_RED_RGTC1_EXT;
pixelFormat = GL_COMPRESSED_SIGNED_RED_RGTC1_EXT;
break;

case OSG_DXGI_FORMAT_BC5_UNORM:
internalFormat = GL_COMPRESSED_RED_GREEN_RGTC2_EXT;
pixelFormat = GL_COMPRESSED_RED_GREEN_RGTC2_EXT;
break;

case OSG_DXGI_FORMAT_BC5_SNORM:
internalFormat = GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT;
pixelFormat = GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT;
break;

default:
OSG_WARN << "ReadDDSFile warning: unhandled DX10 pixel format 0x"
<< std::hex << std::setw(8) << std::setfill('0')
Expand Down

0 comments on commit 673f30a

Please sign in to comment.