From bf9ae9688aa757eea3accb1ac28dc077b472a3a1 Mon Sep 17 00:00:00 2001 From: Salvador Cipolla Date: Wed, 17 Sep 2025 20:17:36 -0300 Subject: [PATCH 01/10] Initial KTX1/ETC2 support --- code/bmpman/bm_internal.h | 19 +- code/bmpman/bmpman.cpp | 135 +++++++++-- code/bmpman/bmpman.h | 21 +- code/cfile/cfile.cpp | 18 +- code/graphics/opengl/gropengltexture.cpp | 53 ++++- code/ktxutils/ktxutils.cpp | 279 +++++++++++++++++++++++ code/ktxutils/ktxutils.h | 81 +++++++ code/source_groups.cmake | 6 + 8 files changed, 571 insertions(+), 41 deletions(-) create mode 100644 code/ktxutils/ktxutils.cpp create mode 100644 code/ktxutils/ktxutils.h diff --git a/code/bmpman/bm_internal.h b/code/bmpman/bm_internal.h index 90e338d230c..b5a0aa82605 100644 --- a/code/bmpman/bm_internal.h +++ b/code/bmpman/bm_internal.h @@ -70,7 +70,7 @@ struct bitmap_entry { // Stuff to keep track of usage ubyte preloaded; //!< If set, then this was loaded from the lst file int preload_count; //!< how many times this gets used in game, for unlocking - ushort used_flags; //!< What flags it was accessed thru + uint used_flags; //!< What flags it was accessed thru int load_count; bitmap bm; //!< Bitmap info @@ -93,14 +93,15 @@ struct bitmap_slot { }; // image specific lock functions -void bm_lock_ani( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags ); -void bm_lock_dds( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags ); -void bm_lock_png( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags ); -void bm_lock_apng( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags ); -void bm_lock_jpg( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags ); -void bm_lock_pcx( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags ); -void bm_lock_tga( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags ); -void bm_lock_user( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags, bool convert = true ); +void bm_lock_ani( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags ); +void bm_lock_dds( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags ); +void bm_lock_png( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags ); +void bm_lock_apng( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags ); +void bm_lock_jpg( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags ); +void bm_lock_pcx( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags ); +void bm_lock_tga( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags ); +void bm_lock_user( int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags, bool convert = true ); +void bm_lock_ktx1(int handle, bitmap_slot* bs, bitmap* bmp, int bpp, uint flags); const size_t BM_BLOCK_SIZE = 4096; diff --git a/code/bmpman/bmpman.cpp b/code/bmpman/bmpman.cpp index b5a3cde240f..b1eab603525 100644 --- a/code/bmpman/bmpman.cpp +++ b/code/bmpman/bmpman.cpp @@ -32,6 +32,7 @@ #include "tgautils/tgautils.h" #include "tracing/Monitor.h" #include "tracing/tracing.h" +#include "ktxutils/ktxutils.h" #include #include @@ -59,8 +60,8 @@ size_t bm_texture_ram = 0; int Bm_paging = 0; // Extension type lists -const BM_TYPE bm_type_list[] = { BM_TYPE_DDS, BM_TYPE_TGA, BM_TYPE_PNG, BM_TYPE_JPG, BM_TYPE_PCX }; -const char *bm_ext_list[] = { ".dds", ".tga", ".png", ".jpg", ".pcx" }; +const BM_TYPE bm_type_list[] = { BM_TYPE_DDS, BM_TYPE_TGA, BM_TYPE_PNG, BM_TYPE_JPG, BM_TYPE_PCX, BM_TYPE_KTX }; +const char* bm_ext_list[] = { ".dds", ".tga", ".png", ".jpg", ".pcx", ".ktx" }; const int BM_NUM_TYPES = sizeof(bm_type_list) / sizeof(bm_type_list[0]); const BM_TYPE bm_ani_type_list[] = { BM_TYPE_EFF, BM_TYPE_ANI, BM_TYPE_PNG }; @@ -205,7 +206,7 @@ void clear_bm_lookup_cache() { /** * Converts the bitmap referenced by bmp to the type specified by flags */ -static void bm_convert_format(bitmap *bmp, ushort flags); +static void bm_convert_format(bitmap *bmp, uint flags); /** * Frees a bitmap's data if it can @@ -639,7 +640,7 @@ int bm_create_3d(int bpp, int w, int h, int d, void* data) { return n; } -void bm_convert_format(bitmap *bmp, ushort flags) { +void bm_convert_format(bitmap *bmp, uint flags) { int idx; // no transparency for 24 bpp images @@ -901,7 +902,7 @@ void bm_get_frame_usage(int *ntotal, int *nnew) { #endif } -int bm_get_info(int handle, int *w, int * h, ushort* flags, int *nframes, int *fps) { +int bm_get_info(int handle, int *w, int * h, uint* flags, int *nframes, int *fps) { bitmap * bmp; if (!bm_inited) return -1; @@ -1055,6 +1056,18 @@ int bm_is_compressed(int num) { case BM_TYPE_CUBEMAP_DXT5: return DDS_CUBEMAP_DXT5; + case BM_TYPE_ETC2_RGB: + return KTX_ETC2_RGB; + + case BM_TYPE_ETC2_RGBA_EAC: + return KTX_ETC2_RGBA_EAC; + + case BM_TYPE_EAC_R11: + return KTX_EAC_R11; + + case BM_TYPE_EAC_RG11: + return KTX_EAC_RG11; + default: return 0; } @@ -1148,6 +1161,16 @@ static int bm_load_info(BM_TYPE type, const char *filename, CFILE *img_cfp, int return -1; } } + // its a KTX file + else if (type == BM_TYPE_KTX) { + int ktx_ct; + int ktx_error = ktx1_read_header(filename, img_cfp, w, h, bpp, &ktx_ct, mm_lvl, size); + if (ktx_error != KTX1_ERROR_NONE) { + mprintf(("ktx: could not open '%s'\n", filename)); + return -1; + } + *c_type = (BM_TYPE)ktx_ct; + } // if its a tga file else if (type == BM_TYPE_TGA) { int tga_error = targa_read_header(filename, img_cfp, w, h, bpp, NULL); @@ -1361,6 +1384,8 @@ bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int c_type = BM_TYPE_JPG; } else if (!stricmp(NOX("pcx"), ext)) { c_type = BM_TYPE_PCX; + } else if (!stricmp(NOX("ktx"), ext)) { + c_type = BM_TYPE_KTX; } else { mprintf(("BMPMAN: Unknown file type in EFF parse!\n")); return false; @@ -1390,7 +1415,7 @@ bool bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int /** * Lock an image files data into memory */ -static int bm_load_image_data(int handle, int bpp, ushort flags, bool nodebug) +static int bm_load_image_data(int handle, int bpp, uint flags, bool nodebug) { BM_TYPE c_type = BM_TYPE_NONE; int true_bpp; @@ -1482,6 +1507,10 @@ static int bm_load_image_data(int handle, int bpp, ushort flags, bool nodebug) bm_lock_user(handle, bs, bmp, true_bpp, flags, false); break; + case BM_TYPE_KTX: + bm_lock_ktx1(handle, bs, bmp, true_bpp, flags); + break; + default: Warning(LOCATION, "Unsupported type in bm_lock -- %d\n", c_type); return -1; @@ -1941,7 +1970,7 @@ int bm_load_sub_slow(const char *real_filename, const int num_ext, const char ** return -1; } -bitmap * bm_lock(int handle, int bpp, ushort flags, bool nodebug) { +bitmap * bm_lock(int handle, int bpp, uint flags, bool nodebug) { bitmap *bmp; Assertion(bm_inited, "bmpman must be initialized before this function can be called!"); @@ -2038,7 +2067,7 @@ bitmap * bm_lock(int handle, int bpp, ushort flags, bool nodebug) { return bmp; } -void bm_lock_ani(int /*handle*/, bitmap_slot *bs, bitmap* /*bmp*/, int bpp, ushort flags) { +void bm_lock_ani(int /*handle*/, bitmap_slot *bs, bitmap* /*bmp*/, int bpp, uint flags) { anim *the_anim; anim_instance *the_anim_instance; bitmap *bm; @@ -2164,7 +2193,7 @@ void bm_lock_ani(int /*handle*/, bitmap_slot *bs, bitmap* /*bmp*/, int bpp, usho } -void bm_lock_apng(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, ushort /*flags*/) { +void bm_lock_apng(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, uint /*flags*/) { auto be = &bs->entry; int first_frame = be->info.ani.first_frame; auto first_entry = bm_get_entry(first_frame); @@ -2214,7 +2243,7 @@ void bm_lock_apng(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, ushort } -void bm_lock_dds(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, ushort /*flags*/) { +void bm_lock_dds(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, uint /*flags*/) { ubyte *data = NULL; int error; ubyte dds_bpp = 0; @@ -2278,7 +2307,7 @@ void bm_lock_dds(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, ushort / #endif } -void bm_lock_jpg(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort /*flags*/) { +void bm_lock_jpg(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint /*flags*/) { ubyte *data = NULL; int d_size = 0; int jpg_error = JPEG_ERROR_INVALID; @@ -2325,7 +2354,7 @@ void bm_lock_jpg(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort /*fla #endif } -void bm_lock_pcx(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags) { +void bm_lock_pcx(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags) { ubyte *data; int pcx_error; char filename[MAX_FILENAME_LEN]; @@ -2370,7 +2399,7 @@ void bm_lock_pcx(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags bm_convert_format(bmp, flags); } -void bm_lock_png(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, ushort /*flags*/) { +void bm_lock_png(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, uint /*flags*/) { ubyte *data = NULL; //assume 32 bit - libpng should expand everything int d_size; @@ -2415,7 +2444,7 @@ void bm_lock_png(int handle, bitmap_slot *bs, bitmap *bmp, int /*bpp*/, ushort / #endif } -void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags) { +void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags) { ubyte *data = NULL; int byte_size; char filename[MAX_FILENAME_LEN]; @@ -2474,7 +2503,7 @@ void bm_lock_tga(int handle, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags bm_convert_format(bmp, flags); } -void bm_lock_user(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, ushort flags, bool convert) { +void bm_lock_user(int /*handle*/, bitmap_slot *bs, bitmap *bmp, int bpp, uint flags, bool convert) { auto be = &bs->entry; // Unload any existing data @@ -2767,6 +2796,22 @@ void bm_page_in_texture(int bitmapnum, int nframes) { frame_entry->used_flags = BMP_TEX_CUBEMAP; continue; + case BM_TYPE_ETC2_RGB: + frame_entry->used_flags = BMP_TEX_ETC2_RGB; + continue; + + case BM_TYPE_ETC2_RGBA_EAC: + frame_entry->used_flags = BMP_TEX_ETC2_RGBA_EAC; + continue; + + case BM_TYPE_EAC_R11: + frame_entry->used_flags = BMP_TEX_EAC_R11; + continue; + + case BM_TYPE_EAC_RG11: + frame_entry->used_flags = BMP_TEX_EAC_RG11; + continue; + default: continue; } @@ -2812,6 +2857,22 @@ void bm_page_in_xparent_texture(int bitmapnum, int nframes) { entry->used_flags = BMP_TEX_CUBEMAP; continue; + case BM_TYPE_ETC2_RGB: + entry->used_flags = BMP_TEX_ETC2_RGB; + continue; + + case BM_TYPE_ETC2_RGBA_EAC: + entry->used_flags = BMP_TEX_ETC2_RGBA_EAC; + continue; + + case BM_TYPE_EAC_R11: + entry->used_flags = BMP_TEX_EAC_R11; + continue; + + case BM_TYPE_EAC_RG11: + entry->used_flags = BMP_TEX_EAC_RG11; + continue; + default: continue; } @@ -3432,3 +3493,47 @@ SDL_Surface* bm_to_sdl_surface(int handle) { return bitmapSurface; } + +// copied bm_lock_dds and adjusted for ktx. missing BIG_ENDIAN +void bm_lock_ktx1(int handle, bitmap_slot* bs, bitmap* bmp, int bpp, uint flags) +{ + (void)bpp; + (void)flags; + ubyte* data = nullptr; + ubyte ktx_bpp = 0; + int ktx_error = KTX1_ERROR_NONE; + char filename[MAX_FILENAME_LEN]; + + auto be = &bs->entry; + + bm_free_data(bs); + + Assert(be->mem_taken > 0); + Assert(&be->bm == bmp); + + data = (ubyte*)bm_malloc(handle, be->mem_taken); + if (!data) + return; + memset(data, 0, be->mem_taken); + + // make sure we are using the correct filename in the case of an EFF. + // this will populate filename[] whether it's EFF or not + EFF_FILENAME_CHECK; + + ktx_error = ktx1_read_bitmap(filename, data, &ktx_bpp, be->dir_type); + + if (ktx_error != KTX1_ERROR_NONE) + { + mprintf(("KTX: read_bitmap error=%d file='%s'\n", ktx_error, filename)); + bm_free_data(bs); + return; + } + + bmp->bpp = ktx_bpp; + bmp->data = (ptr_u)data; + bmp->flags = 0; + +#ifdef BMPMAN_NDEBUG + Assert(be->data_size > 0); +#endif +} \ No newline at end of file diff --git a/code/bmpman/bmpman.h b/code/bmpman/bmpman.h index 01a4f1b40d5..09c98816069 100644 --- a/code/bmpman/bmpman.h +++ b/code/bmpman/bmpman.h @@ -34,6 +34,7 @@ // Flag positions for bitmap.flags // ***** NOTE: bitmap.flags is an 8-bit value, no more BMP_TEX_* flags can be added unless the type is changed!! ****** +// Update: type changed to 16-bit #define BMP_AABITMAP (1<<0) //!< antialiased bitmap #define BMP_TEX_XPARENT (1<<1) //!< transparent texture #define BMP_TEX_OTHER (1<<2) //!< so we can identify all "normal" textures @@ -43,9 +44,14 @@ #define BMP_TEX_BC7 (1<<6) //!< BC7 compressed 8r8g8b8a (32bit) #define BMP_TEX_CUBEMAP (1<<7) //!< a texture made for cubic environment map #define BMP_MASK_BITMAP (1<<8) //!< a bitmap that will be used for masking mouse interaction. Typically not used in render operations +#define BMP_TEX_ETC2_RGB (1 << 9) +#define BMP_TEX_ETC2_RGBA_EAC (1 << 10) +#define BMP_TEX_EAC_R11 (1 << 11) +#define BMP_TEX_EAC_RG11 (1 << 12) // Combined flags -#define BMP_TEX_COMP ( BMP_TEX_DXT1 | BMP_TEX_DXT3 | BMP_TEX_DXT5 | BMP_TEX_BC7 ) //!< Compressed textures +#define BMP_TEX_COMP ( BMP_TEX_DXT1 | BMP_TEX_DXT3 | BMP_TEX_DXT5 | BMP_TEX_BC7 | BMP_TEX_ETC2_RGB |\ + BMP_TEX_ETC2_RGBA_EAC | BMP_TEX_EAC_R11 | BMP_TEX_EAC_RG11 ) //!< Compressed textures #define BMP_TEX_NONCOMP ( BMP_TEX_XPARENT | BMP_TEX_OTHER ) //!< Non-compressed textures #define BMP_TEX_ANY ( BMP_TEX_COMP | BMP_TEX_NONCOMP ) //!< Any texture @@ -81,7 +87,12 @@ enum BM_TYPE BM_TYPE_CUBEMAP_DXT3, //!< 32-bit cubemap (compressed cubemap surface) BM_TYPE_CUBEMAP_DXT5, //!< 32-bit cubemap (compressed cubemap surface) - BM_TYPE_3D //!< 3D in-memory + BM_TYPE_3D, //!< 3D in-memory + BM_TYPE_KTX, //!< generic identifier for KTX + BM_TYPE_ETC2_RGB, //!< 24 bit without alpha + BM_TYPE_ETC2_RGBA_EAC, //!< 32 bit with alpha + BM_TYPE_EAC_R11, //!< BC4 equivalent + BM_TYPE_EAC_RG11 //!< BC5 equivalent }; /** @@ -96,7 +107,7 @@ struct bitmap short rowsize; //!< What you need to add to go to next row int bpp; //!< Requested bitdepth of each pixel. ( 7, 8, 15, 16, 24, 32) int true_bpp; //!< The image's actual bitdepth - ushort flags; //!< Various texture type flags. @see BMPMAN_CONSTANTS + uint flags; //!< Various texture type flags. @see BMPMAN_CONSTANTS ptr_u data; //!< Pointer to data, or maybe offset into VRAM. ubyte *palette; /**< @brief Pointer to this bitmap's palette (if it has one). * @details If BMP_NO_PALETTE_MAP flag is cleared, this palette just points to the screen palette. (gr_palette) @@ -344,7 +355,7 @@ int bm_load_either(const char *filename, int *nframes = NULL, int *fps = NULL, i * @returns A pointer to the bitmap that's valid until bm_unlock is called if successful, or * @returns NULL if unsuccessful */ -bitmap* bm_lock(int handle, int bpp, ushort flags, bool nodebug = false); +bitmap* bm_lock(int handle, int bpp, uint flags, bool nodebug = false); /** * @brief Returns the image type of the given bitmap handle @@ -387,7 +398,7 @@ int bm_is_valid(int handle); * @returns The handle to the first frame on success, or * @returns -1 on failure */ -int bm_get_info(int handle, int *w = nullptr, int * h = nullptr, ushort* flags = nullptr, int *nframes = nullptr, int *fps = nullptr); +int bm_get_info(int handle, int *w = nullptr, int * h = nullptr, uint* flags = nullptr, int *nframes = nullptr, int *fps = nullptr); /** * @brief Gets 3D info on the bitmap indexed by handle. diff --git a/code/cfile/cfile.cpp b/code/cfile/cfile.cpp index 0fd43a137f5..7f13c7eb69d 100644 --- a/code/cfile/cfile.cpp +++ b/code/cfile/cfile.cpp @@ -52,7 +52,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = { // Root must be index 1!! { CF_TYPE_ROOT, "", ".mve .ogg", CF_TYPE_ROOT }, { CF_TYPE_DATA, "data", ".cfg .txt", CF_TYPE_ROOT }, - { CF_TYPE_MAPS, "data" DIR_SEPARATOR_STR "maps", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA }, + { CF_TYPE_MAPS, "data" DIR_SEPARATOR_STR "maps", ".pcx .ani .eff .tga .jpg .png .dds .ktx", CF_TYPE_DATA }, { CF_TYPE_TEXT, "data" DIR_SEPARATOR_STR "text", ".txt .net", CF_TYPE_DATA }, { CF_TYPE_MODELS, "data" DIR_SEPARATOR_STR "models", ".pof", CF_TYPE_DATA }, { CF_TYPE_TABLES, "data" DIR_SEPARATOR_STR "tables", ".tbl .tbm .lua", CF_TYPE_DATA }, @@ -66,23 +66,23 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = { { CF_TYPE_VOICE_TRAINING, "data" DIR_SEPARATOR_STR "voice" DIR_SEPARATOR_STR "training", ".wav .ogg", CF_TYPE_VOICE }, { CF_TYPE_MUSIC, "data" DIR_SEPARATOR_STR "music", ".wav .ogg", CF_TYPE_DATA }, { CF_TYPE_MOVIES, "data" DIR_SEPARATOR_STR "movies", ".mve .msb .ogg .mp4 .srt .webm .png",CF_TYPE_DATA }, - { CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg .rml .rcss", CF_TYPE_DATA }, + { CF_TYPE_INTERFACE, "data" DIR_SEPARATOR_STR "interface", ".pcx .ani .dds .tga .eff .png .jpg .rml .rcss .ktx", CF_TYPE_DATA }, { CF_TYPE_FONT, "data" DIR_SEPARATOR_STR "fonts", ".vf .ttf .otf", CF_TYPE_DATA }, - { CF_TYPE_EFFECTS, "data" DIR_SEPARATOR_STR "effects", ".ani .eff .pcx .neb .tga .jpg .png .dds .sdr", CF_TYPE_DATA }, - { CF_TYPE_HUD, "data" DIR_SEPARATOR_STR "hud", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA }, + { CF_TYPE_EFFECTS, "data" DIR_SEPARATOR_STR "effects", ".ani .eff .pcx .neb .tga .jpg .png .dds .sdr .ktx", CF_TYPE_DATA }, + { CF_TYPE_HUD, "data" DIR_SEPARATOR_STR "hud", ".pcx .ani .eff .tga .jpg .png .dds .ktx", CF_TYPE_DATA }, { CF_TYPE_PLAYERS, "data" DIR_SEPARATOR_STR "players", ".hcf", /* DON'T add pilot files here!! */ CF_TYPE_DATA }, - { CF_TYPE_PLAYER_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "images", ".pcx .png .dds", CF_TYPE_PLAYERS }, - { CF_TYPE_SQUAD_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "squads", ".pcx .png .dds", CF_TYPE_PLAYERS }, + { CF_TYPE_PLAYER_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "images", ".pcx .png .dds .ktx", CF_TYPE_PLAYERS }, + { CF_TYPE_SQUAD_IMAGES, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "squads", ".pcx .png .dds .ktx", CF_TYPE_PLAYERS }, { CF_TYPE_SINGLE_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "single", ".pl2 .cs2 .plr .csg .css .json", CF_TYPE_PLAYERS }, { CF_TYPE_MULTI_PLAYERS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "multi", ".plr .json", CF_TYPE_PLAYERS }, { CF_TYPE_PLAYER_BINDS, "data" DIR_SEPARATOR_STR "players" DIR_SEPARATOR_STR "presets", ".json", CF_TYPE_PLAYERS }, { CF_TYPE_CACHE, "data" DIR_SEPARATOR_STR "cache", ".clr .tmp .bx", CF_TYPE_DATA }, //clr=cached color - { CF_TYPE_MULTI_CACHE, "data" DIR_SEPARATOR_STR "multidata", ".pcx .png .jpg .dds .fs2 .txt", CF_TYPE_DATA }, + { CF_TYPE_MULTI_CACHE, "data" DIR_SEPARATOR_STR "multidata", ".pcx .png .jpg .dds .fs2 .txt .ktx", CF_TYPE_DATA }, { CF_TYPE_MISSIONS, "data" DIR_SEPARATOR_STR "missions", ".fs2 .fc2 .ntl .ssv", CF_TYPE_DATA }, { CF_TYPE_CONFIG, "data" DIR_SEPARATOR_STR "config", ".cfg .tbl .tbm .xml .csv", CF_TYPE_DATA }, { CF_TYPE_DEMOS, "data" DIR_SEPARATOR_STR "demos", ".fsd", CF_TYPE_DATA }, - { CF_TYPE_CBANIMS, "data" DIR_SEPARATOR_STR "cbanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA }, - { CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA }, + { CF_TYPE_CBANIMS, "data" DIR_SEPARATOR_STR "cbanims", ".pcx .ani .eff .tga .jpg .png .dds .ktx", CF_TYPE_DATA }, + { CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds .ktx", CF_TYPE_DATA }, { CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc .fnl", CF_TYPE_DATA }, { CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA }, { CF_TYPE_FREDDOCS, "data" DIR_SEPARATOR_STR "freddocs", ".html", CF_TYPE_DATA } diff --git a/code/graphics/opengl/gropengltexture.cpp b/code/graphics/opengl/gropengltexture.cpp index 76f540f78c8..31b571bc98c 100644 --- a/code/graphics/opengl/gropengltexture.cpp +++ b/code/graphics/opengl/gropengltexture.cpp @@ -24,7 +24,6 @@ #include "math/vecmat.h" #include "options/Option.h" #include "osapi/osregistry.h" - matrix4 GL_texture_matrix; int GL_texture_ram = 0; @@ -416,7 +415,8 @@ static int opengl_texture_set_level(int bitmap_handle, int bitmap_type, int bmap // check for compressed image types auto block_size = 0; - switch (bm_is_compressed(bitmap_handle)) { + auto bm_handle = bm_is_compressed(bitmap_handle); + switch (bm_handle) { case DDS_DXT1: case DDS_CUBEMAP_DXT1: intFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; @@ -439,6 +439,20 @@ static int opengl_texture_set_level(int bitmap_handle, int bitmap_type, int bmap intFormat = GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; block_size = 16; break; + + case KTX_ETC2_RGB: + case KTX_ETC2_RGBA_EAC: + case KTX_EAC_R11: + case KTX_EAC_RG11: + case KTX_ETC2_SRGB: + case KTX_ETC2_SRGBA_EAC: + case KTX_ETC2_RGB_A1: + case KTX_ETC2_SRGB_A1: + case KTX_EAC_R11_SNORM: + case KTX_EAC_RG11_SNORM: + intFormat = ktx_map_ktx_type_to_gl_internal(bm_handle); + block_size = ktx_etc_block_bytes(intFormat); + break; } if (bitmap_type == TCACHE_TYPE_CUBEMAP) { @@ -737,7 +751,8 @@ static GLenum opengl_get_internal_format(int handle, int bitmap_type, int bpp) { auto byte_mult = (bpp >> 3); // check for compressed image types - switch ( bm_is_compressed(handle) ) { + auto bm_handle = bm_is_compressed(handle); + switch (bm_handle) { case DDS_DXT1: case DDS_CUBEMAP_DXT1: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT; @@ -754,6 +769,18 @@ static GLenum opengl_get_internal_format(int handle, int bitmap_type, int bpp) { case DDS_BC7: return GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; + case KTX_ETC2_RGB: + case KTX_ETC2_RGBA_EAC: + case KTX_EAC_R11: + case KTX_EAC_RG11: + case KTX_ETC2_SRGB: + case KTX_ETC2_SRGBA_EAC: + case KTX_ETC2_RGB_A1: + case KTX_ETC2_SRGB_A1: + case KTX_EAC_R11_SNORM: + case KTX_EAC_RG11_SNORM: + return ktx_map_ktx_type_to_gl_internal(bm_handle); + default: // Not compressed break; @@ -841,6 +868,26 @@ void opengl_determine_bpp_and_flags(int bitmap_handle, int bitmap_type, ushort& flags |= BMP_TEX_CUBEMAP; break; + case KTX_ETC2_RGB: + bpp = 24; + flags |= BMP_TEX_ETC2_RGB; + break; + + case KTX_ETC2_RGBA_EAC: + bpp = 32; + flags |= BMP_TEX_ETC2_RGBA_EAC; + break; + + case KTX_EAC_R11: + bpp = 8; + flags |= BMP_TEX_EAC_R11; + break; + + case KTX_EAC_RG11: + bpp = 16; + flags |= BMP_TEX_EAC_RG11; + break; + default: Assert( 0 ); break; diff --git a/code/ktxutils/ktxutils.cpp b/code/ktxutils/ktxutils.cpp new file mode 100644 index 00000000000..f16a1b217c0 --- /dev/null +++ b/code/ktxutils/ktxutils.cpp @@ -0,0 +1,279 @@ +#include "ktxutils.h" +#include "bmpman/bmpman.h" +#include "cfile/cfile.h" +#include +//KTX1 Spec definition https://registry.khronos.org/KTX/specs/1.0/ktxspec.v1.html +//ETC2 formats spec https://registry.khronos.org/DataFormat/specs/1.4/dataformat.1.4.inline.html#ETC2 + +static const uint8_t KTX_ID[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' }; + +// copied from ddsutils +static inline int is_power_of_two(int w, int h) +{ + return ((w && !(w & (w - 1))) && (h && !(h & (h - 1)))); +} + +// BPB ETC/EAC +uint32_t ktx_etc_block_bytes(GLenum internal_format) +{ + switch (internal_format) + { + case GL_COMPRESSED_RGB8_ETC2: + case GL_COMPRESSED_SRGB8_ETC2: + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: + case GL_COMPRESSED_R11_EAC: + case GL_COMPRESSED_SIGNED_R11_EAC: + return 8; + + case GL_COMPRESSED_RGBA8_ETC2_EAC: + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: + case GL_COMPRESSED_RG11_EAC: + case GL_COMPRESSED_SIGNED_RG11_EAC: + return 16; + + default: + return 0; + } +} + + +int ktx_map_ktx_type_to_gl_internal(unsigned int ktx_format) +{ + switch (ktx_format) + { + case KTX_ETC2_RGB: + return GL_COMPRESSED_RGB8_ETC2; + case KTX_ETC2_RGBA_EAC: + return GL_COMPRESSED_RGBA8_ETC2_EAC; + case KTX_EAC_R11: + return GL_COMPRESSED_R11_EAC; + case KTX_EAC_RG11: + return GL_COMPRESSED_RG11_EAC; + case KTX_ETC2_SRGB: + return GL_COMPRESSED_SRGB8_ETC2; + case KTX_ETC2_SRGBA_EAC: + return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; + case KTX_ETC2_RGB_A1: + return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; + case KTX_ETC2_SRGB_A1: + return GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2; + case KTX_EAC_R11_SNORM: + return GL_COMPRESSED_SIGNED_R11_EAC; + case KTX_EAC_RG11_SNORM: + return GL_COMPRESSED_SIGNED_RG11_EAC; + + default: return 0; + } +} + +int ktx_map_gl_internal_to_bm(GLenum internal_format) +{ + switch (internal_format) + { + case GL_COMPRESSED_RGB8_ETC2: + case GL_COMPRESSED_SRGB8_ETC2: + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: + return BM_TYPE_ETC2_RGB; + + case GL_COMPRESSED_RGBA8_ETC2_EAC: + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: + return BM_TYPE_ETC2_RGBA_EAC; + + case GL_COMPRESSED_R11_EAC: + case GL_COMPRESSED_SIGNED_R11_EAC: + return BM_TYPE_EAC_R11; + + case GL_COMPRESSED_RG11_EAC: + case GL_COMPRESSED_SIGNED_RG11_EAC: + return BM_TYPE_EAC_RG11; + + default: + return BM_TYPE_NONE; + } +} + +int ktx1_read_header(const char* filename, CFILE* img_cfp, int* w, int* h, int* bpp, int* c_type, int* mip_levels, size_t* total_size) +{ + CFILE* cf; + char real_name[MAX_FILENAME_LEN]; + if (img_cfp == NULL) { + // this better not happen.. ever + Assert(filename != NULL); + + // make sure there is an extension + strcpy_s(real_name, filename); + char* p = strchr(real_name, '.'); + if (p) { + *p = 0; + } + strcat_s(real_name, ".ktx"); + + // try to open the file + cf = cfopen(real_name, "rb"); + + // file not found + if (cf == NULL) + return KTX1_ERROR_INVALID_FILENAME; + } else { + cf = img_cfp; + } + + KTX1_Header hdr{}; + if (cfread(&hdr, 1, sizeof(hdr), cf) != sizeof(hdr)) { + if (!img_cfp) + cfclose(cf); + mprintf(("ktx: read header error, parse header error. File: file='%s'\n", filename)); + return KTX1_ERROR_BAD_HEADER; + } + + if (memcmp(hdr.identifier, KTX_ID, 12) != 0 || hdr.endianness != 0x04030201) { + if (!img_cfp) + cfclose(cf); + mprintf(("ktx: read header error, parse header error. File: file='%s'\n", filename)); + return KTX1_ERROR_BAD_HEADER; + } + + // Only 2D no arrays or cubemaps + if (hdr.pixelHeight == 0 || hdr.pixelWidth == 0 || hdr.numberOfFaces > 1 || hdr.numberOfArrayElements > 0 || + (hdr.pixelDepth > 1)) { + if (!img_cfp) + cfclose(cf); + mprintf(("ktx: read header error, only 2D textures are supported. File: file='%s'\n", filename)); + return KTX1_ERROR_UNSUPPORTED; + } + + const bool isCompressed = (hdr.glType == 0 && hdr.glFormat == 0); + if (!isCompressed) { + //uncompressed + if (!img_cfp) + cfclose(cf); + mprintf(("ktx: read header error, unsupported texture format on file: file='%s'\n", filename)); + return KTX1_ERROR_INVALID_FORMAT; + } + + const uint32_t fmt = hdr.glInternalFormat; + const uint32_t blockBytes = ktx_etc_block_bytes(fmt); + const int bm_ct = ktx_map_gl_internal_to_bm(fmt); + if (blockBytes == 0 || bm_ct == BM_TYPE_NONE) { + if (!img_cfp) + cfclose(cf); + mprintf(("ktx: read header error, unsupported texture format on file: file='%s'\n", filename)); + return KTX1_ERROR_INVALID_FORMAT; + } + + // skip metadata + cfseek(cf, (int)hdr.bytesOfKeyValueData, CF_SEEK_CUR); + + // calculate max size + uint32_t W = hdr.pixelWidth, H = hdr.pixelHeight; + const uint32_t mips = std::max(1u, hdr.numberOfMipmapLevels); + size_t total = 0; + for (uint32_t level = 0; level < mips; ++level) { + uint32_t imageSize = 0; + cfread(&imageSize, 1, sizeof(imageSize), cf); + total += imageSize; + cfseek(cf, (int)imageSize, CF_SEEK_CUR); + uint32_t pad = ((-(int)imageSize) & 3); + if (pad) + cfseek(cf, (int)pad, CF_SEEK_CUR); + + W = std::max(1u, W >> 1); + H = std::max(1u, H >> 1); + } + + if (w) + *w = (int)hdr.pixelWidth; + if (h) + *h = (int)hdr.pixelHeight; + if (c_type) + *c_type = bm_ct; + if (bpp) + { + switch (bm_ct) + { + case BM_TYPE_ETC2_RGB: + *bpp = 24; + break; + case BM_TYPE_ETC2_RGBA_EAC: + *bpp = 32; + break; + case BM_TYPE_EAC_R11: + *bpp = 8; + break; + case BM_TYPE_EAC_RG11: + *bpp = 16; + break; + default: + *bpp = 0; + break; + } + } + if (mip_levels) + *mip_levels = (int)mips; + if (total_size) + *total_size = total; + + if (!img_cfp) + cfclose(cf); + return KTX1_ERROR_NONE; +} + +int ktx1_read_bitmap(const char* filename, ubyte* dst, ubyte* out_bpp, int cf_type) +{ + CFILE* cf; + char real_name[MAX_FILENAME_LEN]; + // this better not happen.. ever + Assert(filename != NULL); + + // make sure there is an extension + strcpy_s(real_name, filename); + char* p = strchr(real_name, '.'); + if (p) { + *p = 0; + } + strcat_s(real_name, ".ktx"); + + // try to open the file + cf = cfopen(real_name, "rb"); + + // file not found + if (cf == NULL) + return KTX1_ERROR_INVALID_FILENAME; + + KTX1_Header hdr{}; + int rc = KTX1_ERROR_NONE; + if (cfread(&hdr, 1, sizeof(hdr), cf) != sizeof(hdr) || memcmp(hdr.identifier, KTX_ID, 12) != 0) + { + rc = KTX1_ERROR_BAD_HEADER; + } + if (hdr.glType != 0 || hdr.glFormat != 0) + { + rc = KTX1_ERROR_INVALID_FORMAT; + } + + if (rc == KTX1_ERROR_NONE) + { + cfseek(cf, (int)hdr.bytesOfKeyValueData, CF_SEEK_CUR); + + const uint32_t mips = std::max(1u, hdr.numberOfMipmapLevels); + size_t offset = 0; + for (uint32_t level = 0; level < mips; ++level) + { + uint32_t image_size = 0; + cfread(&image_size, 1, sizeof(image_size), cf); + cfread(dst + offset, 1, image_size, cf); + offset += image_size; + uint32_t pad = ((-(int)image_size) & 3); // 4 byte padding + if (pad) + cfseek(cf, (int)pad, CF_SEEK_CUR); + } + + if (out_bpp) + *out_bpp = 0; + } + + cfclose(cf); + return rc; +} \ No newline at end of file diff --git a/code/ktxutils/ktxutils.h b/code/ktxutils/ktxutils.h new file mode 100644 index 00000000000..7df91b4103b --- /dev/null +++ b/code/ktxutils/ktxutils.h @@ -0,0 +1,81 @@ +#pragma once +#include "globalincs/pstypes.h" +#include "cfile/cfile.h" +#include + +// ETC2 types +#define KTX_ETC2_RGB 101 +#define KTX_ETC2_RGBA_EAC 102 +#define KTX_EAC_R11 103 +#define KTX_EAC_RG11 104 +#define KTX_ETC2_SRGB 105 +#define KTX_ETC2_SRGBA_EAC 106 +#define KTX_ETC2_RGB_A1 107 +#define KTX_ETC2_SRGB_A1 108 +#define KTX_EAC_R11_SNORM 109 +#define KTX_EAC_RG11_SNORM 110 + +// GLenum definitions, ETC2 is guarranted on ES 3.2, but in desktop GL it is supported from 4.3 +// glad loader is GL 3.2 and these definitions are not there. But these will work if the GPU is GL 4.3 +// https://www.sidefx.com/docs/hdk/glcorearb_8h_source.html +#ifndef GL_COMPRESSED_RGB8_ETC2 +#define GL_COMPRESSED_RGB8_ETC2 0x9274 +#endif +#ifndef GL_COMPRESSED_SRGB8_ETC2 +#define GL_COMPRESSED_SRGB8_ETC2 0x9275 +#endif +#ifndef GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 +#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 +#endif +#ifndef GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 +#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 +#endif +#ifndef GL_COMPRESSED_RGBA8_ETC2_EAC +#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#endif +#ifndef GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC +#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 +#endif +#ifndef GL_COMPRESSED_R11_EAC +#define GL_COMPRESSED_R11_EAC 0x9270 +#endif +#ifndef GL_COMPRESSED_SIGNED_R11_EAC +#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 +#endif +#ifndef GL_COMPRESSED_RG11_EAC +#define GL_COMPRESSED_RG11_EAC 0x9272 +#endif +#ifndef GL_COMPRESSED_SIGNED_RG11_EAC +#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 +#endif + +enum KTX1_Error { + KTX1_ERROR_NONE = 0, + KTX1_ERROR_INVALID_FILENAME, + KTX1_ERROR_BAD_HEADER, + KTX1_ERROR_UNSUPPORTED, + KTX1_ERROR_INVALID_FORMAT +}; + +struct KTX1_Header { + uint8_t identifier[12]; + uint32_t endianness; // 0x04030201 little + uint32_t glType; + uint32_t glTypeSize; + uint32_t glFormat; + uint32_t glInternalFormat; + uint32_t glBaseInternalFormat; + uint32_t pixelWidth, pixelHeight, pixelDepth; + uint32_t numberOfArrayElements; + uint32_t numberOfFaces; + uint32_t numberOfMipmapLevels; + uint32_t bytesOfKeyValueData; +}; + +int ktx1_read_header(const char* filename, CFILE* img_cfp, int* w, int* h, int* bpp, int* c_type, int* mip_levels, size_t* total_size); + +int ktx1_read_bitmap(const char* filename, ubyte* dst, ubyte* out_bpp, int cf_type); + +int ktx_map_ktx_type_to_gl_internal(unsigned int ktx_format); + +uint32_t ktx_etc_block_bytes(GLenum internal_format); \ No newline at end of file diff --git a/code/source_groups.cmake b/code/source_groups.cmake index 09ca8bbb330..fc7baa4ff05 100644 --- a/code/source_groups.cmake +++ b/code/source_groups.cmake @@ -1754,3 +1754,9 @@ add_file_folder("Windows Stubs" windows_stub/config.h windows_stub/stubs.cpp ) + +# ktx utils files +add_file_folder("ktxutils" + ktxutils/ktxutils.cpp + ktxutils/ktxutils.h +) From 8269e79838d598ffbc08c7b3ceae92a51c67a115 Mon Sep 17 00:00:00 2001 From: Salvador Cipolla Date: Wed, 17 Sep 2025 20:38:54 -0300 Subject: [PATCH 02/10] Conditional glad include --- code/ktxutils/ktxutils.cpp | 1 - code/ktxutils/ktxutils.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/code/ktxutils/ktxutils.cpp b/code/ktxutils/ktxutils.cpp index f16a1b217c0..ce3dbb9d462 100644 --- a/code/ktxutils/ktxutils.cpp +++ b/code/ktxutils/ktxutils.cpp @@ -1,7 +1,6 @@ #include "ktxutils.h" #include "bmpman/bmpman.h" #include "cfile/cfile.h" -#include //KTX1 Spec definition https://registry.khronos.org/KTX/specs/1.0/ktxspec.v1.html //ETC2 formats spec https://registry.khronos.org/DataFormat/specs/1.4/dataformat.1.4.inline.html#ETC2 diff --git a/code/ktxutils/ktxutils.h b/code/ktxutils/ktxutils.h index 7df91b4103b..6260cec8199 100644 --- a/code/ktxutils/ktxutils.h +++ b/code/ktxutils/ktxutils.h @@ -1,7 +1,9 @@ #pragma once #include "globalincs/pstypes.h" #include "cfile/cfile.h" +#ifdef WITH_OPENGL #include +#endif // ETC2 types #define KTX_ETC2_RGB 101 From 3fe8a5bac412448403cb177ac8b677e3dff81478 Mon Sep 17 00:00:00 2001 From: Salvador Cipolla Date: Wed, 17 Sep 2025 20:40:24 -0300 Subject: [PATCH 03/10] remove unused function --- code/ktxutils/ktxutils.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/code/ktxutils/ktxutils.cpp b/code/ktxutils/ktxutils.cpp index ce3dbb9d462..08c11217258 100644 --- a/code/ktxutils/ktxutils.cpp +++ b/code/ktxutils/ktxutils.cpp @@ -6,12 +6,6 @@ static const uint8_t KTX_ID[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' }; -// copied from ddsutils -static inline int is_power_of_two(int w, int h) -{ - return ((w && !(w & (w - 1))) && (h && !(h & (h - 1)))); -} - // BPB ETC/EAC uint32_t ktx_etc_block_bytes(GLenum internal_format) { From c3dd23350a2f6175a7270519dccbf36357cc265c Mon Sep 17 00:00:00 2001 From: Salvador Cipolla Date: Wed, 17 Sep 2025 22:55:54 -0300 Subject: [PATCH 04/10] define glenum for non opengl build --- code/ktxutils/ktxutils.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/ktxutils/ktxutils.h b/code/ktxutils/ktxutils.h index 6260cec8199..eaadffa8618 100644 --- a/code/ktxutils/ktxutils.h +++ b/code/ktxutils/ktxutils.h @@ -3,6 +3,8 @@ #include "cfile/cfile.h" #ifdef WITH_OPENGL #include +#else +#define GLenum int #endif // ETC2 types From 760aadd002d83622dcc10446a246d1676e0b368e Mon Sep 17 00:00:00 2001 From: Salvador Cipolla Date: Wed, 17 Sep 2025 23:39:14 -0300 Subject: [PATCH 05/10] remove unused param --- code/bmpman/bmpman.cpp | 2 +- code/ktxutils/ktxutils.cpp | 2 +- code/ktxutils/ktxutils.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/bmpman/bmpman.cpp b/code/bmpman/bmpman.cpp index b1eab603525..16643a0ab16 100644 --- a/code/bmpman/bmpman.cpp +++ b/code/bmpman/bmpman.cpp @@ -3520,7 +3520,7 @@ void bm_lock_ktx1(int handle, bitmap_slot* bs, bitmap* bmp, int bpp, uint flags) // this will populate filename[] whether it's EFF or not EFF_FILENAME_CHECK; - ktx_error = ktx1_read_bitmap(filename, data, &ktx_bpp, be->dir_type); + ktx_error = ktx1_read_bitmap(filename, data, &ktx_bpp); if (ktx_error != KTX1_ERROR_NONE) { diff --git a/code/ktxutils/ktxutils.cpp b/code/ktxutils/ktxutils.cpp index 08c11217258..d92ca0dbe76 100644 --- a/code/ktxutils/ktxutils.cpp +++ b/code/ktxutils/ktxutils.cpp @@ -213,7 +213,7 @@ int ktx1_read_header(const char* filename, CFILE* img_cfp, int* w, int* h, int* return KTX1_ERROR_NONE; } -int ktx1_read_bitmap(const char* filename, ubyte* dst, ubyte* out_bpp, int cf_type) +int ktx1_read_bitmap(const char* filename, ubyte* dst, ubyte* out_bpp) { CFILE* cf; char real_name[MAX_FILENAME_LEN]; diff --git a/code/ktxutils/ktxutils.h b/code/ktxutils/ktxutils.h index eaadffa8618..da9b05e7ce2 100644 --- a/code/ktxutils/ktxutils.h +++ b/code/ktxutils/ktxutils.h @@ -78,7 +78,7 @@ struct KTX1_Header { int ktx1_read_header(const char* filename, CFILE* img_cfp, int* w, int* h, int* bpp, int* c_type, int* mip_levels, size_t* total_size); -int ktx1_read_bitmap(const char* filename, ubyte* dst, ubyte* out_bpp, int cf_type); +int ktx1_read_bitmap(const char* filename, ubyte* dst, ubyte* out_bpp); int ktx_map_ktx_type_to_gl_internal(unsigned int ktx_format); From 1019f6343c9fa60f552a9443946934f23abb4c1c Mon Sep 17 00:00:00 2001 From: Salvador Cipolla Date: Thu, 18 Sep 2025 00:15:16 -0300 Subject: [PATCH 06/10] fix qtbuild --- qtfred/src/ui/util/ImageRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qtfred/src/ui/util/ImageRenderer.cpp b/qtfred/src/ui/util/ImageRenderer.cpp index 15350038e1e..8659eefd8c4 100644 --- a/qtfred/src/ui/util/ImageRenderer.cpp +++ b/qtfred/src/ui/util/ImageRenderer.cpp @@ -23,7 +23,7 @@ bool loadHandleToQImage(int bmHandle, QImage& outImage, QString* outError) } int w = 0, h = 0; - ushort flags = 0; + uint flags = 0; int nframes = 0, fps = 0; // Use the returned handle (first frame if this is an animation.. TODO: Handle animations. Will be useful for Heads) From 97fd0957daa33bb0435798d8ba6d8f6d5db7c74f Mon Sep 17 00:00:00 2001 From: Salvador Cipolla Date: Thu, 18 Sep 2025 07:54:22 -0300 Subject: [PATCH 07/10] change ktx format to enum --- code/graphics/opengl/gropengltexture.cpp | 4 ++-- code/ktxutils/ktxutils.cpp | 6 ++--- code/ktxutils/ktxutils.h | 28 ++++++++++++------------ 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/code/graphics/opengl/gropengltexture.cpp b/code/graphics/opengl/gropengltexture.cpp index 31b571bc98c..fb43a4b486d 100644 --- a/code/graphics/opengl/gropengltexture.cpp +++ b/code/graphics/opengl/gropengltexture.cpp @@ -450,7 +450,7 @@ static int opengl_texture_set_level(int bitmap_handle, int bitmap_type, int bmap case KTX_ETC2_SRGB_A1: case KTX_EAC_R11_SNORM: case KTX_EAC_RG11_SNORM: - intFormat = ktx_map_ktx_type_to_gl_internal(bm_handle); + intFormat = ktx_map_ktx_format_to_gl_internal(bm_handle); block_size = ktx_etc_block_bytes(intFormat); break; } @@ -779,7 +779,7 @@ static GLenum opengl_get_internal_format(int handle, int bitmap_type, int bpp) { case KTX_ETC2_SRGB_A1: case KTX_EAC_R11_SNORM: case KTX_EAC_RG11_SNORM: - return ktx_map_ktx_type_to_gl_internal(bm_handle); + return ktx_map_ktx_format_to_gl_internal(bm_handle); default: // Not compressed diff --git a/code/ktxutils/ktxutils.cpp b/code/ktxutils/ktxutils.cpp index d92ca0dbe76..a76dbdd0d3f 100644 --- a/code/ktxutils/ktxutils.cpp +++ b/code/ktxutils/ktxutils.cpp @@ -7,7 +7,7 @@ static const uint8_t KTX_ID[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' }; // BPB ETC/EAC -uint32_t ktx_etc_block_bytes(GLenum internal_format) +uint32_t ktx_etc_block_bytes(const int internal_format) { switch (internal_format) { @@ -31,7 +31,7 @@ uint32_t ktx_etc_block_bytes(GLenum internal_format) } -int ktx_map_ktx_type_to_gl_internal(unsigned int ktx_format) +int ktx_map_ktx_format_to_gl_internal(const int ktx_format) { switch (ktx_format) { @@ -60,7 +60,7 @@ int ktx_map_ktx_type_to_gl_internal(unsigned int ktx_format) } } -int ktx_map_gl_internal_to_bm(GLenum internal_format) +int ktx_map_gl_internal_to_bm(const int internal_format) { switch (internal_format) { diff --git a/code/ktxutils/ktxutils.h b/code/ktxutils/ktxutils.h index da9b05e7ce2..0ae9d4a3e3f 100644 --- a/code/ktxutils/ktxutils.h +++ b/code/ktxutils/ktxutils.h @@ -3,21 +3,21 @@ #include "cfile/cfile.h" #ifdef WITH_OPENGL #include -#else -#define GLenum int #endif // ETC2 types -#define KTX_ETC2_RGB 101 -#define KTX_ETC2_RGBA_EAC 102 -#define KTX_EAC_R11 103 -#define KTX_EAC_RG11 104 -#define KTX_ETC2_SRGB 105 -#define KTX_ETC2_SRGBA_EAC 106 -#define KTX_ETC2_RGB_A1 107 -#define KTX_ETC2_SRGB_A1 108 -#define KTX_EAC_R11_SNORM 109 -#define KTX_EAC_RG11_SNORM 110 +enum KTX_Format { + KTX_ETC2_RGB = 100, + KTX_ETC2_RGBA_EAC, + KTX_EAC_R11, + KTX_EAC_RG11, + KTX_ETC2_SRGB, + KTX_ETC2_SRGBA_EAC, + KTX_ETC2_RGB_A1, + KTX_ETC2_SRGB_A1, + KTX_EAC_R11_SNORM, + KTX_EAC_RG11_SNORM +}; // GLenum definitions, ETC2 is guarranted on ES 3.2, but in desktop GL it is supported from 4.3 // glad loader is GL 3.2 and these definitions are not there. But these will work if the GPU is GL 4.3 @@ -80,6 +80,6 @@ int ktx1_read_header(const char* filename, CFILE* img_cfp, int* w, int* h, int* int ktx1_read_bitmap(const char* filename, ubyte* dst, ubyte* out_bpp); -int ktx_map_ktx_type_to_gl_internal(unsigned int ktx_format); +int ktx_map_ktx_format_to_gl_internal(const int ktx_format); -uint32_t ktx_etc_block_bytes(GLenum internal_format); \ No newline at end of file +uint32_t ktx_etc_block_bytes(const int internal_format); \ No newline at end of file From 3cfad2248a67acb800137164b53d07d3b8fa2a03 Mon Sep 17 00:00:00 2001 From: Salvador Cipolla Date: Thu, 18 Sep 2025 18:50:33 -0300 Subject: [PATCH 08/10] use nullptr --- code/ktxutils/ktxutils.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/code/ktxutils/ktxutils.cpp b/code/ktxutils/ktxutils.cpp index a76dbdd0d3f..740ea707931 100644 --- a/code/ktxutils/ktxutils.cpp +++ b/code/ktxutils/ktxutils.cpp @@ -91,9 +91,9 @@ int ktx1_read_header(const char* filename, CFILE* img_cfp, int* w, int* h, int* { CFILE* cf; char real_name[MAX_FILENAME_LEN]; - if (img_cfp == NULL) { + if (img_cfp == nullptr) { // this better not happen.. ever - Assert(filename != NULL); + Assert(filename != nullptr); // make sure there is an extension strcpy_s(real_name, filename); @@ -107,7 +107,7 @@ int ktx1_read_header(const char* filename, CFILE* img_cfp, int* w, int* h, int* cf = cfopen(real_name, "rb"); // file not found - if (cf == NULL) + if (cf == nullptr) return KTX1_ERROR_INVALID_FILENAME; } else { cf = img_cfp; @@ -218,7 +218,7 @@ int ktx1_read_bitmap(const char* filename, ubyte* dst, ubyte* out_bpp) CFILE* cf; char real_name[MAX_FILENAME_LEN]; // this better not happen.. ever - Assert(filename != NULL); + Assert(filename != nullptr); // make sure there is an extension strcpy_s(real_name, filename); @@ -232,7 +232,7 @@ int ktx1_read_bitmap(const char* filename, ubyte* dst, ubyte* out_bpp) cf = cfopen(real_name, "rb"); // file not found - if (cf == NULL) + if (cf == nullptr) return KTX1_ERROR_INVALID_FILENAME; KTX1_Header hdr{}; From 65db883c86ff912cb9199b41f96b9c82e82cc680 Mon Sep 17 00:00:00 2001 From: Salvador Cipolla Date: Fri, 19 Sep 2025 21:15:01 -0300 Subject: [PATCH 09/10] ktx: support the same etc2 formats available in amd compressonator --- code/bmpman/bmpman.cpp | 48 ++++++++++++----------- code/bmpman/bmpman.h | 27 +++++++------ code/graphics/opengl/gropengltexture.cpp | 30 +++++---------- code/ktxutils/ktxutils.cpp | 49 ++++++++++-------------- code/ktxutils/ktxutils.h | 18 +-------- 5 files changed, 73 insertions(+), 99 deletions(-) diff --git a/code/bmpman/bmpman.cpp b/code/bmpman/bmpman.cpp index 16643a0ab16..0c0743d03e3 100644 --- a/code/bmpman/bmpman.cpp +++ b/code/bmpman/bmpman.cpp @@ -1059,14 +1059,20 @@ int bm_is_compressed(int num) { case BM_TYPE_ETC2_RGB: return KTX_ETC2_RGB; + case BM_TYPE_ETC2_SRGB: + return KTX_ETC2_SRGB; + case BM_TYPE_ETC2_RGBA_EAC: return KTX_ETC2_RGBA_EAC; - case BM_TYPE_EAC_R11: - return KTX_EAC_R11; + case BM_TYPE_ETC2_SRGBA_EAC: + return KTX_ETC2_SRGBA_EAC; + + case BM_TYPE_ETC2_RGBA1: + return KTX_ETC2_RGB_A1; - case BM_TYPE_EAC_RG11: - return KTX_EAC_RG11; + case BM_TYPE_ETC2_SRGBA1: + return KTX_ETC2_SRGB_A1; default: return 0; @@ -2797,19 +2803,18 @@ void bm_page_in_texture(int bitmapnum, int nframes) { continue; case BM_TYPE_ETC2_RGB: - frame_entry->used_flags = BMP_TEX_ETC2_RGB; - continue; - - case BM_TYPE_ETC2_RGBA_EAC: - frame_entry->used_flags = BMP_TEX_ETC2_RGBA_EAC; + case BM_TYPE_ETC2_SRGB: + frame_entry->used_flags = BMP_TEX_ETC2_RGB8; continue; - case BM_TYPE_EAC_R11: - frame_entry->used_flags = BMP_TEX_EAC_R11; + case BM_TYPE_ETC2_RGBA1: + case BM_TYPE_ETC2_SRGBA1: + frame_entry->used_flags = BMP_TEX_ETC2_RGBA1; continue; - case BM_TYPE_EAC_RG11: - frame_entry->used_flags = BMP_TEX_EAC_RG11; + case BM_TYPE_ETC2_RGBA_EAC: + case BM_TYPE_ETC2_SRGBA_EAC: + frame_entry->used_flags = BMP_TEX_ETC2_RGBA8; continue; default: @@ -2858,19 +2863,18 @@ void bm_page_in_xparent_texture(int bitmapnum, int nframes) { continue; case BM_TYPE_ETC2_RGB: - entry->used_flags = BMP_TEX_ETC2_RGB; + case BM_TYPE_ETC2_SRGB: + entry->used_flags = BMP_TEX_ETC2_RGB8; continue; - case BM_TYPE_ETC2_RGBA_EAC: - entry->used_flags = BMP_TEX_ETC2_RGBA_EAC; + case BM_TYPE_ETC2_RGBA1: + case BM_TYPE_ETC2_SRGBA1: + entry->used_flags = BMP_TEX_ETC2_RGBA1; continue; - case BM_TYPE_EAC_R11: - entry->used_flags = BMP_TEX_EAC_R11; - continue; - - case BM_TYPE_EAC_RG11: - entry->used_flags = BMP_TEX_EAC_RG11; + case BM_TYPE_ETC2_RGBA_EAC: + case BM_TYPE_ETC2_SRGBA_EAC: + entry->used_flags = BMP_TEX_ETC2_RGBA8; continue; default: diff --git a/code/bmpman/bmpman.h b/code/bmpman/bmpman.h index 09c98816069..a5979b220a5 100644 --- a/code/bmpman/bmpman.h +++ b/code/bmpman/bmpman.h @@ -34,7 +34,7 @@ // Flag positions for bitmap.flags // ***** NOTE: bitmap.flags is an 8-bit value, no more BMP_TEX_* flags can be added unless the type is changed!! ****** -// Update: type changed to 16-bit +// Update: bitmap.flags type changed to 16-bit #define BMP_AABITMAP (1<<0) //!< antialiased bitmap #define BMP_TEX_XPARENT (1<<1) //!< transparent texture #define BMP_TEX_OTHER (1<<2) //!< so we can identify all "normal" textures @@ -44,14 +44,14 @@ #define BMP_TEX_BC7 (1<<6) //!< BC7 compressed 8r8g8b8a (32bit) #define BMP_TEX_CUBEMAP (1<<7) //!< a texture made for cubic environment map #define BMP_MASK_BITMAP (1<<8) //!< a bitmap that will be used for masking mouse interaction. Typically not used in render operations -#define BMP_TEX_ETC2_RGB (1 << 9) -#define BMP_TEX_ETC2_RGBA_EAC (1 << 10) -#define BMP_TEX_EAC_R11 (1 << 11) -#define BMP_TEX_EAC_RG11 (1 << 12) +#define BMP_TEX_ETC2_RGB8 (1 << 9) //!< ETC2 RGB compressed (24bit, no alpha) +#define BMP_TEX_ETC2_RGBA1 (1 << 10) //!< ETC2 RGBA1 compressed (24bit, 1 alpha) +#define BMP_TEX_ETC2_RGBA8 (1 << 11) //!< ETC2 RGBA8 compressed (32bit, 8 alpha) + // Combined flags -#define BMP_TEX_COMP ( BMP_TEX_DXT1 | BMP_TEX_DXT3 | BMP_TEX_DXT5 | BMP_TEX_BC7 | BMP_TEX_ETC2_RGB |\ - BMP_TEX_ETC2_RGBA_EAC | BMP_TEX_EAC_R11 | BMP_TEX_EAC_RG11 ) //!< Compressed textures +#define BMP_TEX_COMP ( BMP_TEX_DXT1 | BMP_TEX_DXT3 | BMP_TEX_DXT5 | BMP_TEX_BC7 | BMP_TEX_ETC2_RGB8 |\ + BMP_TEX_ETC2_RGBA1 | BMP_TEX_ETC2_RGBA8 ) //!< Compressed textures #define BMP_TEX_NONCOMP ( BMP_TEX_XPARENT | BMP_TEX_OTHER ) //!< Non-compressed textures #define BMP_TEX_ANY ( BMP_TEX_COMP | BMP_TEX_NONCOMP ) //!< Any texture @@ -88,11 +88,14 @@ enum BM_TYPE BM_TYPE_CUBEMAP_DXT5, //!< 32-bit cubemap (compressed cubemap surface) BM_TYPE_3D, //!< 3D in-memory - BM_TYPE_KTX, //!< generic identifier for KTX - BM_TYPE_ETC2_RGB, //!< 24 bit without alpha - BM_TYPE_ETC2_RGBA_EAC, //!< 32 bit with alpha - BM_TYPE_EAC_R11, //!< BC4 equivalent - BM_TYPE_EAC_RG11 //!< BC5 equivalent + + BM_TYPE_KTX, //!< generic identifier for KTX1 + BM_TYPE_ETC2_RGB, //!< 24 bit, no alpha + BM_TYPE_ETC2_SRGB, //!< 24 bit, no alpha, signed + BM_TYPE_ETC2_RGBA1, //!< 24 bit, 1 bit alpha + BM_TYPE_ETC2_SRGBA1, //!< 24 bit, 1 bit alpha, signed + BM_TYPE_ETC2_RGBA_EAC, //!< 32 bit, 8 bit alpha + BM_TYPE_ETC2_SRGBA_EAC //!< 32 bit, 8 bit alpha, signed }; /** diff --git a/code/graphics/opengl/gropengltexture.cpp b/code/graphics/opengl/gropengltexture.cpp index fb43a4b486d..c00c85b544c 100644 --- a/code/graphics/opengl/gropengltexture.cpp +++ b/code/graphics/opengl/gropengltexture.cpp @@ -442,14 +442,10 @@ static int opengl_texture_set_level(int bitmap_handle, int bitmap_type, int bmap case KTX_ETC2_RGB: case KTX_ETC2_RGBA_EAC: - case KTX_EAC_R11: - case KTX_EAC_RG11: case KTX_ETC2_SRGB: case KTX_ETC2_SRGBA_EAC: case KTX_ETC2_RGB_A1: case KTX_ETC2_SRGB_A1: - case KTX_EAC_R11_SNORM: - case KTX_EAC_RG11_SNORM: intFormat = ktx_map_ktx_format_to_gl_internal(bm_handle); block_size = ktx_etc_block_bytes(intFormat); break; @@ -771,14 +767,10 @@ static GLenum opengl_get_internal_format(int handle, int bitmap_type, int bpp) { case KTX_ETC2_RGB: case KTX_ETC2_RGBA_EAC: - case KTX_EAC_R11: - case KTX_EAC_RG11: case KTX_ETC2_SRGB: case KTX_ETC2_SRGBA_EAC: case KTX_ETC2_RGB_A1: case KTX_ETC2_SRGB_A1: - case KTX_EAC_R11_SNORM: - case KTX_EAC_RG11_SNORM: return ktx_map_ktx_format_to_gl_internal(bm_handle); default: @@ -869,23 +861,21 @@ void opengl_determine_bpp_and_flags(int bitmap_handle, int bitmap_type, ushort& break; case KTX_ETC2_RGB: + case KTX_ETC2_SRGB: bpp = 24; - flags |= BMP_TEX_ETC2_RGB; + flags |= BMP_TEX_ETC2_RGB8; break; - case KTX_ETC2_RGBA_EAC: - bpp = 32; - flags |= BMP_TEX_ETC2_RGBA_EAC; - break; - - case KTX_EAC_R11: - bpp = 8; - flags |= BMP_TEX_EAC_R11; + case KTX_ETC2_RGB_A1: + case KTX_ETC2_SRGB_A1: + bpp = 24; + flags |= BMP_TEX_ETC2_RGBA1; break; - case KTX_EAC_RG11: - bpp = 16; - flags |= BMP_TEX_EAC_RG11; + case KTX_ETC2_RGBA_EAC: + case KTX_ETC2_SRGBA_EAC: + bpp = 32; + flags |= BMP_TEX_ETC2_RGBA8; break; default: diff --git a/code/ktxutils/ktxutils.cpp b/code/ktxutils/ktxutils.cpp index 740ea707931..c54fcd04fd9 100644 --- a/code/ktxutils/ktxutils.cpp +++ b/code/ktxutils/ktxutils.cpp @@ -3,6 +3,13 @@ #include "cfile/cfile.h" //KTX1 Spec definition https://registry.khronos.org/KTX/specs/1.0/ktxspec.v1.html //ETC2 formats spec https://registry.khronos.org/DataFormat/specs/1.4/dataformat.1.4.inline.html#ETC2 +/* + KTX 1 Parser - Format supported by Etc2Comp and AMD Compressonator + ETC2 support for the formats supported by AMD compressonator and their signed alternatives: + ETC2_RGB / ETC2_SRGB -> 24 bit no alpha + ETC2_RGBA1 / ETC2_SRGBA1 -> 24 bit with 1 bit punchthrough alpha + ETC2_RGBA / ETC2_SRGBA -> 32 bit with 8 bit alpha +*/ static const uint8_t KTX_ID[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' }; @@ -15,14 +22,10 @@ uint32_t ktx_etc_block_bytes(const int internal_format) case GL_COMPRESSED_SRGB8_ETC2: case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: - case GL_COMPRESSED_R11_EAC: - case GL_COMPRESSED_SIGNED_R11_EAC: return 8; case GL_COMPRESSED_RGBA8_ETC2_EAC: case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: - case GL_COMPRESSED_RG11_EAC: - case GL_COMPRESSED_SIGNED_RG11_EAC: return 16; default: @@ -39,10 +42,6 @@ int ktx_map_ktx_format_to_gl_internal(const int ktx_format) return GL_COMPRESSED_RGB8_ETC2; case KTX_ETC2_RGBA_EAC: return GL_COMPRESSED_RGBA8_ETC2_EAC; - case KTX_EAC_R11: - return GL_COMPRESSED_R11_EAC; - case KTX_EAC_RG11: - return GL_COMPRESSED_RG11_EAC; case KTX_ETC2_SRGB: return GL_COMPRESSED_SRGB8_ETC2; case KTX_ETC2_SRGBA_EAC: @@ -51,10 +50,6 @@ int ktx_map_ktx_format_to_gl_internal(const int ktx_format) return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; case KTX_ETC2_SRGB_A1: return GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2; - case KTX_EAC_R11_SNORM: - return GL_COMPRESSED_SIGNED_R11_EAC; - case KTX_EAC_RG11_SNORM: - return GL_COMPRESSED_SIGNED_RG11_EAC; default: return 0; } @@ -65,22 +60,19 @@ int ktx_map_gl_internal_to_bm(const int internal_format) switch (internal_format) { case GL_COMPRESSED_RGB8_ETC2: + return BM_TYPE_ETC2_RGB; case GL_COMPRESSED_SRGB8_ETC2: + return BM_TYPE_ETC2_SRGB; + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: + return BM_TYPE_ETC2_RGBA1; case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: - return BM_TYPE_ETC2_RGB; + return BM_TYPE_ETC2_SRGBA1; case GL_COMPRESSED_RGBA8_ETC2_EAC: - case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: return BM_TYPE_ETC2_RGBA_EAC; - - case GL_COMPRESSED_R11_EAC: - case GL_COMPRESSED_SIGNED_R11_EAC: - return BM_TYPE_EAC_R11; - - case GL_COMPRESSED_RG11_EAC: - case GL_COMPRESSED_SIGNED_RG11_EAC: - return BM_TYPE_EAC_RG11; + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: + return BM_TYPE_ETC2_SRGBA_EAC; default: return BM_TYPE_NONE; @@ -91,6 +83,7 @@ int ktx1_read_header(const char* filename, CFILE* img_cfp, int* w, int* h, int* { CFILE* cf; char real_name[MAX_FILENAME_LEN]; + //copied from ddsutils if (img_cfp == nullptr) { // this better not happen.. ever Assert(filename != nullptr); @@ -187,17 +180,16 @@ int ktx1_read_header(const char* filename, CFILE* img_cfp, int* w, int* h, int* switch (bm_ct) { case BM_TYPE_ETC2_RGB: + case BM_TYPE_ETC2_SRGB: + case BM_TYPE_ETC2_RGBA1: + case BM_TYPE_ETC2_SRGBA1: *bpp = 24; break; case BM_TYPE_ETC2_RGBA_EAC: + case BM_TYPE_ETC2_SRGBA_EAC: *bpp = 32; break; - case BM_TYPE_EAC_R11: - *bpp = 8; - break; - case BM_TYPE_EAC_RG11: - *bpp = 16; - break; + default: *bpp = 0; break; @@ -217,6 +209,7 @@ int ktx1_read_bitmap(const char* filename, ubyte* dst, ubyte* out_bpp) { CFILE* cf; char real_name[MAX_FILENAME_LEN]; + // copied from ddsutils // this better not happen.. ever Assert(filename != nullptr); diff --git a/code/ktxutils/ktxutils.h b/code/ktxutils/ktxutils.h index 0ae9d4a3e3f..eb04bfe849c 100644 --- a/code/ktxutils/ktxutils.h +++ b/code/ktxutils/ktxutils.h @@ -9,14 +9,10 @@ enum KTX_Format { KTX_ETC2_RGB = 100, KTX_ETC2_RGBA_EAC, - KTX_EAC_R11, - KTX_EAC_RG11, KTX_ETC2_SRGB, KTX_ETC2_SRGBA_EAC, KTX_ETC2_RGB_A1, - KTX_ETC2_SRGB_A1, - KTX_EAC_R11_SNORM, - KTX_EAC_RG11_SNORM + KTX_ETC2_SRGB_A1 }; // GLenum definitions, ETC2 is guarranted on ES 3.2, but in desktop GL it is supported from 4.3 @@ -40,18 +36,6 @@ enum KTX_Format { #ifndef GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC #define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 #endif -#ifndef GL_COMPRESSED_R11_EAC -#define GL_COMPRESSED_R11_EAC 0x9270 -#endif -#ifndef GL_COMPRESSED_SIGNED_R11_EAC -#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 -#endif -#ifndef GL_COMPRESSED_RG11_EAC -#define GL_COMPRESSED_RG11_EAC 0x9272 -#endif -#ifndef GL_COMPRESSED_SIGNED_RG11_EAC -#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 -#endif enum KTX1_Error { KTX1_ERROR_NONE = 0, From c539bde50e73f383bf999de034a99131308e6c4e Mon Sep 17 00:00:00 2001 From: Salvador Cipolla Date: Mon, 29 Sep 2025 23:04:14 -0300 Subject: [PATCH 10/10] add comments and missing include --- code/graphics/opengl/gropengltexture.cpp | 1 + code/ktxutils/ktxutils.h | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/code/graphics/opengl/gropengltexture.cpp b/code/graphics/opengl/gropengltexture.cpp index c00c85b544c..6ae97cdffbe 100644 --- a/code/graphics/opengl/gropengltexture.cpp +++ b/code/graphics/opengl/gropengltexture.cpp @@ -24,6 +24,7 @@ #include "math/vecmat.h" #include "options/Option.h" #include "osapi/osregistry.h" +#include matrix4 GL_texture_matrix; int GL_texture_ram = 0; diff --git a/code/ktxutils/ktxutils.h b/code/ktxutils/ktxutils.h index eb04bfe849c..b4b0aedc18c 100644 --- a/code/ktxutils/ktxutils.h +++ b/code/ktxutils/ktxutils.h @@ -60,10 +60,14 @@ struct KTX1_Header { uint32_t bytesOfKeyValueData; }; +//reads a dds header and returns a KTX1_Error int ktx1_read_header(const char* filename, CFILE* img_cfp, int* w, int* h, int* bpp, int* c_type, int* mip_levels, size_t* total_size); +//reads bitmap and returns a KTX1_Error int ktx1_read_bitmap(const char* filename, ubyte* dst, ubyte* out_bpp); +//Get the GL enum type for this KTX format type, returns 0 if type is invalid. int ktx_map_ktx_format_to_gl_internal(const int ktx_format); +//Get ktx bits per byte from GL internat format enum, returns 0 if internal format is invalid uint32_t ktx_etc_block_bytes(const int internal_format); \ No newline at end of file