diff --git a/README b/README index 0d50d1ae..2323e6c5 100644 --- a/README +++ b/README @@ -314,10 +314,25 @@ SDL Keyboard Differences PNG support ioquake3 supports the use of PNG (Portable Network Graphic) images as - textures. It should be noted that the use of such images in a maps will + textures. It should be noted that the use of such images in a map will result in missing placeholder textures where the map is used with the id Quake 3 client or earlier versions of ioquake3. + Recent versions of GtkRadiant and q3map2 support PNG images without + modification. However GtkRadiant is not aware that PNG textures are supported + by ioquake3. To change this behaviour open the file 'q3.game' in the 'games' + directory of the GtkRadiant base directory with an editor and change the + line: + + texturetypes="tga jpg" + + to + + texturetypes="tga jpg png" + + Restart GtkRadiant and PNG textures are now available. + + ------------------------------------------------------------- Contributing ----- Please send all patches to bugzilla (https://bugzilla.icculus.org), or join the diff --git a/code/qcommon/files.c b/code/qcommon/files.c index 8a056d57..4a909e37 100644 --- a/code/qcommon/files.c +++ b/code/qcommon/files.c @@ -1207,7 +1207,6 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF } } - Com_DPrintf ("Can't find %s\n", filename); #ifdef FS_MISSING if (missingFiles) { fprintf(missingFiles, "%s\n", filename); diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index b30688a6..a68b283b 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -53,6 +53,28 @@ char *COM_SkipPath (char *pathname) return last; } +/* +============ +COM_GetExtension +============ +*/ +const char *COM_GetExtension( const char *name ) { + int length, i; + + length = strlen(name)-1; + i = length; + + while (name[i] != '.') + { + i--; + if (name[i] == '/' || i == 0) + return ""; // no extension + } + + return &name[i+1]; +} + + /* ============ COM_StripExtension diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index e3a062ac..fcd48e02 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -599,6 +599,7 @@ int Q_isnan( float x ); float Com_Clamp( float min, float max, float value ); char *COM_SkipPath( char *pathname ); +const char *COM_GetExtension( const char *name ); void COM_StripExtension(const char *in, char *out, int destsize); void COM_DefaultExtension( char *path, int maxSize, const char *extension ); diff --git a/code/renderer/tr_image.c b/code/renderer/tr_image.c index 609b8b26..016b6f02 100644 --- a/code/renderer/tr_image.c +++ b/code/renderer/tr_image.c @@ -4376,6 +4376,27 @@ static void LoadPNG(const char *name, byte **pic, int *width, int *height) //=================================================================== +typedef struct +{ + char *ext; + void (*ImageLoader)( const char *, unsigned char **, int *, int * ); +} imageExtToLoaderMap_t; + +// Note that the ordering indicates the order of preference used +// when there are multiple images of different formats available +static imageExtToLoaderMap_t imageLoaders[ ] = +{ + { "tga", LoadTGA }, + { "jpg", LoadJPG }, + { "jpeg", LoadJPG }, + { "png", LoadPNG }, + { "pcx", LoadPCX32 }, + { "bmp", LoadBMP } +}; + +static int numImageLoaders = sizeof( imageLoaders ) / + sizeof( imageLoaders[ 0 ] ); + /* ================= R_LoadImage @@ -4384,53 +4405,71 @@ Loads any of the supported image types into a cannonical 32 bit format. ================= */ -void R_LoadImage( const char *name, byte **pic, int *width, int *height ) { - int len; +void R_LoadImage( const char *name, byte **pic, int *width, int *height ) +{ + qboolean orgNameFailed = qfalse; + int i; + char localName[ MAX_QPATH ]; + const char *ext; *pic = NULL; *width = 0; *height = 0; - len = strlen(name); - if (len<5) { - return; - } + Q_strncpyz( localName, name, MAX_QPATH ); - if ( !Q_stricmp( name+len-4, ".tga" ) ) { - LoadTGA( name, pic, width, height ); + ext = COM_GetExtension( localName ); - // This is a hack to get around the fact that some - // baseq3 shaders refer to tga files where the images - // are actually jpgs - if (!*pic) { - // try jpg in place of tga - char altname[MAX_QPATH]; + if( *ext ) + { + // Look for the correct loader and use it + for( i = 0; i < numImageLoaders; i++ ) + { + if( !Q_stricmp( ext, imageLoaders[ i ].ext ) ) + { + // Load + imageLoaders[ i ].ImageLoader( localName, pic, width, height ); + break; + } + } - strcpy( altname, name ); - len = strlen( altname ); - altname[len-3] = 'j'; - altname[len-2] = 'p'; - altname[len-1] = 'g'; - - ri.Printf( PRINT_DEVELOPER, "WARNING: %s failed, trying %s\n", name, altname ); - LoadJPG( altname, pic, width, height ); + // A loader was found + if( i < numImageLoaders ) + { + if( *pic == NULL ) + { + // Loader failed, most likely because the file isn't there; + // try again without the extension + orgNameFailed = qtrue; + COM_StripExtension( name, localName, MAX_QPATH ); + } + else + { + // Something loaded + return; + } } } - else if ( !Q_stricmp(name+len-4, ".pcx") ) + + // Try and find a suitable match using all + // the image formats supported + for( i = 0; i < numImageLoaders; i++ ) { - LoadPCX32( name, pic, width, height ); - } - else if ( !Q_stricmp( name+len-4, ".bmp" ) ) - { - LoadBMP( name, pic, width, height ); - } - else if ( !Q_stricmp( name+len-4, ".jpg" ) ) - { - LoadJPG( name, pic, width, height ); - } - else if ( !Q_stricmp( name+len-4, ".png" ) ) - { - LoadPNG( name, pic, width, height ); + char *altName = va( "%s.%s", localName, imageLoaders[ i ].ext ); + + // Load + imageLoaders[ i ].ImageLoader( altName, pic, width, height ); + + if( *pic ) + { + if( orgNameFailed ) + { + ri.Printf( PRINT_DEVELOPER, "WARNING: %s not present, using %s instead\n", + name, altName ); + } + + break; + } } } diff --git a/code/renderer/tr_shader.c b/code/renderer/tr_shader.c index edcf2bcb..3f122692 100644 --- a/code/renderer/tr_shader.c +++ b/code/renderer/tr_shader.c @@ -2416,7 +2416,6 @@ most world construction surfaces. */ shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ) { char strippedName[MAX_QPATH]; - char fileName[MAX_QPATH]; int i, hash; char *shaderText; image_t *image; @@ -2494,13 +2493,11 @@ shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImag // // if not defined in the in-memory shader descriptions, - // look for a single TGA, BMP, or PCX + // look for a single supported image file // - Q_strncpyz( fileName, name, sizeof( fileName ) ); - COM_DefaultExtension( fileName, sizeof( fileName ), ".tga" ); - image = R_FindImageFile( fileName, mipRawImage, mipRawImage, mipRawImage ? GL_REPEAT : GL_CLAMP ); + image = R_FindImageFile( name, mipRawImage, mipRawImage, mipRawImage ? GL_REPEAT : GL_CLAMP ); if ( !image ) { - ri.Printf( PRINT_DEVELOPER, "Couldn't find image for shader %s\n", name ); + ri.Printf( PRINT_DEVELOPER, "Couldn't find image file for shader %s\n", name ); shader.defaultShader = qtrue; return FinishShader(); }