Skip to content

Commit

Permalink
tr_image: do not use R_FindImageLoader with cube maps, test multifile…
Browse files Browse the repository at this point in the history
… cubemaps first (or preview may be loaded as cubemap instead)

- do not use R_FindImageLoader with cube maps
- test multifile cubemaps first (or preview may be loaded as cubemap instead)
- reword image loader lookup code
  • Loading branch information
illwieckz committed Oct 26, 2024
1 parent 7d04993 commit 4a9b464
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 61 deletions.
147 changes: 88 additions & 59 deletions src/engine/renderer/tr_image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1616,15 +1616,17 @@ image_t *R_Create3DImage( const char *name, const byte *pic, int width, int heig
return image;
}

struct imageExtToLoaderMap_t
using imageLoader_t = void( * )( const char *, unsigned char **, int *, int *, int *, int *, int *, byte );

struct imageExtLoader_t
{
const char *ext;
void ( *ImageLoader )( const char *, unsigned char **, int *, int *, int *, int *, int *, byte );
imageLoader_t imageLoader;
};

// Note that the ordering indicates the order of preference used
// when there are multiple images of different formats available
static const imageExtToLoaderMap_t imageLoaders[] =
static const imageExtLoader_t imageLoaders[] =
{
{ "webp", LoadWEBP },
{ "png", LoadPNG },
Expand All @@ -1636,8 +1638,6 @@ static const imageExtToLoaderMap_t imageLoaders[] =
{ "ktx", LoadKTX },
};

static int numImageLoaders = ARRAY_LEN( imageLoaders );

/*
=================
R_FindImageLoader
Expand All @@ -1646,17 +1646,17 @@ Finds and returns an image loader for a given basename,
tells the extra prefix that may be required to load the image.
=================
*/
static int R_FindImageLoader( const char *baseName, const char **prefix ) {
static const imageExtLoader_t* R_FindImageLoader( const char *baseName, const char **prefix ) {
const FS::PakInfo* bestPak = nullptr;
int i;
const imageExtLoader_t* bestLoader = nullptr;

int bestLoader = -1;
*prefix = "";

// try and find a suitable match using all the image formats supported
// prioritize with the pak priority
for ( i = 0; i < numImageLoaders; i++ )
for ( const imageExtLoader_t &loader : imageLoaders )
{
std::string altName = Str::Format( "%s.%s", baseName, imageLoaders[i].ext );
std::string altName = Str::Format( "%s.%s", baseName, loader.ext );
const FS::PakInfo* pak = FS::PakPath::LocateFile( altName );

// We found a file and its pak is better than the best pak we have
Expand All @@ -1665,37 +1665,37 @@ static int R_FindImageLoader( const char *baseName, const char **prefix ) {
if ( pak != nullptr && ( bestPak == nullptr || pak < bestPak ) )
{
bestPak = pak;
bestLoader = i;
bestLoader = &loader;
}

if( pak == nullptr ) {
if ( FS::HomePath::FileExists( altName ) ) {
bestLoader = i;
bestLoader = &loader;
}
}

// DarkPlaces or Doom3 packages can ship alternative texture path in the form of
// dds/<path without ext>.dds
if ( bestPak == nullptr && !Q_stricmp( "dds", imageLoaders[i].ext ) )
if ( bestPak == nullptr && !Q_stricmp( "dds", loader.ext ) )
{
std::string prefixedName = Str::Format( "dds/%s.dds", baseName );
bestPak = FS::PakPath::LocateFile( prefixedName );
if ( bestPak != nullptr ) {
*prefix = "dds/";
bestPak = pak;
bestLoader = i;
bestLoader = &loader;
}
}
}

return bestLoader;
}

int R_FindImageLoader( const char *baseName ) {
bool R_HasImageLoader( const char *baseName ) {
// not used but required by R_FindImageLoader
const char *prefix;

return R_FindImageLoader( baseName, &prefix );
return R_FindImageLoader( baseName, &prefix ) != nullptr;
}

/*
Expand All @@ -1722,7 +1722,6 @@ static void R_LoadImage( const char **buffer, byte **pic, int *width, int *heigh
return;
}

int i;
const char *ext;
char filename[ MAX_QPATH ];
byte alphaByte;
Expand All @@ -1738,9 +1737,10 @@ static void R_LoadImage( const char **buffer, byte **pic, int *width, int *heigh
if ( *ext )
{
// look for the correct loader and use it
for ( i = 0; i < numImageLoaders; i++ )
bool found = false;
for ( const auto &loader : imageLoaders )
{
if ( !Q_stricmp( ext, imageLoaders[ i ].ext ) )
if ( !Q_stricmp( ext, loader.ext ) )
{
// do not complain on missing file if extension is hardcoded to a wrong one
// since file can exist with another extension and it will tested right after
Expand All @@ -1750,15 +1750,16 @@ static void R_LoadImage( const char **buffer, byte **pic, int *width, int *heigh
if ( FS::PakPath::FileExists( filename ) )
{
// load
imageLoaders[ i ].ImageLoader( filename, pic, width, height, numLayers, numMips, bits, alphaByte );
loader.imageLoader( filename, pic, width, height, numLayers, numMips, bits, alphaByte );
}
// we still have to break because a loader was found, so we can strip the extension
found = true;
break;
}
}

// a loader was found
if ( i < numImageLoaders )
if ( found )
{
if ( *pic != nullptr )
{
Expand All @@ -1772,21 +1773,21 @@ static void R_LoadImage( const char **buffer, byte **pic, int *width, int *heigh
// and it may be possible the file has a dot in its name that was mistakenly
// taken as an extension
const char *prefix;
int bestLoader = R_FindImageLoader( filename, &prefix );
const imageExtLoader_t* loader = R_FindImageLoader( filename, &prefix );

if ( *ext && bestLoader == -1 )
if ( *ext && loader )
{
// if there is no file with such extension
// or there is no codec available for this file format
COM_StripExtension3( token, filename, sizeof(filename) );

bestLoader = R_FindImageLoader( filename, &prefix );
loader = R_FindImageLoader( filename, &prefix );
}

if ( bestLoader >= 0 )
if ( loader )
{
char *altName = va( "%s%s.%s", prefix, filename, imageLoaders[ bestLoader ].ext );
imageLoaders[ bestLoader ].ImageLoader( altName, pic, width, height, numLayers, numMips, bits, alphaByte );
char *altName = va( "%s%s.%s", prefix, filename, loader->ext );
loader->imageLoader( altName, pic, width, height, numLayers, numMips, bits, alphaByte );
}
}

Expand Down Expand Up @@ -2009,15 +2010,9 @@ static void R_FreeCubePics( byte **pic, int count )
}
}

struct cubeMapLoader_t
{
const char *ext;
void ( *ImageLoader )( const char *, unsigned char **, int *, int *, int *, int *, int *, byte );
};

// Note that the ordering indicates the order of preference used
// when there are multiple images of different formats available
static const cubeMapLoader_t cubeMapLoaders[] =
static const imageExtLoader_t cubeMapLoaders[] =
{
{ "crn", LoadCRN },
{ "ktx", LoadKTX },
Expand Down Expand Up @@ -2075,9 +2070,37 @@ struct face_t
int height;
};

static const imageExtLoader_t* R_FindCubeImageLoader( const char *baseName )
{
const FS::PakInfo* bestPak = nullptr;
const imageExtLoader_t* bestLoader = nullptr;

for ( const auto &loader : cubeMapLoaders )
{
std::string altName = Str::Format( "%s.%s", baseName, loader.ext );
const FS::PakInfo* pak = FS::PakPath::LocateFile( altName );

// We found a file and its pak is better than the best pak we have
// this relies on how the filesystem works internally and should be moved
// to a more explicit interface once there is one. (FIXME)
if ( pak != nullptr && ( bestPak == nullptr || pak < bestPak ) )
{
bestPak = pak;
bestLoader = &loader;
}

if ( pak == nullptr ) {
if ( FS::HomePath::FileExists( altName ) ) {
bestLoader = &loader;
}
}
}

return bestLoader;
}

image_t *R_FindCubeImage( const char *imageName, imageParams_t &imageParams )
{
int i, j;
image_t *image = nullptr;
int width = 0, height = 0, numLayers = 0, numMips = 0;
byte *pic[ MAX_TEXTURE_MIPS * MAX_TEXTURE_LAYERS ];
Expand All @@ -2102,28 +2125,9 @@ image_t *R_FindCubeImage( const char *imageName, imageParams_t &imageParams )
}
}

char cubeMapBaseName[ MAX_QPATH ];
COM_StripExtension3( buffer, cubeMapBaseName, sizeof( cubeMapBaseName ) );

for ( const cubeMapLoader_t &loader : cubeMapLoaders )
{
std::string cubeMapName = Str::Format( "%s.%s", cubeMapBaseName, loader.ext );
if( R_FindImageLoader( cubeMapBaseName ) >= 0 )
{
Log::Debug( "found %s cube map '%s'", loader.ext, cubeMapBaseName );
loader.ImageLoader( cubeMapName.c_str(), pic, &width, &height, &numLayers, &numMips, &imageParams.bits, 0 );
// Look for 6-files skybox.

if( numLayers == 6 && pic[0] ) {
image = R_CreateCubeImage( ( char * ) buffer, ( const byte ** ) pic, width, height, imageParams );
R_FreeCubePics( pic, 1 );
return image;
}

R_FreeCubePics( pic, numLayers );
}
}

for ( i = 0; i < 6; i++ )
for ( int i = 0; i < 6; i++ )
{
pic[ i ] = nullptr;
}
Expand All @@ -2133,7 +2137,8 @@ image_t *R_FindCubeImage( const char *imageName, imageParams_t &imageParams )
int greatestEdge = 0;
face_t faces[6];

for ( i = 0; i < 6; i++ )
int i = 0;
for ( ; i < 6; i++ )
{
Com_sprintf( filename, sizeof( filename ), "%s%s%s", buffer, format.sep, format.suffixes[ i ] );

Expand Down Expand Up @@ -2179,8 +2184,7 @@ image_t *R_FindCubeImage( const char *imageName, imageParams_t &imageParams )

if ( i == 6 )
{

for ( j = 0; j < 6; j++ )
for ( int j = 0; j < 6; j++ )
{
width = faces[ j ].width;
height = faces[ j ].height;
Expand Down Expand Up @@ -2232,6 +2236,31 @@ image_t *R_FindCubeImage( const char *imageName, imageParams_t &imageParams )
R_FreeCubePics( pic, i );
}

// Look for 6-faces single-file DDS/KTX skybox.
// TODO: Respect explicit extension.

char baseName[ MAX_QPATH ];
COM_StripExtension3( buffer, baseName, sizeof( baseName ) );

const imageExtLoader_t *loader = R_FindCubeImageLoader( baseName );

if ( loader )
{
std::string altName = Str::Format( "%s.%s", baseName, loader->ext );

Log::Debug( "found %s cube map '%s' candidate: %s", loader->ext, baseName, altName );
loader->imageLoader( altName.c_str(), pic, &width, &height, &numLayers, &numMips, &imageParams.bits, 0 );

if ( numLayers == 6 && pic[0] ) {
Log::Debug( "found %s cube map '%s': %s", loader->ext, baseName, altName );
image = R_CreateCubeImage( ( char * ) buffer, ( const byte ** ) pic, width, height, imageParams );
R_FreeCubePics( pic, 1 );
return image;
}

R_FreeCubePics( pic, numLayers );
}

return nullptr;
}

Expand Down
2 changes: 1 addition & 1 deletion src/engine/renderer/tr_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -3265,7 +3265,7 @@ inline bool checkGLErrors()
void R_InitImages();
void R_ShutdownImages();

int R_FindImageLoader( const char *baseName );
bool R_HasImageLoader( const char *baseName );
image_t *R_FindImageFile( const char *name, imageParams_t &imageParams );
image_t *R_FindCubeImage( const char *name, imageParams_t &imageParams );

Expand Down
2 changes: 1 addition & 1 deletion src/engine/renderer/tr_shader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1965,7 +1965,7 @@ void LoadExtraMaps( shaderStage_t *stage, const char *colorMapName )
for ( const extraMapParser_t parser: dpExtraMapParsers )
{
std::string extraMapName = Str::Format( "%s%s", colorMapBaseName, parser.suffix );
if( R_FindImageLoader( extraMapName.c_str() ) >= 0 )
if ( R_HasImageLoader( extraMapName.c_str() ) )
{
foundExtraMap = true;
Log::Debug( "found extra %s '%s'", parser.description, extraMapName.c_str() );
Expand Down

0 comments on commit 4a9b464

Please sign in to comment.