From 6473efa9953f3b28a13425ea1819340a508538f1 Mon Sep 17 00:00:00 2001 From: SNMetamorph <25657591+SNMetamorph@users.noreply.github.com> Date: Thu, 3 Mar 2022 13:42:29 +0400 Subject: [PATCH] engine: added support for BC7 and BC6H compression formats of DDS textures --- common/com_image.h | 13 +-- engine/common/imagelib/img_dds.c | 96 +++++++++++++------- engine/common/imagelib/img_dds.h | 145 +++++++++++++++++++++++++++++++ 3 files changed, 220 insertions(+), 34 deletions(-) diff --git a/common/com_image.h b/common/com_image.h index 063309ab..c270cf26 100644 --- a/common/com_image.h +++ b/common/com_image.h @@ -9,7 +9,7 @@ NOTE: number at end of pixelformat name it's a total bitscount e.g. PF_RGB_24 == ======================================================================== */ #define ImageRAW( type ) (type == PF_RGBA_32 || type == PF_BGRA_32 || type == PF_RGB_24 || type == PF_BGR_24 || type == PF_LUMINANCE) -#define ImageDXT( type ) (type == PF_DXT1 || type == PF_DXT3 || type == PF_DXT5 || type == PF_ATI2) +#define ImageDXT( type ) (type == PF_DXT1 || type == PF_DXT3 || type == PF_DXT5 || type == PF_ATI2 || type == PF_BC6H_SIGNED || type == PF_BC6H_UNSIGNED || type == PF_BC7) typedef enum { @@ -21,10 +21,13 @@ typedef enum PF_RGB_24, // uncompressed dds or another 24-bit image PF_BGR_24, // big-endian RGB (MacOS) PF_LUMINANCE, - PF_DXT1, // s3tc DXT1 format - PF_DXT3, // s3tc DXT3 format - PF_DXT5, // s3tc DXT5 format - PF_ATI2, // latc ATI2N format + PF_DXT1, // s3tc DXT1/BC1 format + PF_DXT3, // s3tc DXT3/BC2 format + PF_DXT5, // s3tc DXT5/BC3 format + PF_ATI2, // latc ATI2N/BC5 format + PF_BC6H_SIGNED, // bptc BC6H signed FP16 format + PF_BC6H_UNSIGNED, // bptc BC6H unsigned FP16 format + PF_BC7, // bptc BC7 format PF_TOTALCOUNT, // must be last } pixformat_t; diff --git a/engine/common/imagelib/img_dds.c b/engine/common/imagelib/img_dds.c index 845813c6..361ddae2 100644 --- a/engine/common/imagelib/img_dds.c +++ b/engine/common/imagelib/img_dds.c @@ -91,7 +91,7 @@ qboolean Image_CheckDXT5Alpha( dds_t *hdr, byte *fin ) return false; } -void Image_DXTGetPixelFormat( dds_t *hdr ) +void Image_DXTGetPixelFormat( dds_t *hdr, dds_header_dxt10_t *headerExt ) { uint bits = hdr->dsPixelFormat.dwRGBBitCount; @@ -100,29 +100,53 @@ void Image_DXTGetPixelFormat( dds_t *hdr ) if( FBitSet( hdr->dsPixelFormat.dwFlags, DDS_FOURCC )) { - switch( hdr->dsPixelFormat.dwFourCC ) + if( hdr->dsPixelFormat.dwFourCC == TYPE_DX10 ) { - case TYPE_DXT1: - image.type = PF_DXT1; - break; - case TYPE_DXT2: - image.flags &= ~IMAGE_HAS_ALPHA; // alpha is already premultiplied by color - // intentionally fallthrough - case TYPE_DXT3: - image.type = PF_DXT3; - break; - case TYPE_DXT4: - image.flags &= ~IMAGE_HAS_ALPHA; // alpha is already premultiplied by color - // intentionally fallthrough - case TYPE_DXT5: - image.type = PF_DXT5; - break; - case TYPE_ATI2: - image.type = PF_ATI2; - break; - default: - image.type = PF_UNKNOWN; // assume error - break; + switch( headerExt->dxgiFormat ) + { + case DXGI_FORMAT_BC6H_SF16: + image.type = PF_BC6H_SIGNED; + break; + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_TYPELESS: + image.type = PF_BC6H_UNSIGNED; + break; + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: + case DXGI_FORMAT_BC7_TYPELESS: + image.type = PF_BC7; + break; + default: + image.type = PF_UNKNOWN; + break; + } + } + else + { + switch( hdr->dsPixelFormat.dwFourCC ) + { + case TYPE_DXT1: + image.type = PF_DXT1; + break; + case TYPE_DXT2: + image.flags &= ~IMAGE_HAS_ALPHA; // alpha is already premultiplied by color + // intentionally fallthrough + case TYPE_DXT3: + image.type = PF_DXT3; + break; + case TYPE_DXT4: + image.flags &= ~IMAGE_HAS_ALPHA; // alpha is already premultiplied by color + // intentionally fallthrough + case TYPE_DXT5: + image.type = PF_DXT5; + break; + case TYPE_ATI2: + image.type = PF_ATI2; + break; + default: + image.type = PF_UNKNOWN; // assume error + break; + } } } else @@ -171,6 +195,9 @@ size_t Image_DXTGetLinearSize( int type, int width, int height, int depth ) case PF_DXT1: return ((( width + 3 ) / 4 ) * (( height + 3 ) / 4 ) * depth * 8 ); case PF_DXT3: case PF_DXT5: + case PF_BC6H_SIGNED: + case PF_BC6H_UNSIGNED: + case PF_BC7: case PF_ATI2: return ((( width + 3 ) / 4 ) * (( height + 3 ) / 4 ) * depth * 16 ); case PF_LUMINANCE: return (width * height * depth); case PF_BGR_24: @@ -254,16 +281,18 @@ qboolean Image_LoadDDS( const char *name, const byte *buffer, fs_offset_t filesi { dds_t header; byte *fin; + int headersOffset; + dds_header_dxt10_t header2; - if( filesize < sizeof( dds_t )) + if( filesize < sizeof( header )) return false; - memcpy( &header, buffer, sizeof( dds_t )); + memcpy( &header, buffer, sizeof( header )); if( header.dwIdent != DDSHEADER ) return false; // it's not a dds file, just skip it - if( header.dwSize != sizeof( dds_t ) - sizeof( uint )) // size of the structure (minus MagicNum) + if( header.dwSize != sizeof( header ) - sizeof( uint )) // size of the structure (minus MagicNum) { Con_DPrintf( S_ERROR "Image_LoadDDS: (%s) have corrupted header\n", name ); return false; @@ -275,6 +304,13 @@ qboolean Image_LoadDDS( const char *name, const byte *buffer, fs_offset_t filesi return false; } + headersOffset = sizeof( header ); + if( header.dsPixelFormat.dwFourCC == TYPE_DX10 ) + { + memcpy( &header2, buffer + sizeof( header ), sizeof( header2 )); + headersOffset += sizeof( header2 ); + } + image.width = header.dwWidth; image.height = header.dwHeight; @@ -284,7 +320,7 @@ qboolean Image_LoadDDS( const char *name, const byte *buffer, fs_offset_t filesi if( !Image_ValidSize( name )) return false; - Image_DXTGetPixelFormat( &header ); // and image type too :) + Image_DXTGetPixelFormat( &header, &header2 ); // and image type too :) Image_DXTAdjustVolume( &header ); if( !Image_CheckFlag( IL_DDS_HARDWARE ) && ImageDXT( image.type )) @@ -296,9 +332,9 @@ qboolean Image_LoadDDS( const char *name, const byte *buffer, fs_offset_t filesi return false; } - image.size = Image_DXTCalcSize( name, &header, filesize - 128 ); + image.size = Image_DXTCalcSize( name, &header, filesize - headersOffset ); if( image.size == 0 ) return false; // just in case - fin = (byte *)(buffer + sizeof( dds_t )); + fin = (byte *)( buffer + headersOffset ); // copy an encode method image.encode = (word)header.dwReserved1[0]; @@ -320,6 +356,8 @@ qboolean Image_LoadDDS( const char *name, const byte *buffer, fs_offset_t filesi SetBits( image.flags, IMAGE_HAS_ALPHA ); else if( image.type == PF_DXT5 && Image_CheckDXT5Alpha( &header, fin )) SetBits( image.flags, IMAGE_HAS_ALPHA ); + else if ( image.type == PF_BC7 ) + SetBits(image.flags, IMAGE_HAS_ALPHA); if( !FBitSet( header.dsPixelFormat.dwFlags, DDS_LUMINANCE )) SetBits( image.flags, IMAGE_HAS_COLOR ); break; diff --git a/engine/common/imagelib/img_dds.h b/engine/common/imagelib/img_dds.h index 43329233..b13c342c 100644 --- a/engine/common/imagelib/img_dds.h +++ b/engine/common/imagelib/img_dds.h @@ -29,6 +29,7 @@ GNU General Public License for more details. #define TYPE_DXT3 (('3'<<24)+('T'<<16)+('X'<<8)+'D') // little-endian "DXT3" #define TYPE_DXT4 (('4'<<24)+('T'<<16)+('X'<<8)+'D') // little-endian "DXT4" #define TYPE_DXT5 (('5'<<24)+('T'<<16)+('X'<<8)+'D') // little-endian "DXT5" +#define TYPE_DX10 (('0'<<24)+('1'<<16)+('X'<<8)+'D') // little-endian "DX10" #define TYPE_ATI1 (('1'<<24)+('I'<<16)+('T'<<8)+'A') // little-endian "ATI1" #define TYPE_ATI2 (('2'<<24)+('I'<<16)+('T'<<8)+'A') // little-endian "ATI2" #define TYPE_RXGB (('B'<<24)+('G'<<16)+('X'<<8)+'R') // little-endian "RXGB" doom3 normalmaps @@ -75,6 +76,141 @@ GNU General Public License for more details. #define DDS_CUBEMAP_ALL_SIDES 0x0000FC00L #define DDS_VOLUME 0x00200000L +typedef enum +{ + DXGI_FORMAT_UNKNOWN = 0, + DXGI_FORMAT_R32G32B32A32_TYPELESS = 1, + DXGI_FORMAT_R32G32B32A32_FLOAT = 2, + DXGI_FORMAT_R32G32B32A32_UINT = 3, + DXGI_FORMAT_R32G32B32A32_SINT = 4, + DXGI_FORMAT_R32G32B32_TYPELESS = 5, + DXGI_FORMAT_R32G32B32_FLOAT = 6, + DXGI_FORMAT_R32G32B32_UINT = 7, + DXGI_FORMAT_R32G32B32_SINT = 8, + DXGI_FORMAT_R16G16B16A16_TYPELESS = 9, + DXGI_FORMAT_R16G16B16A16_FLOAT = 10, + DXGI_FORMAT_R16G16B16A16_UNORM = 11, + DXGI_FORMAT_R16G16B16A16_UINT = 12, + DXGI_FORMAT_R16G16B16A16_SNORM = 13, + DXGI_FORMAT_R16G16B16A16_SINT = 14, + DXGI_FORMAT_R32G32_TYPELESS = 15, + DXGI_FORMAT_R32G32_FLOAT = 16, + DXGI_FORMAT_R32G32_UINT = 17, + DXGI_FORMAT_R32G32_SINT = 18, + DXGI_FORMAT_R32G8X24_TYPELESS = 19, + DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20, + DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21, + DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22, + DXGI_FORMAT_R10G10B10A2_TYPELESS = 23, + DXGI_FORMAT_R10G10B10A2_UNORM = 24, + DXGI_FORMAT_R10G10B10A2_UINT = 25, + DXGI_FORMAT_R11G11B10_FLOAT = 26, + DXGI_FORMAT_R8G8B8A8_TYPELESS = 27, + DXGI_FORMAT_R8G8B8A8_UNORM = 28, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29, + DXGI_FORMAT_R8G8B8A8_UINT = 30, + DXGI_FORMAT_R8G8B8A8_SNORM = 31, + DXGI_FORMAT_R8G8B8A8_SINT = 32, + DXGI_FORMAT_R16G16_TYPELESS = 33, + DXGI_FORMAT_R16G16_FLOAT = 34, + DXGI_FORMAT_R16G16_UNORM = 35, + DXGI_FORMAT_R16G16_UINT = 36, + DXGI_FORMAT_R16G16_SNORM = 37, + DXGI_FORMAT_R16G16_SINT = 38, + DXGI_FORMAT_R32_TYPELESS = 39, + DXGI_FORMAT_D32_FLOAT = 40, + DXGI_FORMAT_R32_FLOAT = 41, + DXGI_FORMAT_R32_UINT = 42, + DXGI_FORMAT_R32_SINT = 43, + DXGI_FORMAT_R24G8_TYPELESS = 44, + DXGI_FORMAT_D24_UNORM_S8_UINT = 45, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46, + DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47, + DXGI_FORMAT_R8G8_TYPELESS = 48, + DXGI_FORMAT_R8G8_UNORM = 49, + DXGI_FORMAT_R8G8_UINT = 50, + DXGI_FORMAT_R8G8_SNORM = 51, + DXGI_FORMAT_R8G8_SINT = 52, + DXGI_FORMAT_R16_TYPELESS = 53, + DXGI_FORMAT_R16_FLOAT = 54, + DXGI_FORMAT_D16_UNORM = 55, + DXGI_FORMAT_R16_UNORM = 56, + DXGI_FORMAT_R16_UINT = 57, + DXGI_FORMAT_R16_SNORM = 58, + DXGI_FORMAT_R16_SINT = 59, + DXGI_FORMAT_R8_TYPELESS = 60, + DXGI_FORMAT_R8_UNORM = 61, + DXGI_FORMAT_R8_UINT = 62, + DXGI_FORMAT_R8_SNORM = 63, + DXGI_FORMAT_R8_SINT = 64, + DXGI_FORMAT_A8_UNORM = 65, + DXGI_FORMAT_R1_UNORM = 66, + DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67, + DXGI_FORMAT_R8G8_B8G8_UNORM = 68, + DXGI_FORMAT_G8R8_G8B8_UNORM = 69, + DXGI_FORMAT_BC1_TYPELESS = 70, + DXGI_FORMAT_BC1_UNORM = 71, + DXGI_FORMAT_BC1_UNORM_SRGB = 72, + DXGI_FORMAT_BC2_TYPELESS = 73, + DXGI_FORMAT_BC2_UNORM = 74, + DXGI_FORMAT_BC2_UNORM_SRGB = 75, + DXGI_FORMAT_BC3_TYPELESS = 76, + DXGI_FORMAT_BC3_UNORM = 77, + DXGI_FORMAT_BC3_UNORM_SRGB = 78, + DXGI_FORMAT_BC4_TYPELESS = 79, + DXGI_FORMAT_BC4_UNORM = 80, + DXGI_FORMAT_BC4_SNORM = 81, + DXGI_FORMAT_BC5_TYPELESS = 82, + DXGI_FORMAT_BC5_UNORM = 83, + DXGI_FORMAT_BC5_SNORM = 84, + DXGI_FORMAT_B5G6R5_UNORM = 85, + DXGI_FORMAT_B5G5R5A1_UNORM = 86, + DXGI_FORMAT_B8G8R8A8_UNORM = 87, + DXGI_FORMAT_B8G8R8X8_UNORM = 88, + DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89, + DXGI_FORMAT_B8G8R8A8_TYPELESS = 90, + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91, + DXGI_FORMAT_B8G8R8X8_TYPELESS = 92, + DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93, + DXGI_FORMAT_BC6H_TYPELESS = 94, + DXGI_FORMAT_BC6H_UF16 = 95, + DXGI_FORMAT_BC6H_SF16 = 96, + DXGI_FORMAT_BC7_TYPELESS = 97, + DXGI_FORMAT_BC7_UNORM = 98, + DXGI_FORMAT_BC7_UNORM_SRGB = 99, + DXGI_FORMAT_AYUV = 100, + DXGI_FORMAT_Y410 = 101, + DXGI_FORMAT_Y416 = 102, + DXGI_FORMAT_NV12 = 103, + DXGI_FORMAT_P010 = 104, + DXGI_FORMAT_P016 = 105, + DXGI_FORMAT_420_OPAQUE = 106, + DXGI_FORMAT_YUY2 = 107, + DXGI_FORMAT_Y210 = 108, + DXGI_FORMAT_Y216 = 109, + DXGI_FORMAT_NV11 = 110, + DXGI_FORMAT_AI44 = 111, + DXGI_FORMAT_IA44 = 112, + DXGI_FORMAT_P8 = 113, + DXGI_FORMAT_A8P8 = 114, + DXGI_FORMAT_B4G4R4A4_UNORM = 115, + DXGI_FORMAT_P208 = 130, + DXGI_FORMAT_V208 = 131, + DXGI_FORMAT_V408 = 132, + DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE, + DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE, + DXGI_FORMAT_FORCE_UINT = 0xffffffff +} dxgi_format_t; + +typedef enum +{ + D3D10_RESOURCE_DIMENSION_UNKNOWN = 0, + D3D10_RESOURCE_DIMENSION_BUFFER = 1, + D3D10_RESOURCE_DIMENSION_TEXTURE1D = 2, + D3D10_RESOURCE_DIMENSION_TEXTURE2D = 3, + D3D10_RESOURCE_DIMENSION_TEXTURE3D = 4 +} dds_resource_dimension_t; + typedef struct dds_pf_s { uint32_t dwSize; @@ -96,6 +232,15 @@ typedef struct dds_caps_s uint32_t dwCaps4; // currently unused } dds_caps_t; +typedef struct dds_header_dxt10_s +{ + dxgi_format_t dxgiFormat; + dds_resource_dimension_t resourceDimension; + uint32_t miscFlag; + uint32_t arraySize; + uint32_t miscFlags2; +} dds_header_dxt10_t; + typedef struct dds_s { uint32_t dwIdent; // must matched with DDSHEADER