* unlimit MAX_IMAGES

This commit is contained in:
Garux 2021-10-06 10:51:32 +03:00
parent 2602c48a18
commit 9660fbb6f1
7 changed files with 90 additions and 148 deletions

View File

@ -1127,7 +1127,7 @@ void LoadTGA( const char *name, byte **pixels, int *width, int *height ){
WriteTGA WriteTGA
================ ================
*/ */
void WriteTGA( const char *filename, byte *data, int width, int height ) { void WriteTGA( const char *filename, const byte *data, int width, int height ) {
byte *buffer; byte *buffer;
int i; int i;
int c; int c;

View File

@ -38,7 +38,7 @@ void Save256Image( const char *name, byte *pixels, byte *palette,
void LoadTGA( const char *filename, byte **pixels, int *width, int *height ); void LoadTGA( const char *filename, byte **pixels, int *width, int *height );
void LoadTGABuffer( const byte *buffer, const byte* enddata, byte **pic, int *width, int *height ); void LoadTGABuffer( const byte *buffer, const byte* enddata, byte **pic, int *width, int *height );
void WriteTGA( const char *filename, byte *data, int width, int height ); void WriteTGA( const char *filename, const byte *data, int width, int height );
void WriteTGAGray( const char *filename, byte *data, int width, int height ); void WriteTGAGray( const char *filename, byte *data, int width, int height );
int LoadJPGBuff( void *src_buffer, int src_size, unsigned char **pic, int *width, int *height ); int LoadJPGBuff( void *src_buffer, int src_size, unsigned char **pic, int *width, int *height );

View File

@ -246,8 +246,8 @@ static void ConvertShader( FILE *f, const bspShader_t& shader ){
} }
/* set bitmap filename */ /* set bitmap filename */
if ( si->shaderImage->filename[ 0 ] != '*' ) { if ( si->shaderImage->filename.c_str()[ 0 ] != '*' ) {
strcpy( filename, si->shaderImage->filename ); strcpy( filename, si->shaderImage->filename.c_str() );
} }
else{ else{
sprintf( filename, "%s.tga", si->shader.c_str() ); sprintf( filename, "%s.tga", si->shader.c_str() );

View File

@ -155,8 +155,8 @@ static void ConvertShaderToMTL( FILE *f, const bspShader_t& shader ){
} }
/* set bitmap filename */ /* set bitmap filename */
if ( si->shaderImage->filename[ 0 ] != '*' ) { if ( si->shaderImage->filename.c_str()[ 0 ] != '*' ) {
strcpy( filename, si->shaderImage->filename ); strcpy( filename, si->shaderImage->filename.c_str() );
} }
else{ else{
sprintf( filename, "%s.tga", si->shader.c_str() ); sprintf( filename, "%s.tga", si->shader.c_str() );

View File

@ -223,57 +223,18 @@ static void LoadPNGBuffer( byte *buffer, int size, byte **pixels, int *width, in
/* static std::forward_list<image_t> images;
ImageInit()
implicitly called by every function to set up image list
*/
static void ImageInit( void ){ static struct construct_default_image
if ( numImages <= 0 ) { {
/* clear images (fixme: this could theoretically leak) */ construct_default_image(){
memset( images, 0, sizeof( images ) ); image_t img;
img.name = img.filename = DEFAULT_IMAGE;
/* generate *bogus image */ img.width = img.height = 64;
images[ 0 ].name = copystring( DEFAULT_IMAGE ); img.pixels = void_ptr( memset( safe_malloc( 64 * 64 * 4 ), 255, 64 * 64 * 4 ) );
images[ 0 ].filename = copystring( DEFAULT_IMAGE ); images.emplace_front( std::move( img ) );
images[ 0 ].width = 64;
images[ 0 ].height = 64;
images[ 0 ].refCount = 1;
images[ 0 ].pixels = safe_malloc( 64 * 64 * 4 );
memset( images[ 0 ].pixels, 255, 64 * 64 * 4 );
} }
} } s_construct_default_image;
/*
ImageFree()
frees an rgba image
*/
void ImageFree( image_t *image ){
/* dummy check */
if ( image == NULL ) {
return;
}
/* decrement refcount */
image->refCount--;
/* free? */
if ( image->refCount <= 0 ) {
free( image->name );
image->name = NULL;
free( image->filename );
image->filename = NULL;
free( image->pixels );
image->width = 0;
image->height = 0;
numImages--;
}
}
/* /*
ImageFind() ImageFind()
@ -281,20 +242,17 @@ void ImageFree( image_t *image ){
name is name without extension, as in images[ i ].name name is name without extension, as in images[ i ].name
*/ */
image_t *ImageFind( const char *name ){ static const image_t *ImageFind( const char *name ){
/* init */
ImageInit();
/* dummy check */ /* dummy check */
if ( strEmptyOrNull( name ) ) { if ( strEmptyOrNull( name ) ) {
return NULL; return NULL;
} }
/* search list */ /* search list */
for ( int i = 0; i < MAX_IMAGES; ++i ) for ( const auto& img : images )
{ {
if ( images[ i ].name != NULL && strEqual( name, images[ i ].name ) ) { if ( striEqual( name, img.name.c_str() ) ) {
return &images[ i ]; return &img;
} }
} }
@ -310,89 +268,70 @@ image_t *ImageFind( const char *name ){
expects extensionless path as input expects extensionless path as input
*/ */
image_t *ImageLoad( const char *filename ){ const image_t *ImageLoad( const char *name ){
image_t *image; /* dummy check */
char name[ 1024 ]; if ( strEmptyOrNull( name ) ) {
return NULL;
}
/* try to find existing image */
if ( auto img = ImageFind( name ) ) {
return img;
}
/* none found, so let's create a new one */
image_t image;
char filename[ 1024 ];
int size; int size;
byte *buffer = NULL; byte *buffer = NULL;
bool alphaHack = false; bool alphaHack = false;
image.name = name;
/* init */
ImageInit();
/* dummy check */
if ( strEmptyOrNull( filename ) ) {
return NULL;
}
strcpy( name, filename );
/* try to find existing image */
image = ImageFind( name );
if ( image != NULL ) {
image->refCount++;
return image;
}
/* none found, so find first empty image slot */
for ( int i = 0; i < MAX_IMAGES; ++i )
{
if ( images[ i ].name == NULL ) {
image = &images[ i ];
image->name = copystring( name ); /* set it up */
break;
}
}
/* too many images? */
if ( image == NULL ) {
Error( "MAX_IMAGES (%d) exceeded, there are too many image files referenced by the map.", MAX_IMAGES );
}
/* attempt to load tga */ /* attempt to load tga */
strcat( name, ".tga" ); // StripExtension( name ); already sprintf( filename, "%s.tga", name ); // StripExtension( name ); already
size = vfsLoadFile( name, (void**) &buffer, 0 ); size = vfsLoadFile( filename, (void**) &buffer, 0 );
if ( size > 0 ) { if ( size > 0 ) {
LoadTGABuffer( buffer, buffer + size, &image->pixels, &image->width, &image->height ); LoadTGABuffer( buffer, buffer + size, &image.pixels, &image.width, &image.height );
} }
else else
{ {
/* attempt to load png */ /* attempt to load png */
path_set_extension( name, ".png" ); path_set_extension( filename, ".png" );
size = vfsLoadFile( name, (void**) &buffer, 0 ); size = vfsLoadFile( filename, (void**) &buffer, 0 );
if ( size > 0 ) { if ( size > 0 ) {
LoadPNGBuffer( buffer, size, &image->pixels, &image->width, &image->height ); LoadPNGBuffer( buffer, size, &image.pixels, &image.width, &image.height );
} }
else else
{ {
/* attempt to load jpg */ /* attempt to load jpg */
path_set_extension( name, ".jpg" ); path_set_extension( filename, ".jpg" );
size = vfsLoadFile( name, (void**) &buffer, 0 ); size = vfsLoadFile( filename, (void**) &buffer, 0 );
if ( size > 0 ) { if ( size > 0 ) {
if ( LoadJPGBuff( buffer, size, &image->pixels, &image->width, &image->height ) == -1 && image->pixels != NULL ) { if ( LoadJPGBuff( buffer, size, &image.pixels, &image.width, &image.height ) == -1 && image.pixels != NULL ) {
// On error, LoadJPGBuff might store a pointer to the error message in image->pixels // On error, LoadJPGBuff might store a pointer to the error message in image.pixels
Sys_Warning( "LoadJPGBuff %s %s\n", name, (unsigned char*) image->pixels ); Sys_Warning( "LoadJPGBuff %s %s\n", filename, (unsigned char*) image.pixels );
image.pixels = NULL;
} }
alphaHack = true; alphaHack = true;
} }
else else
{ {
/* attempt to load dds */ /* attempt to load dds */
path_set_extension( name, ".dds" ); path_set_extension( filename, ".dds" );
size = vfsLoadFile( name, (void**) &buffer, 0 ); size = vfsLoadFile( filename, (void**) &buffer, 0 );
if ( size > 0 ) { if ( size > 0 ) {
LoadDDSBuffer( buffer, size, &image->pixels, &image->width, &image->height ); LoadDDSBuffer( buffer, size, &image.pixels, &image.width, &image.height );
/* debug code */ /* debug code */
#if 1 #if 0
{ {
ddsPF_t pf; ddsPF_t pf;
DDSGetInfo( (ddsBuffer_t*) buffer, NULL, NULL, &pf ); DDSGetInfo( (ddsBuffer_t*) buffer, NULL, NULL, &pf );
Sys_Printf( "pf = %d\n", pf ); Sys_Printf( "pf = %d\n", pf );
if ( image->width > 0 ) { if ( image.width > 0 ) {
path_set_extension( name, "_converted.tga" ); path_set_extension( filename, "_converted.tga" );
WriteTGA( "C:\\games\\quake3\\baseq3\\textures\\rad\\dds_converted.tga", image->pixels, image->width, image->height ); WriteTGA( "C:\\games\\quake3\\baseq3\\textures\\rad\\dds_converted.tga", image.pixels, image.width, image.height );
} }
} }
#endif #endif
@ -400,10 +339,10 @@ image_t *ImageLoad( const char *filename ){
else else
{ {
/* attempt to load ktx */ /* attempt to load ktx */
path_set_extension( name, ".ktx" ); path_set_extension( filename, ".ktx" );
size = vfsLoadFile( name, (void**) &buffer, 0 ); size = vfsLoadFile( filename, (void**) &buffer, 0 );
if ( size > 0 ) { if ( size > 0 ) {
LoadKTXBufferFirstImage( buffer, size, &image->pixels, &image->width, &image->height ); LoadKTXBufferFirstImage( buffer, size, &image.pixels, &image.width, &image.height );
} }
} }
} }
@ -414,36 +353,31 @@ image_t *ImageLoad( const char *filename ){
free( buffer ); free( buffer );
/* make sure everything's kosher */ /* make sure everything's kosher */
if ( size <= 0 || image->width <= 0 || image->height <= 0 || image->pixels == NULL ) { if ( size <= 0 || image.width <= 0 || image.height <= 0 || image.pixels == NULL ) {
//% Sys_Printf( "size = %d width = %d height = %d pixels = 0x%08x (%s)\n", //% Sys_Printf( "size = %d width = %d height = %d pixels = 0x%08x (%s)\n",
//% size, image->width, image->height, image->pixels, name ); //% size, image.width, image.height, image.pixels, filename );
free( image->name ); image.pixels = NULL;
image->name = NULL;
return NULL; return NULL;
} }
/* set filename */ /* set filename */
image->filename = copystring( name ); image.filename = filename;
/* set count */
image->refCount = 1;
numImages++;
if ( alphaHack ) { if ( alphaHack ) {
path_set_extension( name, "_alpha.jpg" ); path_set_extension( filename, "_alpha.jpg" );
size = vfsLoadFile( (const char*) name, (void**) &buffer, 0 ); size = vfsLoadFile( (const char*) filename, (void**) &buffer, 0 );
if ( size > 0 ) { if ( size > 0 ) {
unsigned char *pixels; unsigned char *pixels;
int width, height; int width, height;
if ( LoadJPGBuff( buffer, size, &pixels, &width, &height ) == -1 ) { if ( LoadJPGBuff( buffer, size, &pixels, &width, &height ) == -1 ) {
if (pixels) { if (pixels) {
// On error, LoadJPGBuff might store a pointer to the error message in pixels // On error, LoadJPGBuff might store a pointer to the error message in pixels
Sys_Warning( "LoadJPGBuff %s %s\n", name, (unsigned char*) pixels ); Sys_Warning( "LoadJPGBuff %s %s\n", filename, (unsigned char*) pixels );
} }
} else { } else {
if ( width == image->width && height == image->height ) { if ( width == image.width && height == image.height ) {
for ( int i = 0; i < width * height; ++i ) for ( int i = 0; i < width * height; ++i )
image->pixels[4 * i + 3] = pixels[4 * i + 2]; // copy alpha from blue channel image.pixels[4 * i + 3] = pixels[4 * i + 2]; // copy alpha from blue channel
} }
free( pixels ); free( pixels );
} }
@ -451,6 +385,6 @@ image_t *ImageLoad( const char *filename ){
} }
} }
/* return the image */ /* cache and return the image */
return image; return &( *images.insert_after( images.cbegin(), std::move( image ) ) );
} }

View File

@ -115,7 +115,6 @@
// now checking it for strlen() < MAX_QPATH (so it's null terminated), though this check may be not enough/too much, depending on the use case // now checking it for strlen() < MAX_QPATH (so it's null terminated), though this check may be not enough/too much, depending on the use case
#define MAX_QPATH 64 #define MAX_QPATH 64
#define MAX_IMAGES 2048
#define DEFAULT_IMAGE "*default" #define DEFAULT_IMAGE "*default"
#define DEF_BACKSPLASH_FRACTION 0.05f /* 5% backsplash by default */ #define DEF_BACKSPLASH_FRACTION 0.05f /* 5% backsplash by default */
@ -413,10 +412,25 @@ typedef Vector3 tcMod_t[ 3 ];
struct image_t struct image_t
{ {
char *name, *filename; CopiedString name; // relative path w/o extension
int refCount; CopiedString filename; // relative path with extension
int width, height; int width, height;
byte *pixels; byte *pixels = nullptr;
image_t() = default;
image_t( const image_t& ) = delete;
image_t( image_t&& other ) noexcept :
name( std::move( other.name ) ),
filename( std::move( other.filename ) ),
width( other.width ),
height( other.height ),
pixels( std::exchange( other.pixels, nullptr ) )
{}
image_t& operator=( const image_t& ) = delete;
image_t& operator=( image_t&& ) noexcept = delete;
~image_t(){
free( pixels );
}
}; };
@ -576,9 +590,9 @@ struct shaderInfo_t
EImplicitMap implicitMap; /* ydnar: enemy territory implicit shaders */ EImplicitMap implicitMap; /* ydnar: enemy territory implicit shaders */
String64 implicitImagePath; String64 implicitImagePath;
image_t *shaderImage; const image_t *shaderImage;
image_t *lightImage; const image_t *lightImage;
image_t *normalImage; const image_t *normalImage;
float skyLightValue; /* ydnar */ float skyLightValue; /* ydnar */
int skyLightIterations; /* ydnar */ int skyLightIterations; /* ydnar */
@ -1813,9 +1827,7 @@ int ExportEntitiesMain( Args& args );
/* image.c */ /* image.c */
void ImageFree( image_t *image ); const image_t *ImageLoad( const char *name );
image_t *ImageFind( const char *name );
image_t *ImageLoad( const char *filename );
/* shaders.c */ /* shaders.c */
@ -1876,9 +1888,6 @@ void InjectCommandLine( const char *stage, const std::vec
/* general */ /* general */
Q_EXTERN int numImages Q_ASSIGN( 0 );
Q_EXTERN image_t images[ MAX_IMAGES ];
Q_EXTERN shaderInfo_t *shaderInfo Q_ASSIGN( NULL ); Q_EXTERN shaderInfo_t *shaderInfo Q_ASSIGN( NULL );
Q_EXTERN int numShaderInfo Q_ASSIGN( 0 ); Q_EXTERN int numShaderInfo Q_ASSIGN( 0 );

View File

@ -747,7 +747,6 @@ static void LoadShaderImages( shaderInfo_t *si ){
/* if no light image, reuse shader image */ /* if no light image, reuse shader image */
if ( si->lightImage == NULL ) { if ( si->lightImage == NULL ) {
si->lightImage = si->shaderImage; si->lightImage = si->shaderImage;
si->lightImage->refCount++;
} }
/* create default and average colors */ /* create default and average colors */