From ac9133c14c82404a0cefda4c32d2357950f84dd6 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Mon, 8 Sep 2025 17:07:29 +0200 Subject: [PATCH 01/11] tr_image: rework the alpha detection --- src/engine/renderer/tr_image.cpp | 51 +++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index b430bedcd4..5f8ba3300c 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -1041,30 +1041,53 @@ void R_UploadImage( const char *name, const byte **dataArray, int numLayers, int } else { - // scan the texture for each channel's max values - // and verify if the alpha channel is being used or not + // lightmap does not have alpha channel + if ( image->bits & IF_LIGHTMAP ) + { + internalFormat = GL_RGB8; + } + else + { + internalFormat = GL_RGBA8; + } + } - c = image->width * image->height; - scan = dataArray[0]; + // Detect formats. + if ( dataArray ) + { + if ( internalFormat == GL_RGBA8 ) + { + /* Scan the texture for alpha channel's max values + and verify if the alpha channel is being used or not. */ - // lightmap does not have alpha channel + internalFormat = GL_RGB8; - // normalmap may have the heightmap in the alpha channel - // opaque alpha channel means no displacement, so we can enable - // alpha channel everytime it is used, even for normalmap + c = image->width * image->height; - internalFormat = GL_RGB8; + /* A normalmap may have the heightmap in the alpha channel, + an opaque alpha channel means no displacement, so we can enable + the alpha channel everytime it is used, even for normalmap. */ - if ( !( image->bits & IF_LIGHTMAP ) ) - { - for ( i = 0; i < c; i++ ) + for ( int l = 0; l < numLayers; l++ ) { - if ( scan[ i * 4 + 3 ] != 255 ) + scan = dataArray[ l ]; + + for ( i = 0; i < c * 4; i += 4 ) + { + if ( scan[ i + 3 ] != 255 ) + { + internalFormat = GL_RGBA8; + break; + } + } + + if ( internalFormat == GL_RGBA8 ) { - internalFormat = GL_RGBA8; break; } } + + internalFormat = hasAlpha ? GL_RGBA8 : GL_RGB8; } } From 8537bf48f5d4550df62cc7942caf5cf042b265f4 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Wed, 6 Aug 2025 08:13:39 +0200 Subject: [PATCH 02/11] renderer: implement and detect RED and RG images --- src/engine/renderer/tr_backend.cpp | 13 +++-- src/engine/renderer/tr_image.cpp | 82 +++++++++++++++++++++++++++++- src/engine/renderer/tr_public.h | 2 + src/engine/sys/sdl_glimp.cpp | 14 ++++- 4 files changed, 104 insertions(+), 7 deletions(-) diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index 43f74375a0..d8b9421ea8 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -739,12 +739,17 @@ static GLint GL_ToSRGB( GLint internalFormat, bool isSRGB ) { switch ( format ) { -#if 0 // Not used in the code base. - /* EXT_texture_sRGB_R8 extension. - See: https://github.com/KhronosGroup/OpenGL-Registry/blob/main/extensions/EXT/EXT_texture_sRGB_R8.txt */ case GL_RED: + case GL_R8: + /* EXT_texture_sRGB_R8 extension. + See: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_sRGB_R8.txt */ + ASSERT( glConfig.textureSrgbR8Available ); return GL_SR8_EXT; -#endif + case GL_RG8: + /* EXT_texture_sRGB_RG8 extension. + See: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_sRGB_RG8.txt */ + ASSERT( glConfig.textureSrgbRG8Available ); + return GL_SRG8_EXT; case GL_RGB: return GL_SRGB; case GL_RGBA: diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index 5f8ba3300c..a5b7d15fbf 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -164,6 +164,7 @@ class ListImagesCmd : public Cmd::StaticCmd internal component resolutions of its own choosing, referred to as the effective internal format." Use 4 bytes as an estimate: */ { GL_RGBA, { "RGBA", 4 } }, + { GL_RED, { "RED", 1 } }, { GL_RGB8, { "RGB8", 3 } }, { GL_RGBA8, { "RGBA8", 4 } }, @@ -176,10 +177,12 @@ class ListImagesCmd : public Cmd::StaticCmd { GL_RGBA32UI, { "RGBA32UI", 16 } }, { GL_ALPHA16F_ARB, { "A16F", 2 } }, { GL_ALPHA32F_ARB, { "A32F", 4 } }, + { GL_R8, { "R8", 1 } }, { GL_R16F, { "R16F", 2 } }, { GL_R32F, { "R32F", 4 } }, { GL_LUMINANCE_ALPHA16F_ARB, { "LA16F", 4 } }, { GL_LUMINANCE_ALPHA32F_ARB, { "LA32F", 8 } }, + { GL_RG8, { "RG8", 2 } }, { GL_RG16F, { "RG16F", 4 } }, { GL_RG32F, { "RG32F", 8 } }, @@ -1086,8 +1089,85 @@ void R_UploadImage( const char *name, const byte **dataArray, int numLayers, int break; } } + } + + if ( internalFormat == GL_RGB8 ) + { + /* Scan the texture for green and blue channels' max values + and verify if the green and blue channels are being used or not. */ + + bool hasGreen = false; + bool hasBlue = false; + + c = image->width * image->height; + + for ( int l = 0; l < numLayers; l++ ) + { + scan = dataArray[ l ]; + + for ( i = 0; i < c * 4; i += 4 ) + { + if ( scan[ i + 2 ] != 0 ) + { + // We need GL_RGB8. + hasBlue = true; + break; + } + + if ( scan[ i + 1 ] != 0 ) + { + hasGreen = true; + + if ( !glConfig.textureRGAvailable ) + { + // We can't store RG so we can stop there and use GL_RGB8. + break; + } + // Else continue to make sure there is no blue at all. + } + + // Else use GL_RED or GL_R8. + } + + if ( hasBlue || ( hasGreen && !glConfig.textureRGAvailable ) ) + { + break; + } + } - internalFormat = hasAlpha ? GL_RGBA8 : GL_RGB8; + if ( hasBlue ) + { + // Keep GL_RGB8. + } + else if ( hasGreen ) + { + if ( !glConfig.textureRGAvailable ) + { + // Keep GL_RGB8. + } + else + { + if ( isSRGB && !glConfig.textureSrgbRG8Available ) + { + // Keep GL_RGB8. + } + else + { + internalFormat = GL_RG8; + } + } + } + else + { + if ( isSRGB && !glConfig.textureSrgbR8Available ) + { + // Keep GL_RGB8. + } + else + { + internalFormat = glConfig.textureRGAvailable ? GL_R8 : GL_RED; + } + } } } diff --git a/src/engine/renderer/tr_public.h b/src/engine/renderer/tr_public.h index 3864e278b4..77f55fca05 100644 --- a/src/engine/renderer/tr_public.h +++ b/src/engine/renderer/tr_public.h @@ -139,6 +139,8 @@ struct GLConfig bool gpuShader4Available; bool gpuShader5Available; bool textureGatherAvailable; + bool textureSrgbR8Available; + bool textureSrgbRG8Available; int maxDrawBuffers; float maxTextureAnisotropy; diff --git a/src/engine/sys/sdl_glimp.cpp b/src/engine/sys/sdl_glimp.cpp index 1580598a94..25bb7bc358 100644 --- a/src/engine/sys/sdl_glimp.cpp +++ b/src/engine/sys/sdl_glimp.cpp @@ -108,6 +108,8 @@ static Cvar::Cvar r_arb_texture_barrier( "r_arb_texture_barrier", "Use GL_ARB_texture_barrier if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_texture_gather( "r_arb_texture_gather", "Use GL_ARB_texture_gather if available", Cvar::NONE, true ); +static Cvar::Cvar r_arb_texture_rg( "r_arb_texture_rg", + "Use GL_ARB_texture_rg if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_uniform_buffer_object( "r_arb_uniform_buffer_object", "Use GL_ARB_uniform_buffer_object if available", Cvar::NONE, true ); static Cvar::Cvar r_arb_vertex_attrib_binding( "r_arb_vertex_attrib_binding", @@ -122,8 +124,10 @@ static Cvar::Cvar r_ext_texture_float( "r_ext_texture_float", "Use GL_EXT_texture_float if available", Cvar::NONE, true ); static Cvar::Cvar r_ext_texture_integer( "r_ext_texture_integer", "Use GL_EXT_texture_integer if available", Cvar::NONE, true ); -static Cvar::Cvar r_ext_texture_rg( "r_ext_texture_rg", - "Use GL_EXT_texture_rg if available", Cvar::NONE, true ); +static Cvar::Cvar r_ext_texture_srgb_r8( "r_ext_texture_srgb_r8", + "Use GL_EXT_texture_sRGB_R8 if available", Cvar::NONE, true ); +static Cvar::Cvar r_ext_texture_srgb_rg8( "r_ext_texture_srgb_rg8", + "Use GL_EXT_texture_sRGB_RG8 if available", Cvar::NONE, true ); static Cvar::Cvar r_khr_debug( "r_khr_debug", "Use GL_KHR_debug if available", Cvar::NONE, true ); static Cvar::Cvar r_khr_shader_subgroup( "r_khr_shader_subgroup", @@ -2031,6 +2035,7 @@ static void GLimp_InitExtensions() Cvar::Latch( r_ext_texture_float ); Cvar::Latch( r_ext_texture_integer ); Cvar::Latch( r_ext_texture_rg ); + Cvar::Latch( r_ext_texture_srgb_r8 ); Cvar::Latch( r_khr_debug ); Cvar::Latch( r_khr_shader_subgroup ); @@ -2210,6 +2215,11 @@ static void GLimp_InitExtensions() // made required in OpenGL 3.0 glConfig.textureCompressionRGTCAvailable = LOAD_EXTENSION( ExtFlag_CORE, ARB_texture_compression_rgtc ); + glConfig.textureSrgbR8Available = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, EXT_texture_sRGB_R8, r_ext_texture_srgb_r8.Get() ); + + // Texture - others + glConfig.textureSrgbRG8Available = LOAD_EXTENSION_WITH_TEST( ExtFlag_NONE, EXT_texture_sRGB_RG8, r_ext_texture_srgb_rg8.Get() ); + // Texture - others glConfig.textureAnisotropyAvailable = false; glConfig.textureAnisotropy = 0.0f; From 5ff17d43ef83c04fff048c14fcdc03af45b5fa13 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Mon, 8 Sep 2025 18:14:08 +0200 Subject: [PATCH 03/11] renderer: introduce and use IF_NOALPHA --- src/engine/renderer/tr_bsp.cpp | 4 ++-- src/engine/renderer/tr_image.cpp | 34 ++++++++++++++++---------------- src/engine/renderer/tr_local.h | 3 ++- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/engine/renderer/tr_bsp.cpp b/src/engine/renderer/tr_bsp.cpp index 7da251d6b0..50f20af931 100644 --- a/src/engine/renderer/tr_bsp.cpp +++ b/src/engine/renderer/tr_bsp.cpp @@ -483,8 +483,8 @@ static void R_LoadLightmaps( lump_t *l, const char *bspName ) return; } - int lightMapBits = IF_LIGHTMAP | IF_NOPICMIP; - int deluxeMapBits = IF_NORMALMAP | IF_NOPICMIP; + int lightMapBits = IF_LIGHTMAP | IF_NOALPHA | IF_NOPICMIP; + int deluxeMapBits = IF_NORMALMAP | IF_NOALPHA | IF_NOPICMIP; if ( tr.worldLinearizeLightMap ) { diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index a5b7d15fbf..12251538b3 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -851,10 +851,13 @@ void R_UploadImage( const char *name, const byte **dataArray, int numLayers, int int mipWidth, mipHeight, mipLayers, mipSize, blockSize = 0; int i, c; const byte *scan; + + bool isSRGB = image->bits & IF_SRGB; + bool isAlpha = !( image->bits & IF_NOALPHA ); + GLenum target; GLenum format = GL_RGBA; - GLenum internalFormat = GL_RGB; - bool isSRGB = image->bits & IF_SRGB; + GLenum internalFormat = isAlpha ? GL_RGBA : GL_RGB; static const vec4_t oneClampBorder = { 1, 1, 1, 1 }; static const vec4_t zeroClampBorder = { 0, 0, 0, 1 }; @@ -1044,15 +1047,12 @@ void R_UploadImage( const char *name, const byte **dataArray, int numLayers, int } else { - // lightmap does not have alpha channel - if ( image->bits & IF_LIGHTMAP ) - { - internalFormat = GL_RGB8; - } - else - { - internalFormat = GL_RGBA8; - } + internalFormat = GL_RGBA8; + } + + if ( internalFormat == GL_RGBA8 && !isAlpha ) + { + internalFormat = GL_RGB8; } // Detect formats. @@ -2657,7 +2657,7 @@ static void R_CreateBlackCubeImage() } imageParams_t imageParams = {}; - imageParams.bits = IF_NOPICMIP; + imageParams.bits = IF_NOPICMIP | IF_NOALPHA; imageParams.filterType = filterType_t::FT_LINEAR; imageParams.wrapType = wrapTypeEnum_t::WT_EDGE_CLAMP; @@ -2684,7 +2684,7 @@ static void R_CreateWhiteCubeImage() } imageParams_t imageParams = {}; - imageParams.bits = IF_NOPICMIP; + imageParams.bits = IF_NOPICMIP | IF_NOALPHA; imageParams.filterType = filterType_t::FT_LINEAR; imageParams.wrapType = wrapTypeEnum_t::WT_EDGE_CLAMP; @@ -2727,7 +2727,7 @@ static void R_CreateColorGradeImage() } imageParams_t imageParams = {}; - imageParams.bits = IF_NOPICMIP; + imageParams.bits = IF_NOPICMIP | IF_NOALPHA; imageParams.filterType = filterType_t::FT_LINEAR; imageParams.wrapType = wrapTypeEnum_t::WT_EDGE_CLAMP; @@ -2752,7 +2752,7 @@ void R_CreateBuiltinImages() memset( data, 255, sizeof( data ) ); imageParams_t imageParams = {}; - imageParams.bits = IF_NOPICMIP; + imageParams.bits = IF_NOPICMIP | IF_NOALPHA; imageParams.filterType = filterType_t::FT_LINEAR; imageParams.wrapType = wrapTypeEnum_t::WT_REPEAT; @@ -2766,11 +2766,11 @@ void R_CreateBuiltinImages() // generate a default normalmap with a fully opaque heightmap (no displacement) Vector4Set( data, 128, 128, 255, 255 ); - imageParams.bits = IF_NOPICMIP | IF_NORMALMAP; + imageParams.bits = IF_NOPICMIP | IF_NOALPHA | IF_NORMALMAP; tr.flatImage = R_CreateImage( "$flat", ( const byte ** ) &dataPtr, 1, 1, 1, imageParams ); - imageParams.bits = IF_NOPICMIP; + imageParams.bits = IF_NOPICMIP | IF_NOALPHA; imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP; // Don't reuse previously set data, we test the values for selecting the upload format. diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 0ba092ed53..5b88f797dc 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -498,7 +498,8 @@ enum class ssaoMode { IF_BC4 = BIT( 22 ), IF_BC5 = BIT( 23 ), IF_RGBA32UI = BIT( 24 ), - IF_HOMEPATH = BIT( 25 ) + IF_HOMEPATH = BIT( 25 ), + IF_NOALPHA = BIT( 26 ) }; enum class filterType_t From 338359f6e67b2560c9be16f36f45e4799dda0a05 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Mon, 8 Sep 2025 21:55:15 +0200 Subject: [PATCH 04/11] tr_backend: fix a comment --- src/engine/renderer/tr_backend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index d8b9421ea8..a702a9056b 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -758,7 +758,7 @@ static GLint GL_ToSRGB( GLint internalFormat, bool isSRGB ) return GL_SRGB8; case GL_RGBA8: return GL_SRGB8_ALPHA8; -#if 0 // Internal formats, should not be used directly. +#if 0 // Not used in the codebase. case GL_COMPRESSED_RGB: return GL_COMPRESSED_SRGB; case GL_COMPRESSED_RGBA: From 41471c0856fb24ec5b83dd39a35067421322cd3c Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sat, 13 Sep 2025 17:44:01 +0200 Subject: [PATCH 05/11] tr_image: flag glyph image with IF_ALPHA --- src/engine/renderer/tr_image.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index 12251538b3..d985da4b55 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -1604,7 +1604,7 @@ image_t *R_CreateGlyph( const char *name, const byte *pic, int width, int height image->texture->target = GL_TEXTURE_2D; image->width = width; image->height = height; - image->bits = IF_NOPICMIP; + image->bits = IF_NOPICMIP | IF_ALPHA; image->filterType = filterType_t::FT_LINEAR; image->wrapType = wrapTypeEnum_t::WT_CLAMP; From d46f1bbe8b3a023c98e1c69355f9d2a6d40f5469 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sat, 13 Sep 2025 23:50:23 +0200 Subject: [PATCH 06/11] sdl_glimp: fix the EXT/ARB texture_rg confusion --- src/engine/sys/sdl_glimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/sys/sdl_glimp.cpp b/src/engine/sys/sdl_glimp.cpp index 25bb7bc358..fa0c55f662 100644 --- a/src/engine/sys/sdl_glimp.cpp +++ b/src/engine/sys/sdl_glimp.cpp @@ -2027,6 +2027,7 @@ static void GLimp_InitExtensions() Cvar::Latch( r_arb_sync ); Cvar::Latch( r_arb_texture_barrier ); Cvar::Latch( r_arb_texture_gather ); + Cvar::Latch( r_arb_texture_rg ); Cvar::Latch( r_arb_uniform_buffer_object ); Cvar::Latch( r_arb_vertex_attrib_binding ); Cvar::Latch( r_ext_draw_buffers ); @@ -2034,7 +2035,6 @@ static void GLimp_InitExtensions() Cvar::Latch( r_ext_texture_filter_anisotropic ); Cvar::Latch( r_ext_texture_float ); Cvar::Latch( r_ext_texture_integer ); - Cvar::Latch( r_ext_texture_rg ); Cvar::Latch( r_ext_texture_srgb_r8 ); Cvar::Latch( r_khr_debug ); Cvar::Latch( r_khr_shader_subgroup ); @@ -2145,7 +2145,7 @@ static void GLimp_InitExtensions() && glConfig.gpuShader4Available; // made required in OpenGL 3.0 - glConfig.textureRGAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, ARB_texture_rg, r_ext_texture_rg.Get() ); + glConfig.textureRGAvailable = LOAD_EXTENSION_WITH_TEST( ExtFlag_CORE, ARB_texture_rg, r_arb_texture_rg.Get() ); { bool textureGatherEnabled = r_arb_texture_gather.Get(); From 14826240830e64e8ee5baf2ff202122535dd8965 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sun, 14 Sep 2025 00:28:07 +0200 Subject: [PATCH 07/11] tr_image: document the GL_RGB format --- src/engine/renderer/tr_image.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index d985da4b55..dd30be556e 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -163,6 +163,7 @@ class ListImagesCmd : public Cmd::StaticCmd "If internalformat is specified as a base internal format, the GL stores the resulting texture with internal component resolutions of its own choosing, referred to as the effective internal format." Use 4 bytes as an estimate: */ + { GL_RGB, { "RGB", 3 } }, { GL_RGBA, { "RGBA", 4 } }, { GL_RED, { "RED", 1 } }, From f1f3f529b189277f11ccf94410f26a140f7e21aa Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sun, 14 Sep 2025 00:38:59 +0200 Subject: [PATCH 08/11] tr_image: add some GL format checks and asserts --- src/engine/renderer/tr_image.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index dd30be556e..72623da0fe 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -1172,6 +1172,29 @@ void R_UploadImage( const char *name, const byte **dataArray, int numLayers, int } } + // Make sure we prefer GL_R8 when ARB_texture_rg is available. + ASSERT( !( internalFormat == GL_RED && glConfig.textureRGAvailable ) ); + // Make sure we only use GL_R8 when ARB_texture_rg is available. + ASSERT( !( internalFormat == GL_R8 && !glConfig.textureRGAvailable ) ); + // Make sure we only use GL_RG8 when ARB_texture_rg is available. + ASSERT( !( internalFormat == GL_RG8 && !glConfig.textureRGAvailable ) ); + // Make sure we only use GL_SR8_EXT when EXT_texture_sRGB_R8 is available. + ASSERT( !( internalFormat == GL_R8 && isSRGB && !glConfig.textureSrgbR8Available ) ); + // Make sure we only use GL_SRG8_EXT when EXT_texture_sRGB_RG8 is available. + ASSERT( !( internalFormat == GL_RG8 && isSRGB && !glConfig.textureSrgbRG8Available ) ); + + // Make sure we prefer GL_RGB but don't enforce it. GL_RGB is used when we don't set a format. + if ( internalFormat == GL_RGBA ) + { + Log::Warn( "An explicit format should be used instead of GL_RGB for image %s", name ); + } + + // Make sure we prefer GL_RGBA but don't enforce it. GL_RGBA is used when we don't set a format. + if ( internalFormat == GL_RGBA ) + { + Log::Warn( "An explicit format should be used instead of GL_RGBA for image %s", name ); + } + Log::Debug( "Uploading image %s (%d×%d, %d layers, %0#x type, %0#x format)", name, scaledWidth, scaledHeight, numLayers, image->type, internalFormat ); // 3D textures are uploaded in slices via glTexSubImage3D, From a2d5013441a5fcbe1dae13e0295dd74d51f70e91 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sat, 27 Sep 2025 03:48:38 +0200 Subject: [PATCH 09/11] tr_image: reshape the cinematic image generation a bit --- src/engine/renderer/tr_image.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index 72623da0fe..5d1c917c2b 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -2794,12 +2794,14 @@ void R_CreateBuiltinImages() tr.flatImage = R_CreateImage( "$flat", ( const byte ** ) &dataPtr, 1, 1, 1, imageParams ); + /* Generate cinematic frames. + It is empty data to be filled by the cinematic code, but + we fill it with non-zero values so the format detector keeps all color channels. */ + memset( data, 255, sizeof( data ) ); + imageParams.bits = IF_NOPICMIP | IF_NOALPHA; imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP; - // Don't reuse previously set data, we test the values for selecting the upload format. - memset( data, 255, sizeof( data ) ); - size_t numCinematicImages = 0; for ( image_t * &image : tr.cinematicImage ) { From 7b745f68968b115a8c14f838758d9eac850ccec2 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sat, 27 Sep 2025 04:44:43 +0200 Subject: [PATCH 10/11] tr_image: reshape the default image painting a bit --- src/engine/renderer/tr_image.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index 5d1c917c2b..641fdafc13 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -2493,23 +2493,18 @@ R_CreateDefaultImage static void R_CreateDefaultImage() { constexpr int DEFAULT_SIZE = 128; - int x; byte data[ DEFAULT_SIZE ][ DEFAULT_SIZE ][ 4 ]; byte *dataPtr = &data[0][0][0]; // the default image will be a box, to allow you to see the mapping coordinates memset( data, 32, sizeof( data ) ); - for ( x = 0; x < DEFAULT_SIZE; x++ ) + for ( int x = 0; x < DEFAULT_SIZE; x++ ) { - data[ 0 ][ x ][ 0 ] = data[ 0 ][ x ][ 1 ] = data[ 0 ][ x ][ 2 ] = data[ 0 ][ x ][ 3 ] = 255; - data[ x ][ 0 ][ 0 ] = data[ x ][ 0 ][ 1 ] = data[ x ][ 0 ][ 2 ] = data[ x ][ 0 ][ 3 ] = 255; - - data[ DEFAULT_SIZE - 1 ][ x ][ 0 ] = - data[ DEFAULT_SIZE - 1 ][ x ][ 1 ] = data[ DEFAULT_SIZE - 1 ][ x ][ 2 ] = data[ DEFAULT_SIZE - 1 ][ x ][ 3 ] = 255; - - data[ x ][ DEFAULT_SIZE - 1 ][ 0 ] = - data[ x ][ DEFAULT_SIZE - 1 ][ 1 ] = data[ x ][ DEFAULT_SIZE - 1 ][ 2 ] = data[ x ][ DEFAULT_SIZE - 1 ][ 3 ] = 255; + Vector4Set( data[ 0 ][ x ], 255, 255, 255, 255 ); + Vector4Set( data[ x ][ 0 ], 255, 255, 255, 255 ); + Vector4Set( data[ DEFAULT_SIZE - 1 ][ x ], 255, 255, 255, 255 ); + Vector4Set( data[ x ][ DEFAULT_SIZE - 1 ], 255, 255, 255, 255 ); } imageParams_t imageParams = {}; From 3b88a3a7e51122be146fe0609da852805a5e4ddf Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sat, 27 Sep 2025 04:48:51 +0200 Subject: [PATCH 11/11] tr_image: make some iterators more local --- src/engine/renderer/tr_image.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index 641fdafc13..273e2b39d3 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -850,7 +850,6 @@ void R_UploadImage( const char *name, const byte **dataArray, int numLayers, int const byte *data; byte *scaledBuffer = nullptr; int mipWidth, mipHeight, mipLayers, mipSize, blockSize = 0; - int i, c; const byte *scan; bool isSRGB = image->bits & IF_SRGB; @@ -1066,7 +1065,7 @@ void R_UploadImage( const char *name, const byte **dataArray, int numLayers, int internalFormat = GL_RGB8; - c = image->width * image->height; + int c = image->width * image->height; /* A normalmap may have the heightmap in the alpha channel, an opaque alpha channel means no displacement, so we can enable @@ -1076,7 +1075,7 @@ void R_UploadImage( const char *name, const byte **dataArray, int numLayers, int { scan = dataArray[ l ]; - for ( i = 0; i < c * 4; i += 4 ) + for ( int i = 0; i < c * 4; i += 4 ) { if ( scan[ i + 3 ] != 255 ) { @@ -1100,13 +1099,13 @@ void R_UploadImage( const char *name, const byte **dataArray, int numLayers, int bool hasGreen = false; bool hasBlue = false; - c = image->width * image->height; + int c = image->width * image->height; for ( int l = 0; l < numLayers; l++ ) { scan = dataArray[ l ]; - for ( i = 0; i < c * 4; i += 4 ) + for ( int i = 0; i < c * 4; i += 4 ) { if ( scan[ i + 2 ] != 0 ) { @@ -1204,7 +1203,7 @@ void R_UploadImage( const char *name, const byte **dataArray, int numLayers, int mipHeight = scaledHeight; mipLayers = numLayers; - for( i = 0; i < numMips; i++ ) { + for( int i = 0; i < numMips; i++ ) { GL_TexImage3D( GL_TEXTURE_3D, i, internalFormat, scaledWidth, scaledHeight, mipLayers, 0, format, GL_UNSIGNED_BYTE, nullptr, isSRGB ); if( mipWidth > 1 ) mipWidth >>= 1; @@ -1217,7 +1216,7 @@ void R_UploadImage( const char *name, const byte **dataArray, int numLayers, int if( dataArray ) scaledBuffer = (byte*) ri.Hunk_AllocateTempMemory( sizeof( byte ) * scaledWidth * scaledHeight * 4 ); - for ( i = 0; i < numLayers; i++ ) + for ( int i = 0; i < numLayers; i++ ) { if( dataArray ) data = dataArray[ i ]; @@ -1238,7 +1237,7 @@ void R_UploadImage( const char *name, const byte **dataArray, int numLayers, int } if( image->bits & IF_NORMALMAP ) { - c = scaledWidth * scaledHeight; + int c = scaledWidth * scaledHeight; for ( int j = 0; j < c; j++ ) { vec3_t n; @@ -1306,7 +1305,7 @@ void R_UploadImage( const char *name, const byte **dataArray, int numLayers, int mipHeight = scaledHeight; mipLayers = numLayers; - for ( i = 0; i < numMips; i++ ) + for ( int i = 0; i < numMips; i++ ) { mipSize = ((mipWidth + 3) >> 2) * ((mipHeight + 3) >> 2) * blockSize;