diff --git a/common/com_image.h b/common/com_image.h index d9f5ef6b..098a0d12 100644 --- a/common/com_image.h +++ b/common/com_image.h @@ -9,7 +9,20 @@ 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 || type == PF_BC6H_SIGNED || type == PF_BC6H_UNSIGNED || type == PF_BC7) +#define ImageCompressed( type ) \ + ( type == PF_DXT1 \ + || type == PF_DXT3 \ + || type == PF_DXT5 \ + || type == PF_ATI2 \ + || type == PF_BC4_SIGNED \ + || type == PF_BC4_UNSIGNED \ + || type == PF_BC5_SIGNED \ + || type == PF_BC5_UNSIGNED \ + || type == PF_BC6H_SIGNED \ + || type == PF_BC6H_UNSIGNED \ + || type == PF_BC7_UNORM \ + || type == PF_BC7_SRGB \ + || type == PF_KTX2_RAW ) typedef enum { @@ -25,9 +38,15 @@ typedef enum PF_DXT3, // s3tc DXT3/BC2 format PF_DXT5, // s3tc DXT5/BC3 format PF_ATI2, // latc ATI2N/BC5 format + PF_BC4_SIGNED, + PF_BC4_UNSIGNED, + PF_BC5_SIGNED, + PF_BC5_UNSIGNED, PF_BC6H_SIGNED, // bptc BC6H signed FP16 format PF_BC6H_UNSIGNED, // bptc BC6H unsigned FP16 format - PF_BC7, // bptc BC7 format + PF_BC7_UNORM, // bptc BC7 format + PF_BC7_SRGB, + PF_KTX2_RAW, // Raw KTX2 data, used for yet unsupported KTX2 subformats PF_TOTALCOUNT, // must be last } pixformat_t; @@ -50,6 +69,7 @@ typedef enum IL_LOAD_DECAL = BIT(5), // special mode for load gradient decals IL_OVERVIEW = BIT(6), // overview required some unque operations IL_LOAD_PLAYER_DECAL = BIT(7), // special mode for player decals + IL_KTX2_RAW = BIT(8), // renderer can consume raw KTX2 files (e.g. ref_vk) } ilFlags_t; // goes into rgbdata_t->encode diff --git a/engine/common/imagelib/imagelib.h b/engine/common/imagelib/imagelib.h index 26905ba2..e4b6614c 100644 --- a/engine/common/imagelib/imagelib.h +++ b/engine/common/imagelib/imagelib.h @@ -142,6 +142,7 @@ void Image_CopyPalette32bit( void ); void Image_SetPixelFormat( void ); void Image_GetPaletteQ1( void ); void Image_GetPaletteHL( void ); +size_t Image_ComputeSize( int type, int width, int height, int depth ); // // formats load @@ -156,6 +157,7 @@ qboolean Image_LoadDDS( const char *name, const byte *buffer, fs_offset_t filesi qboolean Image_LoadFNT( const char *name, const byte *buffer, fs_offset_t filesize ); qboolean Image_LoadLMP( const char *name, const byte *buffer, fs_offset_t filesize ); qboolean Image_LoadPAL( const char *name, const byte *buffer, fs_offset_t filesize ); +qboolean Image_LoadKTX2( const char *name, const byte *buffer, fs_offset_t filesize ); // // formats save diff --git a/engine/common/imagelib/img_dds.c b/engine/common/imagelib/img_dds.c index 361ddae2..1562f847 100644 --- a/engine/common/imagelib/img_dds.c +++ b/engine/common/imagelib/img_dds.c @@ -104,6 +104,13 @@ void Image_DXTGetPixelFormat( dds_t *hdr, dds_header_dxt10_t *headerExt ) { switch( headerExt->dxgiFormat ) { + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + image.type = PF_BC4_UNSIGNED; + break; + case DXGI_FORMAT_BC4_SNORM: + image.type = PF_BC4_SIGNED; + break; case DXGI_FORMAT_BC6H_SF16: image.type = PF_BC6H_SIGNED; break; @@ -112,9 +119,20 @@ void Image_DXTGetPixelFormat( dds_t *hdr, dds_header_dxt10_t *headerExt ) 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; + image.type = PF_BC7_UNORM; + break; + case DXGI_FORMAT_BC7_UNORM_SRGB: + image.type = PF_BC7_SRGB; + break; + case DXGI_FORMAT_BC5_TYPELESS: + image.type = PF_ATI2; + break; + case DXGI_FORMAT_BC5_UNORM: + image.type = PF_BC5_UNSIGNED; + break; + case DXGI_FORMAT_BC5_SNORM: + image.type = PF_BC5_SIGNED; break; default: image.type = PF_UNKNOWN; @@ -122,7 +140,7 @@ void Image_DXTGetPixelFormat( dds_t *hdr, dds_header_dxt10_t *headerExt ) } } else - { + { switch( hdr->dsPixelFormat.dwFourCC ) { case TYPE_DXT1: @@ -143,6 +161,15 @@ void Image_DXTGetPixelFormat( dds_t *hdr, dds_header_dxt10_t *headerExt ) case TYPE_ATI2: image.type = PF_ATI2; break; + case TYPE_BC5S: + image.type = PF_BC5_SIGNED; + break; + case TYPE_BC4S: + image.type = PF_BC4_SIGNED; + break; + case TYPE_BC4U: + image.type = PF_BC4_UNSIGNED; + break; default: image.type = PF_UNKNOWN; // assume error break; @@ -188,27 +215,6 @@ void Image_DXTGetPixelFormat( dds_t *hdr, dds_header_dxt10_t *headerExt ) image.num_mips = hdr->dwMipMapCount; // get actual mip count } -size_t Image_DXTGetLinearSize( int type, int width, int height, int depth ) -{ - switch( type ) - { - 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: - case PF_RGB_24: return (width * height * depth * 3); - case PF_BGRA_32: - case PF_RGBA_32: return (width * height * depth * 4); - } - - return 0; -} - size_t Image_DXTCalcMipmapSize( dds_t *hdr ) { size_t buffsize = 0; @@ -219,7 +225,7 @@ size_t Image_DXTCalcMipmapSize( dds_t *hdr ) { width = Q_max( 1, ( hdr->dwWidth >> i )); height = Q_max( 1, ( hdr->dwHeight >> i )); - buffsize += Image_DXTGetLinearSize( image.type, width, height, image.depth ); + buffsize += Image_ComputeSize( image.type, width, height, image.depth ); } return buffsize; @@ -255,7 +261,7 @@ uint Image_DXTCalcSize( const char *name, dds_t *hdr, size_t filesize ) if( filesize != buffsize ) // main check { - Con_DPrintf( S_WARN "Image_LoadDDS: (%s) probably corrupted (%i should be %lu)\n", name, buffsize, filesize ); + Con_DPrintf( S_WARN "Image_LoadDDS: (%s) probably corrupted (%zu should be %lu)\n", name, buffsize, filesize ); if( buffsize > filesize ) return false; } @@ -268,7 +274,7 @@ void Image_DXTAdjustVolume( dds_t *hdr ) if( hdr->dwDepth <= 1 ) return; - hdr->dwLinearSize = Image_DXTGetLinearSize( image.type, hdr->dwWidth, hdr->dwHeight, hdr->dwDepth ); + hdr->dwLinearSize = Image_ComputeSize( image.type, hdr->dwWidth, hdr->dwHeight, hdr->dwDepth ); hdr->dwFlags |= DDS_LINEARSIZE; } @@ -323,7 +329,7 @@ qboolean Image_LoadDDS( const char *name, const byte *buffer, fs_offset_t filesi Image_DXTGetPixelFormat( &header, &header2 ); // and image type too :) Image_DXTAdjustVolume( &header ); - if( !Image_CheckFlag( IL_DDS_HARDWARE ) && ImageDXT( image.type )) + if( !Image_CheckFlag( IL_DDS_HARDWARE ) && ImageCompressed( image.type )) return false; // silently rejected if( image.type == PF_UNKNOWN ) @@ -356,8 +362,10 @@ 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); + else if( image.type == PF_BC5_SIGNED || image.type == PF_BC5_UNSIGNED ) + SetBits( image.flags, IMAGE_HAS_ALPHA ); + else if( image.type == PF_BC7_UNORM || image.type == PF_BC7_SRGB ) + 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 b13c342c..dbf957b3 100644 --- a/engine/common/imagelib/img_dds.h +++ b/engine/common/imagelib/img_dds.h @@ -32,6 +32,9 @@ GNU General Public License for more details. #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_BC5S (('S'<<24)+('5'<<16)+('C'<<8)+'B') // little-endian "BC5S" +#define TYPE_BC4S (('S'<<24)+('4'<<16)+('C'<<8)+'B') // little-endian "BC4S" +#define TYPE_BC4U (('U'<<24)+('4'<<16)+('C'<<8)+'B') // little-endian "BC4U" #define TYPE_RXGB (('B'<<24)+('G'<<16)+('X'<<8)+'R') // little-endian "RXGB" doom3 normalmaps #define TYPE_$ (('\0'<<24)+('\0'<<16)+('\0'<<8)+'$') // little-endian "$" #define TYPE_o (('\0'<<24)+('\0'<<16)+('\0'<<8)+'o') // little-endian "o" @@ -202,7 +205,7 @@ typedef enum DXGI_FORMAT_FORCE_UINT = 0xffffffff } dxgi_format_t; -typedef enum +typedef enum { D3D10_RESOURCE_DIMENSION_UNKNOWN = 0, D3D10_RESOURCE_DIMENSION_BUFFER = 1, diff --git a/engine/common/imagelib/img_ktx2.c b/engine/common/imagelib/img_ktx2.c new file mode 100644 index 00000000..a33f563b --- /dev/null +++ b/engine/common/imagelib/img_ktx2.c @@ -0,0 +1,204 @@ +/* +img_ktx2.c - ktx2 format load +Copyright (C) 2023 Provod + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "imagelib.h" +#include "xash3d_mathlib.h" +#include "img_ktx2.h" + +static void Image_KTX2Format( uint32_t ktx2_format ) +{ + switch( ktx2_format ) + { + case KTX2_FORMAT_BC4_UNORM_BLOCK: + image.type = PF_BC4_UNSIGNED; + // 1 component for ref_gl + break; + case KTX2_FORMAT_BC4_SNORM_BLOCK: + image.type = PF_BC4_SIGNED; + // 1 component for ref_gl + break; + case KTX2_FORMAT_BC5_UNORM_BLOCK: + image.type = PF_BC5_UNSIGNED; + // 2 components for ref_gl + SetBits( image.flags, IMAGE_HAS_ALPHA ); + break; + case KTX2_FORMAT_BC5_SNORM_BLOCK: + image.type = PF_BC5_SIGNED; + // 2 components for ref_gl + SetBits( image.flags, IMAGE_HAS_ALPHA ); + break; + case KTX2_FORMAT_BC6H_UFLOAT_BLOCK: + image.type = PF_BC6H_UNSIGNED; + // 3 components for ref_gl + SetBits( image.flags, IMAGE_HAS_COLOR ); + break; + case KTX2_FORMAT_BC6H_SFLOAT_BLOCK: + image.type = PF_BC6H_SIGNED; + // 3 components for ref_gl + SetBits( image.flags, IMAGE_HAS_COLOR ); + break; + case KTX2_FORMAT_BC7_UNORM_BLOCK: + image.type = PF_BC7_UNORM; + // 4 components for ref_gl + SetBits( image.flags, IMAGE_HAS_COLOR | IMAGE_HAS_ALPHA ); + break; + case KTX2_FORMAT_BC7_SRGB_BLOCK: + image.type = PF_BC7_SRGB; + // 4 components for ref_gl + SetBits( image.flags, IMAGE_HAS_COLOR | IMAGE_HAS_ALPHA ); + break; + default: + image.type = PF_UNKNOWN; + break; + } +} + +static qboolean Image_KTX2Parse( const ktx2_header_t *header, const byte *buffer, fs_offset_t filesize ) +{ + ktx2_index_t index; + size_t total_size = 0; + size_t max_offset = 0; + const byte *const levels_begin = buffer + KTX2_LEVELS_OFFSET; + + // Sets image.type and image.flags + Image_KTX2Format( header->vkFormat ); + + if( image.type == PF_UNKNOWN ) + { + Con_DPrintf( S_ERROR "%s: unsupported KTX2 format %d\n", __FUNCTION__, header->vkFormat ); + return false; + } + + if( !Image_CheckFlag( IL_DDS_HARDWARE ) && ImageCompressed( image.type )) + { + Con_DPrintf( S_WARN "%s: has compressed format, but support is not advertized\n", __FUNCTION__ ); + return false; + } + + if( header->pixelDepth > 1 ) + { + Con_DPrintf( S_ERROR "%s: unsupported KTX2 pixelDepth %d\n", __FUNCTION__, header->pixelDepth ); + return false; + } + + if( header->faceCount > 1 ) + { + Con_DPrintf( S_ERROR "%s: unsupported KTX2 faceCount %d\n", __FUNCTION__, header->faceCount ); + return false; + } + + if( header->layerCount > 1 ) + { + Con_DPrintf( S_ERROR "%s: unsupported KTX2 layerCount %d\n", __FUNCTION__, header->layerCount ); + return false; + } + + if( header->supercompressionScheme != 0 ) + { + Con_DPrintf( S_ERROR "%s: unsupported KTX2 supercompressionScheme %d\n", __FUNCTION__, header->supercompressionScheme ); + return false; + } + + if( header->levelCount * sizeof( ktx2_level_t ) + KTX2_LEVELS_OFFSET > filesize ) + { + Con_DPrintf( S_ERROR "%s: file abruptly ends\n", __FUNCTION__ ); + return false; + } + + memcpy( &index, buffer + KTX2_IDENTIFIER_SIZE + sizeof( ktx2_header_t ), sizeof( index )); + + for( int mip = 0; mip < header->levelCount; ++mip ) + { + const uint32_t width = Q_max( 1, ( header->pixelWidth >> mip )); + const uint32_t height = Q_max( 1, ( header->pixelHeight >> mip )); + const uint32_t mip_size = Image_ComputeSize( image.type, width, height, image.depth ); + + ktx2_level_t level; + memcpy( &level, levels_begin + mip * sizeof( level ), sizeof( level )); + + if( mip_size != level.byteLength ) + { + Con_DPrintf( S_ERROR "%s: mip=%d size mismatch read=%d, but computed=%d\n", + __FUNCTION__, mip, (int)level.byteLength, mip_size ); + return false; + } + + total_size += level.byteLength; + max_offset = Q_max( max_offset, level.byteLength + level.byteOffset ); + } + + if( max_offset > filesize ) + return false; + + image.size = total_size; + image.num_mips = header->levelCount; + + image.rgba = Mem_Malloc( host.imagepool, image.size ); + memcpy( image.rgba, buffer, image.size ); + + for( int mip = 0, cursor = 0; mip < header->levelCount; ++mip ) + { + ktx2_level_t level; + memcpy( &level, levels_begin + mip * sizeof( level ), sizeof( level )); + memcpy( image.rgba + cursor, buffer + level.byteOffset, level.byteLength ); + cursor += level.byteLength; + } + + return true; +} + +qboolean Image_LoadKTX2( const char *name, const byte *buffer, fs_offset_t filesize ) +{ + ktx2_header_t header; + + if( filesize < KTX2_MINIMAL_HEADER_SIZE ) + return false; + + if( memcmp( buffer, KTX2_IDENTIFIER, KTX2_IDENTIFIER_SIZE ) != 0 ) + { + Con_DPrintf( S_ERROR "%s: (%s) has invalid identifier\n", __FUNCTION__, name ); + return false; + } + + memcpy( &header, buffer + KTX2_IDENTIFIER_SIZE, sizeof( header )); + + image.width = header.pixelWidth; + image.height = header.pixelHeight; + image.depth = Q_max( 1, header.pixelDepth ); + image.num_mips = 1; + + ClearBits( image.flags, IMAGE_HAS_COLOR | IMAGE_HAS_ALPHA | IMAGE_HAS_LUMA ); + + if( !Image_KTX2Parse( &header, buffer, filesize )) + { + if( !Image_CheckFlag( IL_KTX2_RAW )) + return false; + + // If KTX2 to imagelib conversion failed, try passing the file as raw data. + // This is useful for ref_vk which can directly support hundreds of formats which we don't convert to pixformat_t here + + Con_DPrintf( S_WARN "%s: (%s) could not be converted to supported imagelib format, passing as raw KTX2 data\n", __FUNCTION__, name ); + // This is a catch-all for ref_vk, which can do this format directly and natively + image.type = PF_KTX2_RAW; + + image.size = filesize; + //image.encode = TODO custom encode type? + + image.rgba = Mem_Malloc( host.imagepool, image.size ); + memcpy( image.rgba, buffer, image.size ); + } + + return true; +} diff --git a/engine/common/imagelib/img_ktx2.h b/engine/common/imagelib/img_ktx2.h new file mode 100644 index 00000000..e1183315 --- /dev/null +++ b/engine/common/imagelib/img_ktx2.h @@ -0,0 +1,79 @@ +/* +img_ktx2.h - ktx2 format reference +Copyright (C) 2023 Provod + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ +#ifndef IMG_KTX2_H +#define IMG_KTX2_H + +#include + +#define KTX2_IDENTIFIER_SIZE 12 +#define KTX2_IDENTIFIER "\xABKTX 20\xBB\r\n\x1A\n" + +/* +static const char k_ktx2_identifier[KTX2_IDENTIFIER_SIZE] = +{ + '\xAB', 'K', 'T', 'X', ' ', '2', '0', '\xBB', '\r', '\n', '\x1A', '\n' +}; +*/ + +typedef struct +{ + uint32_t vkFormat; + uint32_t typeSize; + uint32_t pixelWidth; + uint32_t pixelHeight; + uint32_t pixelDepth; + uint32_t layerCount; + uint32_t faceCount; + uint32_t levelCount; + uint32_t supercompressionScheme; +} ktx2_header_t; + +typedef struct +{ + uint32_t dfdByteOffset; + uint32_t dfdByteLength; + uint32_t kvdByteOffset; + uint32_t kvdByteLength; + uint64_t sgdByteOffset; + uint64_t sgdByteLength; +} ktx2_index_t; + +typedef struct +{ + uint64_t byteOffset; + uint64_t byteLength; + uint64_t uncompressedByteLength; +} ktx2_level_t; + +#define KTX2_LEVELS_OFFSET ( KTX2_IDENTIFIER_SIZE + sizeof( ktx2_header_t ) + sizeof( ktx2_index_t )) + +#define KTX2_MINIMAL_HEADER_SIZE ( KTX2_LEVELS_OFFSET + sizeof( ktx2_level_t )) + +// These have the same values as enum VkFormat in vulkan_core.h +// There are hundreds of formats which can be contained in KTX2. +// Below are listed the ones which are supported here. This list can be extended. +typedef enum +{ + KTX2_FORMAT_BC4_UNORM_BLOCK = 139, + KTX2_FORMAT_BC4_SNORM_BLOCK = 140, + KTX2_FORMAT_BC5_UNORM_BLOCK = 141, + KTX2_FORMAT_BC5_SNORM_BLOCK = 142, + KTX2_FORMAT_BC6H_UFLOAT_BLOCK = 143, + KTX2_FORMAT_BC6H_SFLOAT_BLOCK = 144, + KTX2_FORMAT_BC7_UNORM_BLOCK = 145, + KTX2_FORMAT_BC7_SRGB_BLOCK = 146, +} ktx2_format_t; + +#endif // IMG_KTX2_H diff --git a/engine/common/imagelib/img_utils.c b/engine/common/imagelib/img_utils.c index 094f6345..a6cd189e 100644 --- a/engine/common/imagelib/img_utils.c +++ b/engine/common/imagelib/img_utils.c @@ -105,6 +105,7 @@ static const loadpixformat_t load_game[] = { "%s%s.%s", "lmp", Image_LoadLMP, IL_HINT_NO }, // hl menu images (cached.wad etc) { "%s%s.%s", "fnt", Image_LoadFNT, IL_HINT_HL }, // hl console font (fonts.wad etc) { "%s%s.%s", "pal", Image_LoadPAL, IL_HINT_NO }, // install studio\sprite palette +{ "%s%s.%s", "ktx2", Image_LoadKTX2, IL_HINT_NO }, // ktx2 for world and studio models { NULL, NULL, NULL, IL_HINT_NO } }; @@ -1446,3 +1447,36 @@ qboolean Image_Process(rgbdata_t **pix, int width, int height, uint flags, float return result; } + +// This codebase has too many copies of this function: +// - ref_gl has one +// - ref_vk has one +// - ref_soft has one +// - many more places probably have one too +// TODO figure out how to make it available for ref_* +size_t Image_ComputeSize( int type, int width, int height, int depth ) +{ + switch( type ) + { + case PF_DXT1: + case PF_BC4_SIGNED: + case PF_BC4_UNSIGNED: + return ((( width + 3 ) / 4 ) * (( height + 3 ) / 4 ) * depth * 8 ); + case PF_DXT3: + case PF_DXT5: + case PF_ATI2: + case PF_BC5_UNSIGNED: + case PF_BC5_SIGNED: + case PF_BC6H_SIGNED: + case PF_BC6H_UNSIGNED: + case PF_BC7_UNORM: + case PF_BC7_SRGB: return ((( width + 3 ) / 4 ) * (( height + 3 ) / 4 ) * depth * 16 ); + case PF_LUMINANCE: return ( width * height * depth ); + case PF_BGR_24: + case PF_RGB_24: return ( width * height * depth * 3 ); + case PF_BGRA_32: + case PF_RGBA_32: return ( width * height * depth * 4 ); + } + + return 0; +} diff --git a/ref/gl/gl_image.c b/ref/gl/gl_image.c index a6e383c3..f0ff212c 100644 --- a/ref/gl/gl_image.c +++ b/ref/gl/gl_image.c @@ -388,7 +388,8 @@ static size_t GL_CalcImageSize( pixformat_t format, int width, int height, int d case PF_DXT5: case PF_BC6H_SIGNED: case PF_BC6H_UNSIGNED: - case PF_BC7: + case PF_BC7_UNORM: + case PF_BC7_SRGB: case PF_ATI2: size = (((width + 3) >> 2) * ((height + 3) >> 2) * 16) * depth; break; @@ -694,7 +695,7 @@ static void GL_SetTextureFormat( gl_texture_t *tex, pixformat_t format, int chan Assert( tex != NULL ); - if( ImageDXT( format )) + if( ImageCompressed( format )) { switch( format ) { @@ -703,7 +704,8 @@ static void GL_SetTextureFormat( gl_texture_t *tex, pixformat_t format, int chan case PF_DXT5: tex->format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; case PF_BC6H_SIGNED: tex->format = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB; break; case PF_BC6H_UNSIGNED: tex->format = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB; break; - case PF_BC7: tex->format = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; break; + case PF_BC7_SRGB: + case PF_BC7_UNORM: tex->format = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; break; case PF_ATI2: if( glConfig.hardware_type == GLHW_RADEON ) tex->format = GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI; @@ -1094,7 +1096,7 @@ static void GL_TextureImageRAW( gl_texture_t *tex, GLint side, GLint level, GLin } } -static void GL_TextureImageDXT( gl_texture_t *tex, GLint side, GLint level, GLint width, GLint height, GLint depth, size_t size, const void *data ) +static void GL_TextureImageCompressed( gl_texture_t *tex, GLint side, GLint level, GLint width, GLint height, GLint depth, size_t size, const void *data ) { GLuint cubeTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB; qboolean subImage = FBitSet( tex->flags, TF_IMG_UPLOADED ); @@ -1176,7 +1178,7 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) return false; } - if( pic->type == PF_BC6H_SIGNED || pic->type == PF_BC6H_UNSIGNED || pic->type == PF_BC7 ) + if( pic->type == PF_BC6H_SIGNED || pic->type == PF_BC6H_UNSIGNED || pic->type == PF_BC7_UNORM || pic->type == PF_BC7_SRGB ) { if( !GL_Support( GL_ARB_TEXTURE_COMPRESSION_BPTC )) { @@ -1217,7 +1219,7 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) if( buf != NULL && buf >= bufend ) gEngfuncs.Host_Error( "GL_UploadTexture: %s image buffer overflow\n", tex->name ); - if( ImageDXT( pic->type )) + if( ImageCompressed( pic->type )) { for( j = 0; j < Q_max( 1, pic->numMips ); j++ ) { @@ -1225,7 +1227,7 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) height = Q_max( 1, ( tex->height >> j )); texsize = GL_CalcTextureSize( tex->format, width, height, tex->depth ); size = GL_CalcImageSize( pic->type, width, height, tex->depth ); - GL_TextureImageDXT( tex, i, j, width, height, tex->depth, size, buf ); + GL_TextureImageCompressed( tex, i, j, width, height, tex->depth, size, buf ); tex->size += texsize; buf += size; // move pointer tex->numMips++; @@ -1259,7 +1261,7 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic ) data = GL_ResampleTexture( buf, pic->width, pic->height, tex->width, tex->height, normalMap ); else data = buf; - if( !ImageDXT( pic->type ) && !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( pic->flags, IMAGE_ONEBIT_ALPHA )) + if( !ImageCompressed( pic->type ) && !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( pic->flags, IMAGE_ONEBIT_ALPHA )) data = GL_ApplyFilter( data, tex->width, tex->height ); // mips will be auto-generated if desired @@ -1307,7 +1309,7 @@ static void GL_ProcessImage( gl_texture_t *tex, rgbdata_t *pic ) tex->encode = pic->encode; // share encode method - if( ImageDXT( pic->type )) + if( ImageCompressed( pic->type )) { if( !pic->numMips ) tex->flags |= TF_NOMIPMAP; // disable mipmapping by user request @@ -1922,7 +1924,7 @@ void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor ) return; } - if( ImageDXT( image->original->type )) + if( ImageCompressed( image->original->type )) { gEngfuncs.Con_Printf( S_ERROR "GL_ProcessTexture: can't process compressed texture %s\n", image->name ); return; diff --git a/ref/soft/r_image.c b/ref/soft/r_image.c index 933e8cf7..7d58787b 100644 --- a/ref/soft/r_image.c +++ b/ref/soft/r_image.c @@ -557,7 +557,7 @@ static qboolean GL_UploadTexture( image_t *tex, rgbdata_t *pic ) data = GL_ResampleTexture( buf, pic->width, pic->height, tex->width, tex->height, normalMap ); else data = buf; - //if( !ImageDXT( pic->type ) && !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( pic->flags, IMAGE_ONEBIT_ALPHA )) + //if( !ImageCompressed( pic->type ) && !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( pic->flags, IMAGE_ONEBIT_ALPHA )) // data = GL_ApplyFilter( data, tex->width, tex->height ); // mips will be auto-generated if desired @@ -663,7 +663,7 @@ static qboolean GL_UploadTexture( image_t *tex, rgbdata_t *pic ) if( buf != NULL && buf >= bufend ) gEngfuncs.Host_Error( "GL_UploadTexture: %s image buffer overflow\n", tex->name ); - if( ImageDXT( pic->type )) + if( ImageCompressed( pic->type )) { for( j = 0; j < Q_max( 1, pic->numMips ); j++ ) { @@ -671,7 +671,7 @@ static qboolean GL_UploadTexture( image_t *tex, rgbdata_t *pic ) height = Q_max( 1, ( tex->height >> j )); texsize = GL_CalcTextureSize( tex->format, width, height, tex->depth ); size = GL_CalcImageSize( pic->type, width, height, tex->depth ); - GL_TextureImageDXT( tex, i, j, width, height, tex->depth, size, buf ); + GL_TextureImageCompressed( tex, i, j, width, height, tex->depth, size, buf ); tex->size += texsize; buf += size; // move pointer tex->numMips++; @@ -705,7 +705,7 @@ static qboolean GL_UploadTexture( image_t *tex, rgbdata_t *pic ) data = GL_ResampleTexture( buf, pic->width, pic->height, tex->width, tex->height, normalMap ); else data = buf; - if( !ImageDXT( pic->type ) && !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( pic->flags, IMAGE_ONEBIT_ALPHA )) + if( !ImageCompressed( pic->type ) && !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( pic->flags, IMAGE_ONEBIT_ALPHA )) data = GL_ApplyFilter( data, tex->width, tex->height ); // mips will be auto-generated if desired @@ -753,7 +753,7 @@ static void GL_ProcessImage( image_t *tex, rgbdata_t *pic ) if( tex->flags & TF_FORCE_COLOR ) pic->flags |= IMAGE_HAS_COLOR; if( pic->flags & IMAGE_HAS_ALPHA ) tex->flags |= TF_HAS_ALPHA; - if( ImageDXT( pic->type )) + if( ImageCompressed( pic->type )) { if( !pic->numMips ) tex->flags |= TF_NOMIPMAP; // disable mipmapping by user request @@ -1178,7 +1178,7 @@ void GAME_EXPORT GL_ProcessTexture( int texnum, float gamma, int topColor, int b return; } - if( ImageDXT( image->original->type )) + if( ImageCompressed( image->original->type )) { gEngfuncs.Con_Printf( S_ERROR "GL_ProcessTexture: can't process compressed texture %s\n", image->name ); return;