diff --git a/src/engine/renderer/tr_image.cpp b/src/engine/renderer/tr_image.cpp index 563e4ec9e0..35c2c80a24 100644 --- a/src/engine/renderer/tr_image.cpp +++ b/src/engine/renderer/tr_image.cpp @@ -1611,6 +1611,60 @@ static const imageExtToLoaderMap_t imageLoaders[] = static int numImageLoaders = ARRAY_LEN( imageLoaders ); +/* +================= +R_FindImageLoader + +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 ) { + const FS::PakInfo* bestPak = nullptr; + int i; + + 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++ ) + { + std::string altName = Str::Format( "%s.%s", baseName, imageLoaders[i].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 = i; + } + + // DarkPlaces or Doom3 packages can ship alternative texture path in the form of + // dds/.dds + if ( bestPak == nullptr && !Q_stricmp( "dds", imageLoaders[i].ext ) ) + { + std::string prefixedName = Str::Format( "dds/%s.dds", baseName ); + bestPak = FS::PakPath::LocateFile( prefixedName ); + if ( bestPak != nullptr ) { + *prefix = "dds/"; + bestPak = pak; + bestLoader = i; + } + } + } + + return bestLoader; +} + +int R_FindImageLoader( const char *baseName ) { + // not used but required by R_FindImageLoader + const char *prefix; + + return R_FindImageLoader( baseName, &prefix ); +} + /* ================= R_LoadImage @@ -1682,13 +1736,7 @@ static void R_LoadImage( const char **buffer, byte **pic, int *width, int *heigh // a loader was found if ( i < numImageLoaders ) { - if ( *pic == nullptr ) - { - // loader failed, most likely because the file isn't there; - // try again without the extension - COM_StripExtension3( token, filename, MAX_QPATH ); - } - else + if ( *pic != nullptr ) { // something loaded return; @@ -1696,43 +1744,15 @@ static void R_LoadImage( const char **buffer, byte **pic, int *width, int *heigh } } - int bestLoader = -1; - const FS::PakInfo* bestPak = nullptr; - - // Darkplaces or Doom3 packages can ship alternative texture path in the form of - // dds/.dds - std::string altName = Str::Format("dds/%s.dds", filename); - bestPak = FS::PakPath::LocateFile(altName); - - // If this alternative path exists, it's expected to be loaded as the best one - // except when it goes against Daemon's rule to load the hardcoded one if exists - // because this dds alternative is only supported for compatibility with - // third-party content - if ( bestPak != nullptr ) { - LoadDDS( altName.c_str(), pic, width, height, numLayers, numMips, bits, alphaByte ); - return; - } - - // try and find a suitable match using all the image formats supported - // prioritize with the pak priority - for ( i = 0; i < numImageLoaders; i++ ) - { - std::string altName = Str::Format("%s.%s", filename, imageLoaders[i].ext); - const FS::PakInfo* pak = FS::PakPath::LocateFile(altName); + // the file isn't there, try again without the extension + COM_StripExtension3( token, filename, MAX_QPATH ); - // 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 = i; - } - } + const char *prefix; + int bestLoader = R_FindImageLoader( filename, &prefix ); if ( bestLoader >= 0 ) { - char *altName = va( "%s.%s", filename, imageLoaders[ bestLoader ].ext ); + char *altName = va( "%s%s.%s", prefix, filename, imageLoaders[ bestLoader ].ext ); imageLoaders[ bestLoader ].ImageLoader( altName, pic, width, height, numLayers, numMips, bits, alphaByte ); } } @@ -1938,6 +1958,22 @@ 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[] = +{ + { "crn", LoadCRN }, + { "ktx", LoadKTX }, +}; + +static int numCubeMapLoaders = ARRAY_LEN( cubeMapLoaders ); + image_t *R_FindCubeImage( const char *imageName, int bits, filterType_t filterType, wrapType_t wrapType ) { int i; @@ -1978,22 +2014,23 @@ image_t *R_FindCubeImage( const char *imageName, int bits, filterType_t f } } - // try to load .CRN cubemap - LoadCRN( buffer, pic, &width, &height, &numLayers, &numMips, &bits, 0 ); - if( numLayers == 6 && pic[0] ) { - numPicsToFree = 1; - goto createCubeImage; - } else { - R_FreeCubePics( pic, numLayers ); - } + char cubeMapBaseName[ MAX_QPATH ]; + COM_StripExtension3( buffer, cubeMapBaseName, sizeof( cubeMapBaseName ) ); - // try to load .KTX cubemap - LoadKTX( buffer, pic, &width, &height, &numLayers, &numMips, &bits, 0 ); - if( numLayers == 6 && pic[0] ) { - numPicsToFree = 1; - goto createCubeImage; - } else { - R_FreeCubePics( pic, numLayers ); + for ( i = 0; i < numCubeMapLoaders; i++ ) + { + std::string cubeMapName = Str::Format( "%s.%s", cubeMapBaseName, cubeMapLoaders[ i ].ext ); + if( R_FindImageLoader( cubeMapName.c_str() ) >= 0 ) + { + Log::Debug( "found %s cube map '%s'", cubeMapLoaders[ i ].ext, cubeMapBaseName ); + cubeMapLoaders[ i ].ImageLoader( cubeMapName.c_str(), pic, &width, &height, &numLayers, &numMips, &bits, 0 ); + if( numLayers == 6 && pic[0] ) { + numPicsToFree = 1; + goto createCubeImage; + } else { + R_FreeCubePics( pic, numLayers ); + } + } } for ( i = 0; i < 6; i++ ) diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 165dd65f70..1d894ae511 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -3150,6 +3150,7 @@ static inline void halfToFloat( const f16vec4_t in, vec4_t out ) void R_InitImages(); void R_ShutdownImages(); + int R_FindImageLoader( const char *baseName ); image_t *R_FindImageFile( const char *name, int bits, filterType_t filterType, wrapType_t wrapType ); image_t *R_FindCubeImage( const char *name, int bits, filterType_t filterType, wrapType_t wrapType );