mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-05-31 08:50:54 +00:00
Added support for loading .png image files as textures and changed screenshot command to write in .png format
This commit is contained in:
parent
160a4dd2aa
commit
14f87fe9db
33 changed files with 34444 additions and 49 deletions
|
@ -3,6 +3,7 @@
|
|||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2012-2014 Robert Beckebans
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
|
@ -605,8 +606,264 @@ static void LoadJPG( const char* filename, unsigned char** pic, int* width, int*
|
|||
/* And we're done! */
|
||||
}
|
||||
|
||||
// RB begin
|
||||
/*
|
||||
=========================================================
|
||||
|
||||
PNG LOADING
|
||||
|
||||
=========================================================
|
||||
*/
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../libs/png/png.h"
|
||||
|
||||
|
||||
static void png_Error( png_structp pngPtr, png_const_charp msg )
|
||||
{
|
||||
common->FatalError( "%s", msg );
|
||||
}
|
||||
|
||||
static void png_Warning( png_structp pngPtr, png_const_charp msg )
|
||||
{
|
||||
common->Warning( "%s", msg );
|
||||
}
|
||||
|
||||
static void png_ReadData( png_structp pngPtr, png_bytep data, png_size_t length )
|
||||
{
|
||||
memcpy( data, ( byte* )pngPtr->io_ptr, length );
|
||||
|
||||
pngPtr->io_ptr = ( ( byte* ) pngPtr->io_ptr ) + length;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
LoadPNG
|
||||
=============
|
||||
*/
|
||||
static void LoadPNG( const char* filename, unsigned char** pic, int* width, int* height, ID_TIME_T* timestamp )
|
||||
{
|
||||
byte* fbuffer;
|
||||
|
||||
if( !pic )
|
||||
{
|
||||
fileSystem->ReadFile( filename, NULL, timestamp );
|
||||
return; // just getting timestamp
|
||||
}
|
||||
|
||||
*pic = NULL;
|
||||
|
||||
//
|
||||
// load the file
|
||||
//
|
||||
int fileSize = fileSystem->ReadFile( filename, ( void** )&fbuffer, timestamp );
|
||||
if( !fbuffer )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// create png_struct with the custom error handlers
|
||||
png_structp pngPtr = png_create_read_struct( PNG_LIBPNG_VER_STRING, ( png_voidp ) NULL, png_Error, png_Warning );
|
||||
if( !pngPtr )
|
||||
{
|
||||
common->Error( "LoadPNG( %s ): png_create_read_struct failed", filename );
|
||||
}
|
||||
|
||||
// allocate the memory for image information
|
||||
png_infop infoPtr = png_create_info_struct( pngPtr );
|
||||
if( !infoPtr )
|
||||
{
|
||||
common->Error( "LoadPNG( %s ): png_create_info_struct failed", filename );
|
||||
}
|
||||
|
||||
png_set_read_fn( pngPtr, fbuffer, png_ReadData );
|
||||
|
||||
png_set_sig_bytes( pngPtr, 0 );
|
||||
|
||||
png_read_info( pngPtr, infoPtr );
|
||||
|
||||
png_uint_32 pngWidth, pngHeight;
|
||||
int bitDepth, colorType, interlaceType;
|
||||
png_get_IHDR( pngPtr, infoPtr, &pngWidth, &pngHeight, &bitDepth, &colorType, &interlaceType, NULL, NULL );
|
||||
|
||||
// 16 bit -> 8 bit
|
||||
png_set_strip_16( pngPtr );
|
||||
|
||||
// 1, 2, 4 bit -> 8 bit
|
||||
if( bitDepth < 8 )
|
||||
{
|
||||
png_set_packing( pngPtr );
|
||||
}
|
||||
|
||||
#if 1
|
||||
if( colorType & PNG_COLOR_MASK_PALETTE )
|
||||
{
|
||||
png_set_expand( pngPtr );
|
||||
}
|
||||
|
||||
if( !( colorType & PNG_COLOR_MASK_COLOR ) )
|
||||
{
|
||||
png_set_gray_to_rgb( pngPtr );
|
||||
}
|
||||
|
||||
#else
|
||||
if( colorType == PNG_COLOR_TYPE_PALETTE )
|
||||
{
|
||||
png_set_palette_to_rgb( pngPtr );
|
||||
}
|
||||
|
||||
if( colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8 )
|
||||
{
|
||||
png_set_expand_gray_1_2_4_to_8( pngPtr );
|
||||
}
|
||||
#endif
|
||||
|
||||
// set paletted or RGB images with transparency to full alpha so we get RGBA
|
||||
if( png_get_valid( pngPtr, infoPtr, PNG_INFO_tRNS ) )
|
||||
{
|
||||
png_set_tRNS_to_alpha( pngPtr );
|
||||
}
|
||||
|
||||
// make sure every pixel has an alpha value
|
||||
if( !( colorType & PNG_COLOR_MASK_ALPHA ) )
|
||||
{
|
||||
png_set_filler( pngPtr, 255, PNG_FILLER_AFTER );
|
||||
}
|
||||
|
||||
png_read_update_info( pngPtr, infoPtr );
|
||||
|
||||
byte* out = ( byte* )R_StaticAlloc( pngWidth * pngHeight * 4 );
|
||||
|
||||
*pic = out;
|
||||
*width = pngWidth;
|
||||
*height = pngHeight;
|
||||
|
||||
png_uint_32 rowBytes = png_get_rowbytes( pngPtr, infoPtr );
|
||||
|
||||
png_bytep* rowPointers = ( png_bytep* ) R_StaticAlloc( sizeof( png_bytep ) * pngHeight );
|
||||
for( png_uint_32 row = 0; row < pngHeight; row++ )
|
||||
{
|
||||
rowPointers[row] = ( png_bytep )( out + ( row * pngWidth * 4 ) );
|
||||
}
|
||||
|
||||
png_read_image( pngPtr, rowPointers );
|
||||
|
||||
png_read_end( pngPtr, infoPtr );
|
||||
|
||||
png_destroy_read_struct( &pngPtr, &infoPtr, NULL );
|
||||
|
||||
R_StaticFree( rowPointers );
|
||||
Mem_Free( fbuffer );
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
static int png_compressedSize = 0;
|
||||
static void png_WriteData( png_structp pngPtr, png_bytep data, png_size_t length )
|
||||
{
|
||||
memcpy( ( byte* )pngPtr->io_ptr, data, length );
|
||||
|
||||
pngPtr->io_ptr = ( ( byte* ) pngPtr->io_ptr ) + length;
|
||||
|
||||
png_compressedSize += length;
|
||||
}
|
||||
|
||||
static void png_FlushData( png_structp pngPtr ) { }
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
R_WritePNG
|
||||
================
|
||||
*/
|
||||
void R_WritePNG( const char* filename, const byte* data, int bytesPerPixel, int width, int height, bool flipVertical, const char* basePath )
|
||||
{
|
||||
png_structp pngPtr = png_create_write_struct( PNG_LIBPNG_VER_STRING, NULL, png_Error, png_Warning );
|
||||
if( !pngPtr )
|
||||
{
|
||||
common->Error( "R_WritePNG( %s ): png_create_write_struct failed", filename );
|
||||
}
|
||||
|
||||
png_infop infoPtr = png_create_info_struct( pngPtr );
|
||||
if( !infoPtr )
|
||||
{
|
||||
common->Error( "R_WritePNG( %s ): png_create_info_struct failed", filename );
|
||||
}
|
||||
|
||||
png_compressedSize = 0;
|
||||
byte* buffer = ( byte* ) Mem_Alloc( width * height * bytesPerPixel, TAG_TEMP );
|
||||
png_set_write_fn( pngPtr, buffer, png_WriteData, png_FlushData );
|
||||
|
||||
if( bytesPerPixel == 4 )
|
||||
{
|
||||
png_set_IHDR( pngPtr, infoPtr, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT );
|
||||
}
|
||||
else if( bytesPerPixel == 3 )
|
||||
{
|
||||
png_set_IHDR( pngPtr, infoPtr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT );
|
||||
}
|
||||
else
|
||||
{
|
||||
common->Error( "R_WritePNG( %s ): bytesPerPixel = %i not supported", filename, bytesPerPixel );
|
||||
}
|
||||
|
||||
// write header
|
||||
png_write_info( pngPtr, infoPtr );
|
||||
|
||||
png_bytep* rowPointers = ( png_bytep* ) Mem_Alloc( sizeof( png_bytep ) * height, TAG_TEMP );
|
||||
|
||||
if( !flipVertical )
|
||||
{
|
||||
for( int row = 0, flippedRow = height - 1; row < height; row++, flippedRow-- )
|
||||
{
|
||||
rowPointers[flippedRow] = ( png_bytep )( data + ( row * width * bytesPerPixel ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int row = 0; row < height; row++ )
|
||||
{
|
||||
rowPointers[row] = ( png_bytep )( data + ( row * width * bytesPerPixel ) );
|
||||
}
|
||||
}
|
||||
|
||||
png_write_image( pngPtr, rowPointers );
|
||||
png_write_end( pngPtr, infoPtr );
|
||||
|
||||
png_destroy_write_struct( &pngPtr, &infoPtr );
|
||||
|
||||
Mem_Free( rowPointers );
|
||||
|
||||
fileSystem->WriteFile( filename, buffer, png_compressedSize, basePath );
|
||||
|
||||
Mem_Free( buffer );
|
||||
}
|
||||
// RB end
|
||||
|
||||
//===================================================================
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* ext;
|
||||
void ( *ImageLoader )( const char* filename, unsigned char** pic, int* width, int* height, ID_TIME_T* timestamp );
|
||||
} imageExtToLoader_t;
|
||||
|
||||
static imageExtToLoader_t imageLoaders[] =
|
||||
{
|
||||
{"png", LoadPNG},
|
||||
{"tga", LoadTGA},
|
||||
{"jpg", LoadJPG},
|
||||
};
|
||||
|
||||
static const int numImageLoaders = sizeof( imageLoaders ) / sizeof( imageLoaders[0] );
|
||||
|
||||
/*
|
||||
=================
|
||||
R_LoadImage
|
||||
|
@ -662,22 +919,42 @@ void R_LoadImage( const char* cname, byte** pic, int* width, int* height, ID_TIM
|
|||
name.ToLower();
|
||||
idStr ext;
|
||||
name.ExtractFileExtension( ext );
|
||||
idStr origName = name;
|
||||
|
||||
if( ext == "tga" )
|
||||
// RB begin
|
||||
if( !ext.IsEmpty() )
|
||||
{
|
||||
LoadTGA( name.c_str(), pic, width, height, timestamp ); // try tga first
|
||||
if( ( pic && *pic == 0 ) || ( timestamp && *timestamp == -1 ) ) //-V595
|
||||
int i;
|
||||
for( i = 0; i < numImageLoaders; i++ )
|
||||
{
|
||||
name.StripFileExtension();
|
||||
name.DefaultFileExtension( ".jpg" );
|
||||
LoadJPG( name.c_str(), pic, width, height, timestamp );
|
||||
if( !ext.Icmp( imageLoaders[i].ext ) )
|
||||
{
|
||||
imageLoaders[i].ImageLoader( name.c_str(), pic, width, height, timestamp );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( i < numImageLoaders )
|
||||
{
|
||||
if( pic && *pic == NULL )
|
||||
{
|
||||
// image with the specified extension was not found so try all formats
|
||||
for( i = 0; i < numImageLoaders; i++ )
|
||||
{
|
||||
name.SetFileExtension( imageLoaders[i].ext );
|
||||
imageLoaders[i].ImageLoader( name.c_str(), pic, width, height, timestamp );
|
||||
|
||||
if( pic && *pic != NULL )
|
||||
{
|
||||
//common->Warning("image %s failed to load, using %s instead", origName.c_str(), name.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( ext == "jpg" )
|
||||
{
|
||||
LoadJPG( name.c_str(), pic, width, height, timestamp );
|
||||
}
|
||||
|
||||
// RB end
|
||||
|
||||
if( ( width && *width < 1 ) || ( height && *height < 1 ) )
|
||||
{
|
||||
if( pic && *pic )
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue