Fixed several bugs in the .bimage lookup logic

This commit is contained in:
Robert Beckebans 2025-01-06 17:58:31 +01:00
parent f9ca463d50
commit 67987ab715
7 changed files with 207 additions and 60 deletions

View file

@ -3,7 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2014-2024 Robert Beckebans
Copyright (C) 2014-2025 Robert Beckebans
Copyright (C) 2014-2016 Kot in Action Creative Artel
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -260,14 +260,6 @@ void idBinaryImage::Load2DFromMemory( int width, int height, const byte* pic_con
img.data[ i ] = pic[ i ];
}
}
else if( textureFormat == FMT_RGBA16F )
{
img.Alloc( scaledWidth * scaledHeight * 8 );
for( int i = 0; i < img.dataSize; i++ )
{
img.data[ i ] = pic[ i ];
}
}
else
{
fileData.format = textureFormat = FMT_RGBA8;
@ -287,7 +279,11 @@ void idBinaryImage::Load2DFromMemory( int width, int height, const byte* pic_con
// downsample for the next level
byte* shrunk = NULL;
if( gammaMips )
if( textureFormat == FMT_R11G11B10F )
{
shrunk = R_MipMapR11G11B10F( pic, scaledWidth, scaledHeight );
}
else if( gammaMips )
{
shrunk = R_MipMapWithGamma( pic, scaledWidth, scaledHeight );
}
@ -556,15 +552,6 @@ void idBinaryImage::Load2DAtlasMipchainFromMemory( int width, int height, const
img.data[ i * 2 + 1 ] = color & 0xFF;
}
}
else if( textureFormat == FMT_RG16F )
{
// RB: copy it as it was a RGBA8 because of the same size
img.Alloc( scaledWidth * scaledHeight * 4 );
for( int i = 0; i < img.dataSize; i++ )
{
img.data[ i ] = pic[ i ];
}
}
else if( textureFormat == FMT_R11G11B10F )
{
// RB: copy it as it was a RGBA8 because of the same size
@ -574,14 +561,6 @@ void idBinaryImage::Load2DAtlasMipchainFromMemory( int width, int height, const
img.data[ i ] = pic[ i ];
}
}
else if( textureFormat == FMT_RGBA16F )
{
img.Alloc( scaledWidth * scaledHeight * 8 );
for( int i = 0; i < img.dataSize; i++ )
{
img.data[ i ] = pic[ i ];
}
}
else
{
fileData.format = textureFormat = FMT_RGBA8;
@ -599,21 +578,6 @@ void idBinaryImage::Load2DAtlasMipchainFromMemory( int width, int height, const
dxtPic = NULL;
}
// downsample for the next level
/*
byte* shrunk = NULL;
if( gammaMips )
{
shrunk = R_MipMapWithGamma( pic, scaledWidth, scaledHeight );
}
else
{
shrunk = R_MipMap( pic, scaledWidth, scaledHeight );
}
Mem_Free( pic );
pic = shrunk;
*/
Mem_Free( pic );
}
@ -753,7 +717,11 @@ void idBinaryImage::LoadCubeFromMemory( int width, const byte* pics[6], int numL
// downsample for the next level
byte* shrunk = NULL;
if( gammaMips )
if( textureFormat == FMT_R11G11B10F )
{
shrunk = R_MipMapR11G11B10F( pic, scaledWidth, scaledWidth );
}
else if( gammaMips )
{
shrunk = R_MipMapWithGamma( pic, scaledWidth, scaledWidth );
}

View file

@ -207,6 +207,8 @@ No texture is ever used that does not have a corresponding idImage.
static const int MAX_TEXTURE_LEVELS = 14;
// How is this texture used? Determines the storage and color format
// NOTE: be very careful when editing these because it might break older .bimage files or the lookup name
// Only add new entries at the bottom
typedef enum
{
TD_SPECULAR, // may be compressed, and always zeros the alpha channel
@ -227,28 +229,33 @@ typedef enum
TD_HIGHQUALITY_CUBE, // motorsep - Uncompressed cubemap texture (RGB colorspace)
TD_LOWQUALITY_CUBE, // motorsep - Compressed cubemap texture (RGB colorspace DXT5)
TD_SHADOW_ARRAY, // 2D depth buffer array for shadow mapping
TD_RG16F,
TD_RGBA16F,
TD_RGBA16S,
TD_RGBA32F,
TD_R32F,
TD_RG16F, // BRDF lookup table
TD_RGBA16F, // RT = render target format only, not written to disk
TD_RGBA16S, // RT only
TD_RGBA32F, // RT only
TD_R11G11B10F, // memory efficient HDR RGB format with only 32bpp
// ^-- used up until RBDOOM-3-BFG 1.3
TD_HDRI, // RB: R11G11B10F or BC6
// RB end
TD_R8F, // Stephen: Added for ambient occlusion render target.
TD_LDR, // Stephen: Added for SRGB render target when tonemapping.
TD_DEPTH_STENCIL, // depth buffer and stencil buffer
TD_R32F, // RT only
TD_R8F, // SP: RT only, added for ambient occlusion
TD_LDR, // SP: RT only, added for SRGB render target when tonemapping
TD_DEPTH_STENCIL, // SP: RT only, depth buffer and stencil buffer
} textureUsage_t;
// NOTE: be very careful when editing these because it might break older .bimage files or the lookup name
// Only add new entries at the bottom
typedef enum
{
CF_2D, // not a cube map
CF_NATIVE, // _px, _nx, _py, etc, directly sent to GL
CF_CAMERA, // _forward, _back, etc, rotated and flipped as needed before sending to GL
CF_QUAKE1, // _ft, _bk, etc, rotated and flipped as needed before sending to GL
CF_PANORAMA, // TODO latlong encoded HDRI panorama typically used by Substance or Blender
CF_PANORAMA, // RB: latlong encoded HDRI panorama typically used by Substance or Blender
CF_2D_ARRAY, // not a cube map but not a single 2d texture either
CF_2D_PACKED_MIPCHAIN, // usually 2d but can be an octahedron, packed mipmaps into single 2d texture atlas and limited to dim^2
// ^-- used up until RBDOOM-3-BFG 1.3
CF_SINGLE, // SP: A single texture cubemap. All six sides in one image.
CF_QUAKE1, // RB: _ft, _bk, etc, rotated and flipped as needed before sending to GL
} cubeFiles_t;
typedef void ( *ImageGeneratorFunction )( idImage* image, nvrhi::ICommandList* commandList );
@ -663,6 +670,7 @@ byte* R_ResampleTexture( const byte* in, int inwidth, int inheight, int outwidth
byte* R_MipMapWithAlphaSpecularity( const byte* in, int width, int height );
byte* R_MipMapWithGamma( const byte* in, int width, int height );
byte* R_MipMap( const byte* in, int width, int height );
byte* R_MipMapR11G11B10F( const byte* in, int width, int height );
// these operate in-place on the provided pixels
void R_BlendOverTexture( byte* data, int pixelCount, const byte blend[4] );

View file

@ -156,11 +156,11 @@ ID_INLINE void idImage::DeriveOpts()
opts.format = FMT_DEPTH;
break;
// sp begin
// SP begin
case TD_DEPTH_STENCIL:
opts.format = FMT_DEPTH_STENCIL;
break;
// sp end
// SP end
case TD_SHADOW_ARRAY:
opts.format = FMT_SHADOW_ARRAY;
@ -200,6 +200,7 @@ ID_INLINE void idImage::DeriveOpts()
opts.format = FMT_DXT5;
opts.colorFormat = CFM_YCOCG_DXT5;
break;
case TD_SPECULAR:
opts.gammaMips = true;
opts.format = FMT_DXT1;
@ -223,16 +224,19 @@ ID_INLINE void idImage::DeriveOpts()
opts.format = FMT_DXT5;
opts.colorFormat = CFM_DEFAULT;
break;
case TD_BUMP:
opts.format = FMT_DXT5;
opts.colorFormat = CFM_NORMAL_DXT5;
break;
case TD_FONT:
opts.format = FMT_DXT1;
opts.colorFormat = CFM_GREEN_ALPHA;
opts.numLevels = 4; // We only support 4 levels because we align to 16 in the exporter
opts.gammaMips = true;
break;
case TD_LIGHT:
// RB: TODO check binary format version
// D3 BFG assets require RGB565 but it introduces color banding
@ -240,16 +244,20 @@ ID_INLINE void idImage::DeriveOpts()
opts.format = FMT_RGB565; //FMT_RGBA8;
opts.gammaMips = true;
break;
case TD_LOOKUP_TABLE_MONO:
opts.format = FMT_INT8;
break;
case TD_LOOKUP_TABLE_ALPHA:
opts.format = FMT_ALPHA;
break;
case TD_LOOKUP_TABLE_RGB1:
case TD_LOOKUP_TABLE_RGBA:
opts.format = FMT_RGBA8;
break;
// motorsep 05-17-2015; added this for uncompressed cubemap/skybox textures
case TD_HIGHQUALITY_CUBE:
opts.colorFormat = CFM_DEFAULT;
@ -261,6 +269,13 @@ ID_INLINE void idImage::DeriveOpts()
opts.format = FMT_DXT5;
opts.gammaMips = true;
break;
// motorsep end
case TD_HDRI:
opts.format = FMT_R11G11B10F;
//opts.numLevels = 1;
break;
default:
assert( false );
opts.format = FMT_RGBA8;

View file

@ -3,7 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2021 Robert Beckebans
Copyright (C) 2021-2025 Robert Beckebans
Copyright (C) 2021 Stephen Pridham
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -33,6 +33,8 @@ If you have questions concerning this license or the applicable additional terms
#include "RenderCommon.h"
#include "../libs/mesa/format_r11g11b10f.h"
/*
================
R_ResampleTexture
@ -463,6 +465,152 @@ byte* R_MipMap( const byte* in, int width, int height )
return out;
}
// RB begin
byte* R_MipMapR11G11B10F( const byte* in, int width, int height )
{
int i, j;
const byte* in_p;
byte* out, *out_p;
int row;
int newWidth, newHeight;
if( width < 1 || height < 1 || ( width + height == 2 ) )
{
return NULL;
}
row = width * 4;
newWidth = width >> 1;
newHeight = height >> 1;
if( !newWidth )
{
newWidth = 1;
}
if( !newHeight )
{
newHeight = 1;
}
out = ( byte* )R_StaticAlloc( newWidth * newHeight * 4, TAG_IMAGE );
out_p = out;
in_p = in;
width >>= 1;
height >>= 1;
typedef union
{
uint32 i;
byte b[4];
} convert_t;
if( width == 0 || height == 0 )
{
width += height; // get largest
for( i = 0 ; i < width ; i++, out_p += 4, in_p += 8 )
{
convert_t p1;
p1.b[0] = in_p[0];
p1.b[1] = in_p[1];
p1.b[2] = in_p[2];
p1.b[3] = in_p[3];
convert_t p2;
p2.b[0] = in_p[4];
p2.b[1] = in_p[5];
p2.b[2] = in_p[6];
p2.b[3] = in_p[7];
float c1[3];
r11g11b10f_to_float3( p1.i, c1 );
float c2[3];
r11g11b10f_to_float3( p2.i, c2 );
float rgb[3];
rgb[0] = ( c1[0] + c2[0] ) * 0.5f;
rgb[1] = ( c1[1] + c2[1] ) * 0.5f;
rgb[2] = ( c1[2] + c2[2] ) * 0.5f;
p1.i = float3_to_r11g11b10f( rgb );
out_p[0] = p1.b[0];
out_p[1] = p1.b[1];
out_p[2] = p1.b[2];
out_p[3] = p1.b[3];
//out_p[0] = ( in_p[0] + in_p[4] ) >> 1;
//out_p[1] = ( in_p[1] + in_p[5] ) >> 1;
//out_p[2] = ( in_p[2] + in_p[6] ) >> 1;
//out_p[3] = ( in_p[3] + in_p[7] ) >> 1;
}
return out;
}
for( i = 0 ; i < height ; i++, in_p += row )
{
for( j = 0 ; j < width ; j++, out_p += 4, in_p += 8 )
{
convert_t p1;
p1.b[0] = in_p[0];
p1.b[1] = in_p[1];
p1.b[2] = in_p[2];
p1.b[3] = in_p[3];
convert_t p2;
p2.b[0] = in_p[4];
p2.b[1] = in_p[5];
p2.b[2] = in_p[6];
p2.b[3] = in_p[7];
convert_t p3;
p3.b[0] = in_p[row + 0];
p3.b[1] = in_p[row + 1];
p3.b[2] = in_p[row + 2];
p3.b[3] = in_p[row + 3];
convert_t p4;
p4.b[0] = in_p[row + 4];
p4.b[1] = in_p[row + 5];
p4.b[2] = in_p[row + 6];
p4.b[3] = in_p[row + 7];
float c1[3];
r11g11b10f_to_float3( p1.i, c1 );
float c2[3];
r11g11b10f_to_float3( p2.i, c2 );
float c3[3];
r11g11b10f_to_float3( p3.i, c3 );
float c4[3];
r11g11b10f_to_float3( p4.i, c4 );
float rgb[3];
rgb[0] = ( c1[0] + c2[0] + c3[0] + c4[0] ) * 0.25f;
rgb[1] = ( c1[1] + c2[1] + c3[1] + c4[1] ) * 0.25f;
rgb[2] = ( c1[2] + c2[2] + c3[2] + c4[2] ) * 0.25f;
p1.i = float3_to_r11g11b10f( rgb );
out_p[0] = p1.b[0];
out_p[1] = p1.b[1];
out_p[2] = p1.b[2];
out_p[3] = p1.b[3];
//out_p[0] = ( in_p[0] + in_p[4] + in_p[row + 0] + in_p[row + 4] ) >> 2;
//out_p[1] = ( in_p[1] + in_p[5] + in_p[row + 1] + in_p[row + 5] ) >> 2;
//out_p[2] = ( in_p[2] + in_p[6] + in_p[row + 2] + in_p[row + 6] ) >> 2;
//out_p[3] = ( in_p[3] + in_p[7] + in_p[row + 3] + in_p[row + 7] ) >> 2;
}
}
return out;
}
// RB end
/*
==================
R_BlendOverTexture

View file

@ -1293,7 +1293,7 @@ void idMaterial::ParseFragmentMap( idLexer& src, newShaderStage_t* newStage )
if( !token.Icmp( "hdriMap" ) )
{
cubeMap = CF_PANORAMA;
td = TD_R11G11B10F;
td = TD_HDRI;
continue;
}
if( !token.Icmp( "nearest" ) )
@ -1832,7 +1832,7 @@ void idMaterial::ParseStage( idLexer& src, const textureRepeat_t trpDefault )
str = R_ParsePastImageProgram( src );
idStr::Copynz( imageName, str, sizeof( imageName ) );
cubeMap = CF_PANORAMA;
td = TD_R11G11B10F;
td = TD_HDRI;
continue;
}

View file

@ -1133,7 +1133,14 @@ CONSOLE_COMMAND_SHIP( bakeEnvironmentProbes, "Bake environment probes", NULL )
}
// generate .bimage file
globalImages->ImageFromFile( job->filename, TF_LINEAR, TR_CLAMP, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
if( job->outHeight == RADIANCE_OCTAHEDRON_SIZE )
{
globalImages->ImageFromFile( job->filename, TF_DEFAULT, TR_CLAMP, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
}
else
{
globalImages->ImageFromFile( job->filename, TF_LINEAR, TR_CLAMP, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
}
Mem_Free( job->outBuffer );

View file

@ -497,7 +497,8 @@ void idRenderWorldLocal::WriteLightGrid( idFile* fp, const LightGrid& lightGrid
{
const lightGridPoint_t* gridPoint = &lightGrid.lightGridPoints[i];
fp->WriteFloatString( "/* lgp %i */ %d ( %f %f %f )", i, ( int )gridPoint->valid, gridPoint->origin[0], gridPoint->origin[1], gridPoint->origin[2] );
//fp->WriteFloatString( "/* lgp %i */ %d ( %f %f %f )", i, ( int )gridPoint->valid, gridPoint->origin[0], gridPoint->origin[1], gridPoint->origin[2] );
fp->WriteFloatString( " %d ( %f %f %f )", ( int )gridPoint->valid, gridPoint->origin[0], gridPoint->origin[1], gridPoint->origin[2] );
#if STORE_LIGHTGRID_SHDATA
// spherical harmonic