diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index bdbe237f89..d6b24472ab 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -1819,11 +1819,18 @@ image_t *R_FindImageFile( const char *imageName, imageParams_t &imageParams ) } // Built-in images can't be reloaded with different parameters, so return them as-is. - // For most of the usable ones e.g. _white, parameters wouldn't make a difference anyway. - // HACK: detect built-in images by naming convention, though nothing stops users from using such names - if ( image->name[ 0 ] == '_' && !strchr( image->name, '/' ) ) + // For most of the usable ones e.g. $white, parameters wouldn't make a difference anyway. + // Detect built-in images by naming convention. + switch ( image->name[ 0 ] ) { - return image; + // Private images not meant to be reused (like framebuffers, UI-generated images…). + case '*': + // Public images reusable by the user, like $white that can be used in .shader files. + case '$': + return image; + break; + default: + break; } bool compatible = false; @@ -2383,7 +2390,7 @@ static void R_CreateDefaultImage() imageParams.filterType = filterType_t::FT_DEFAULT; imageParams.wrapType = wrapTypeEnum_t::WT_REPEAT; - tr.defaultImage = R_CreateImage( "_default", ( const byte ** ) &dataPtr, DEFAULT_SIZE, DEFAULT_SIZE, 1, imageParams ); + tr.defaultImage = R_CreateImage( "$default", ( const byte ** ) &dataPtr, DEFAULT_SIZE, DEFAULT_SIZE, 1, imageParams ); } static void R_CreateContrastRenderFBOImage() @@ -2401,7 +2408,7 @@ static void R_CreateContrastRenderFBOImage() imageParams.filterType = filterType_t::FT_LINEAR; imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP; - tr.contrastRenderFBOImage = R_CreateImage( "_contrastRenderFBO", nullptr, width, height, 1, imageParams ); + tr.contrastRenderFBOImage = R_CreateImage( "*contrastRenderFBO", nullptr, width, height, 1, imageParams ); } static void R_CreateBloomRenderFBOImages() @@ -2421,7 +2428,7 @@ static void R_CreateBloomRenderFBOImages() imageParams.filterType = filterType_t::FT_LINEAR; imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP; - tr.bloomRenderFBOImage[i] = R_CreateImage( va( "_bloomRenderFBO%d", i ), nullptr, width, height, 1, imageParams ); + tr.bloomRenderFBOImage[i] = R_CreateImage( va( "*bloomRenderFBO%d", i ), nullptr, width, height, 1, imageParams ); } } @@ -2456,15 +2463,15 @@ static void R_CreateCurrentRenderImage() imageParams.filterType = filterType_t::FT_NEAREST; imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP; - tr.currentRenderImage[0] = R_CreateImage( "_currentRender[0]", nullptr, width, height, 1, imageParams ); - tr.currentRenderImage[1] = R_CreateImage( "_currentRender[1]", nullptr, width, height, 1, imageParams ); + tr.currentRenderImage[0] = R_CreateImage( "*currentRender0", nullptr, width, height, 1, imageParams ); + tr.currentRenderImage[1] = R_CreateImage( "*currentRender1", nullptr, width, height, 1, imageParams ); imageParams = {}; imageParams.bits = IF_NOPICMIP | IF_PACKED_DEPTH24_STENCIL8; imageParams.filterType = filterType_t::FT_NEAREST; imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP; - tr.currentDepthImage = R_CreateImage( "_currentDepth", nullptr, width, height, 1, imageParams ); + tr.currentDepthImage = R_CreateImage( "*currentDepth", nullptr, width, height, 1, imageParams ); if ( glConfig.usingMaterialSystem ) { materialSystem.GenerateDepthImages( width, height, imageParams ); @@ -2494,18 +2501,18 @@ static void R_CreateDepthRenderImage() imageParams.bits = IF_NOPICMIP; imageParams.bits |= r_highPrecisionRendering.Get() ? IF_TWOCOMP32F : IF_TWOCOMP16F; - tr.depthtile1RenderImage = R_CreateImage( "_depthtile1Render", nullptr, w, h, 1, imageParams ); + tr.depthtile1RenderImage = R_CreateImage( "*depthtile1Render", nullptr, w, h, 1, imageParams ); w = (width + TILE_SIZE - 1) >> TILE_SHIFT; h = (height + TILE_SIZE - 1) >> TILE_SHIFT; imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP; - tr.depthtile2RenderImage = R_CreateImage( "_depthtile2Render", nullptr, w, h, 1, imageParams ); + tr.depthtile2RenderImage = R_CreateImage( "*depthtile2Render", nullptr, w, h, 1, imageParams ); imageParams.bits = IF_NOPICMIP | IF_RGBA32UI; - tr.lighttileRenderImage = R_Create3DImage( "_lighttileRender", nullptr, w, h, glConfig.realtimeLightLayers, imageParams ); + tr.lighttileRenderImage = R_Create3DImage( "*lighttileRender", nullptr, w, h, glConfig.realtimeLightLayers, imageParams ); } } @@ -2526,7 +2533,7 @@ static void R_CreatePortalRenderImage() imageParams.filterType = filterType_t::FT_NEAREST; imageParams.wrapType = wrapTypeEnum_t::WT_CLAMP; - tr.portalRenderImage = R_CreateImage( "_portalRender", nullptr, width, height, 1, imageParams ); + tr.portalRenderImage = R_CreateImage( "*portalRender", nullptr, width, height, 1, imageParams ); } // *INDENT-OFF* @@ -2546,7 +2553,7 @@ static void R_CreateBlackCubeImage() imageParams.wrapType = wrapTypeEnum_t::WT_EDGE_CLAMP; const byte *dataPtrs[ 6 ] = { data, data, data, data, data, data }; - tr.blackCubeImage = R_CreateCubeImage( "_blackCube", dataPtrs, width, height, imageParams ); + tr.blackCubeImage = R_CreateCubeImage( "$blackCube", dataPtrs, width, height, imageParams ); } // *INDENT-ON* @@ -2572,7 +2579,7 @@ static void R_CreateWhiteCubeImage() imageParams.filterType = filterType_t::FT_LINEAR; imageParams.wrapType = wrapTypeEnum_t::WT_EDGE_CLAMP; - tr.whiteCubeImage = R_CreateCubeImage( "_whiteCube", ( const byte ** ) data, width, height, imageParams ); + tr.whiteCubeImage = R_CreateCubeImage( "$whiteCube", ( const byte ** ) data, width, height, imageParams ); for ( i = 5; i >= 0; i-- ) { @@ -2615,7 +2622,7 @@ static void R_CreateColorGradeImage() imageParams.filterType = filterType_t::FT_LINEAR; imageParams.wrapType = wrapTypeEnum_t::WT_EDGE_CLAMP; - tr.colorGradeImage = R_Create3DImage( "_colorGrade", data, REF_COLORGRADEMAP_SIZE, REF_COLORGRADEMAP_SIZE, REF_COLORGRADE_SLOTS * REF_COLORGRADEMAP_SIZE, imageParams ); + tr.colorGradeImage = R_Create3DImage( "$colorGrade", data, REF_COLORGRADEMAP_SIZE, REF_COLORGRADEMAP_SIZE, REF_COLORGRADE_SLOTS * REF_COLORGRADEMAP_SIZE, imageParams ); ri.Hunk_FreeTempMemory( data ); } @@ -2627,11 +2634,8 @@ R_CreateBuiltinImages */ void R_CreateBuiltinImages() { - constexpr int DIMENSION = 8; - int x; - byte data[ DIMENSION * DIMENSION * 4 ]; + byte data[ 1 * 1 * 4 ]; byte *dataPtr = data; - byte *out; R_CreateDefaultImage(); @@ -2643,57 +2647,31 @@ void R_CreateBuiltinImages() imageParams.filterType = filterType_t::FT_LINEAR; imageParams.wrapType = wrapTypeEnum_t::WT_REPEAT; - tr.whiteImage = R_CreateImage( "_white", ( const byte ** ) &dataPtr, DIMENSION, DIMENSION, 1, imageParams ); + tr.whiteImage = R_CreateImage( "$white", ( const byte ** ) &dataPtr, 1, 1, 1, imageParams ); // we use a solid black image instead of disabling texturing - memset( data, 0, sizeof( data ) ); - tr.blackImage = R_CreateImage( "_black", ( const byte ** ) &dataPtr, DIMENSION, DIMENSION, 1, imageParams ); - - // red - for ( x = DIMENSION * DIMENSION, out = data; x; --x, out += 4 ) - { - out[ 1 ] = out[ 2 ] = 0; - out[ 0 ] = out[ 3 ] = 255; - } - - tr.redImage = R_CreateImage( "_red", ( const byte ** ) &dataPtr, DIMENSION, DIMENSION, 1, imageParams ); + Vector4Set( data, 0, 0, 0, 255 ); - // green - for ( x = DIMENSION * DIMENSION, out = data; x; --x, out += 4 ) - { - out[ 0 ] = out[ 2 ] = 0; - out[ 1 ] = out[ 3 ] = 255; - } - - tr.greenImage = R_CreateImage( "_green", ( const byte ** ) &dataPtr, DIMENSION, DIMENSION, 1, imageParams ); - - // blue - for ( x = DIMENSION * DIMENSION, out = data; x; --x, out += 4 ) - { - out[ 0 ] = out[ 1 ] = 0; - out[ 2 ] = out[ 3 ] = 255; - } - - tr.blueImage = R_CreateImage( "_blue", ( const byte ** ) &dataPtr, DIMENSION, DIMENSION, 1, imageParams ); + tr.blackImage = R_CreateImage( "$black", ( const byte ** ) &dataPtr, 1, 1, 1, imageParams ); // generate a default normalmap with a fully opaque heightmap (no displacement) - for ( x = DIMENSION * DIMENSION, out = data; x; --x, out += 4 ) - { - out[ 0 ] = out[ 1 ] = 128; - out[ 2 ] = 255; - out[ 3 ] = 255; - } + Vector4Set( data, 128, 128, 255, 255 ); imageParams.bits = IF_NOPICMIP | IF_NORMALMAP; - tr.flatImage = R_CreateImage( "_flat", ( const byte ** ) &dataPtr, DIMENSION, DIMENSION, 1, imageParams ); + tr.flatImage = R_CreateImage( "$flat", ( const byte ** ) &dataPtr, 1, 1, 1, imageParams ); imageParams.bits = IF_NOPICMIP; 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 ) { - image = R_CreateImage( "_cinematic", ( const byte ** ) &dataPtr, 1, 1, 1, imageParams ); + std::string name = Str::Format( "*cinematic%d", numCinematicImages++ ); + image = R_CreateImage( name.c_str(), ( const byte ** ) &dataPtr, 1, 1, 1, imageParams ); } R_CreateContrastRenderFBOImage(); @@ -2855,7 +2833,7 @@ qhandle_t RE_GenerateTexture( const byte *pic, int width, int height ) { R_SyncRenderThread(); - std::string name = Str::Format( "$generatedTexture%d", tr.numGeneratedTextures++ ); + std::string name = Str::Format( "*generatedTexture%d", tr.numGeneratedTextures++ ); imageParams_t imageParams = {}; imageParams.bits = IF_NOPICMIP; diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 231015c716..d97ef87f3a 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -2445,10 +2445,7 @@ enum image_t *defaultImage; image_t *cinematicImage[ MAX_IN_GAME_VIDEOS ]; image_t *whiteImage; // full of 0xff - image_t *blackImage; // full of 0x0 - image_t *redImage; - image_t *greenImage; - image_t *blueImage; + image_t *blackImage; // 0x0 color channels, 0xff alpha channel image_t *flatImage; // use this as default normalmap image_t *blackCubeImage; image_t *whiteCubeImage; diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index 13116c89e6..647eae66c6 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -1429,24 +1429,19 @@ static bool LoadMap( shaderStage_t *stage, const char *buffer, stageType_t type, return true; } - if ( !Q_stricmp( token, "$whiteimage" ) || !Q_stricmp( token, "$white" ) || !Q_stricmp( token, "_white" ) || - !Q_stricmp( token, "*white" ) ) + // Quake III backward compatibility. + if ( !Q_stricmp( token, "$whiteimage" ) || !Q_stricmp( token, "*white" ) ) { stage->bundle[ bundleIndex ].image[ 0 ] = tr.whiteImage; return true; } - else if ( !Q_stricmp( token, "$blackimage" ) || !Q_stricmp( token, "$black" ) || !Q_stricmp( token, "_black" ) || - !Q_stricmp( token, "*black" ) ) + + // Other engine compatibility (old XeaL, QFusion…) + if ( !Q_stricmp( token, "$blackimage" ) || !Q_stricmp( token, "*black" ) ) { stage->bundle[ bundleIndex ].image[ 0 ] = tr.blackImage; return true; } - else if ( !Q_stricmp( token, "$flatimage" ) || !Q_stricmp( token, "$flat" ) || !Q_stricmp( token, "_flat" ) || - !Q_stricmp( token, "*flat" ) ) - { - stage->bundle[ bundleIndex ].image[ 0 ] = tr.flatImage; - return true; - } else if ( !Q_stricmp( token, "$lightmap" ) ) {