diff --git a/tools/quake3/q3map2/image.c b/tools/quake3/q3map2/image.c index 7ce08aa..6d12a67 100644 --- a/tools/quake3/q3map2/image.c +++ b/tools/quake3/q3map2/image.c @@ -177,10 +177,12 @@ static void LoadPNGBuffer( byte *buffer, int size, byte **pixels, int *width, in pb.size = size; pb.offset = 0; png_set_read_fn( png, &pb, PNGReadData ); +#if 0 png->io_ptr = &pb; /* hack! */ +#endif /* set error longjmp */ - if( setjmp( png->jmpbuf ) ) + if( setjmp( png_jmpbuf(png) ) ) { Sys_Printf( "WARNING: An error occurred reading PNG image\n" ); png_destroy_read_struct( &png, &info, &end ); diff --git a/tools/quake3/q3map2/light.c b/tools/quake3/q3map2/light.c index 5d5dfc5..693ee09 100644 --- a/tools/quake3/q3map2/light.c +++ b/tools/quake3/q3map2/light.c @@ -2755,6 +2755,11 @@ int LightMain( int argc, char **argv ) Sys_Printf( "Filling lightmap colors from surrounding pixels to improve JPEG compression\n" ); } /* unhandled args */ + else if( !strcmp( argv[ i ], "-exporthdr" ) ) + { + exporthdr = qtrue; + Sys_Printf( "Exporting hdr lightmaps\n" ); + } else { Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] ); diff --git a/tools/quake3/q3map2/light_bounce.c b/tools/quake3/q3map2/light_bounce.c index 0e59dde..a051f24 100644 --- a/tools/quake3/q3map2/light_bounce.c +++ b/tools/quake3/q3map2/light_bounce.c @@ -389,14 +389,19 @@ static void RadSample( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm, /* create the color gradient */ //% VectorSubtract( maxs, mins, delta ); - /* new: color gradient will always be 0-1.0, expressed as the range of light relative to overall light */ - //% gradient[ 0 ] = maxs[ 0 ] > 0.0f ? (maxs[ 0 ] - mins[ 0 ]) / maxs[ 0 ] : 0.0f; - //% gradient[ 1 ] = maxs[ 1 ] > 0.0f ? (maxs[ 1 ] - mins[ 1 ]) / maxs[ 1 ] : 0.0f; - //% gradient[ 2 ] = maxs[ 2 ] > 0.0f ? (maxs[ 2 ] - mins[ 2 ]) / maxs[ 2 ] : 0.0f; - - /* newer: another contrast function */ - for( i = 0; i < 3; i++ ) - gradient[ i ] = (maxs[ i ] - mins[ i ]) * maxs[ i ]; + if (exporthdr) + { + /* new: color gradient will always be 0-1.0, expressed as the range of light relative to overall light */ + gradient[ 0 ] = maxs[ 0 ] > 0.0f ? (maxs[ 0 ] - mins[ 0 ]) / maxs[ 0 ] : 0.0f; + gradient[ 1 ] = maxs[ 1 ] > 0.0f ? (maxs[ 1 ] - mins[ 1 ]) / maxs[ 1 ] : 0.0f; + gradient[ 2 ] = maxs[ 2 ] > 0.0f ? (maxs[ 2 ] - mins[ 2 ]) / maxs[ 2 ] : 0.0f; + } + else + { + /* newer: another contrast function */ + for( i = 0; i < 3; i++ ) + gradient[ i ] = (maxs[ i ] - mins[ i ]) * maxs[ i ]; + } } diff --git a/tools/quake3/q3map2/light_ydnar.c b/tools/quake3/q3map2/light_ydnar.c index f291e7a..91547be 100644 --- a/tools/quake3/q3map2/light_ydnar.c +++ b/tools/quake3/q3map2/light_ydnar.c @@ -128,6 +128,51 @@ void ColorToBytes( const float *color, byte *colorBytes, float scale ) } +/* +ColorToRGBE() +Tr3B: standard conversion from float pixels to rgbe pixels +*/ + +void ColorToRGBE(const float *color, unsigned char rgbe[4]) +{ + vec3_t sample; + float maxComponent; + int e; + + VectorCopy(color, sample); + + maxComponent = sample[0]; + if(sample[1] > maxComponent) + maxComponent = sample[1]; + if(sample[2] > maxComponent) + maxComponent = sample[2]; + + if(maxComponent < 1e-32) + { + rgbe[0] = 0; + rgbe[1] = 0; + rgbe[2] = 0; + rgbe[3] = 0; + } + else + { +#if 1 + maxComponent = frexp(maxComponent, &e) * 255.0 / maxComponent; + rgbe[0] = (unsigned char) (sample[0] * maxComponent); + rgbe[1] = (unsigned char) (sample[1] * maxComponent); + rgbe[2] = (unsigned char) (sample[2] * maxComponent); + rgbe[3] = (unsigned char) (e + 128); +#else + e = ceil(log2(maxComponent)); + VectorScale(sample, 1.0 / exp2(e), sample); + + rgbe[0] = (unsigned char) (sample[0] * 255); + rgbe[1] = (unsigned char) (sample[1] * 255); + rgbe[2] = (unsigned char) (sample[2] * 255); + rgbe[3] = (unsigned char) (e + 128); +#endif + } +} /* ------------------------------------------------------------------------------- diff --git a/tools/quake3/q3map2/lightmaps_ydnar.c b/tools/quake3/q3map2/lightmaps_ydnar.c index 5c53405..b23ad6a 100644 --- a/tools/quake3/q3map2/lightmaps_ydnar.c +++ b/tools/quake3/q3map2/lightmaps_ydnar.c @@ -37,6 +37,7 @@ several games based on the Quake III Arena engine, in the form of "Q3Map2." #include "q3map2.h" +#define USE_HDR_LIGHTMAPS /* ------------------------------------------------------------------------------- @@ -105,9 +106,66 @@ void WriteTGA24( char *filename, byte *data, int width, int height, qboolean fli free( buffer ); } +// ================================================================ + /* +WriteRGBE() +*/ + +void WriteRGBE(char *filename, float * data, int width, int height) +{ + int i, c; + FILE *file; + unsigned char rgbe[4]; + float rgb[3]; + + file = fopen(filename, "wb"); + if(file == NULL) + Error("Unable to open %s for writing", filename); + + + // write header + if(fprintf(file,"#?RGBE\n") < 0) + Error("RGBE write error: %s", filename); + + if(fprintf(file,"# Generated by ETXMap \n") < 0) + Error("RGBE write error: %s", filename); + + if(fprintf(file, "FORMAT=32-bit_rle_rgbe\n\n") < 0) + Error("RGBE write error: %s", filename); + + if(fprintf(file, "-Y %d +X %d\n", height, width) < 0) + Error("RGBE write error: %s", filename); + + c = (width * height * 3); + for(i = 0; i < c; i += 3) + { +#if 0 + // FIXME XMap2's output is 255 times too high + rgb[0] = data[i + 0] / 255.0f; + rgb[1] = data[i + 1] / 255.0f; + rgb[2] = data[i + 2] / 255.0f; + + ColorToRGBE(rgb, rgbe); + if(fwrite(rgbe, sizeof(rgbe), 1, file) < 1) + Error("RGBE write error: %s", filename); +#else + rgb[0] = data[i + 0]; + rgb[1] = data[i + 1]; + rgb[2] = data[i + 2]; + + if(fwrite(rgb, sizeof(rgb), 1, file) < 1) + Error("RGBE write error: %s", filename); +#endif + } + + // close the file + fclose(file); +} + +/* ExportLightmaps() exports the lightmaps as a list of numbered tga images */ @@ -1897,8 +1955,22 @@ static void SetupOutLightmap( rawLightmap_t *lm, outLightmap_t *olm ) /* allocate buffers */ olm->lightBits = safe_malloc( (olm->customWidth * olm->customHeight / 8) + 8 ); memset( olm->lightBits, 0, (olm->customWidth * olm->customHeight / 8) + 8 ); + olm->bspLightBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 ); memset( olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3 ); + +#if defined(USE_HDR_LIGHTMAPS) + if(exporthdr) + { + olm->bspLightFloats = safe_malloc(olm->customWidth * olm->customHeight * 3 * sizeof(float)); + memset(olm->bspLightFloats, 0, olm->customWidth * olm->customHeight * 3 * sizeof(float)); + } + else +#endif + { + olm->bspLightFloats = NULL; + } + if( deluxemap ) { olm->bspDirBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 ); @@ -2183,6 +2255,17 @@ static void FindOutLightmaps( rawLightmap_t *lm ) /* store color */ pixel = olm->bspLightBytes + (((oy * olm->customWidth) + ox) * 3); ColorToBytes( color, pixel, lm->brightness ); +#if defined(USE_HDR_LIGHTMAPS) + if(exporthdr) + { + float *hdrPixel; + + hdrPixel = olm->bspLightFloats + (((oy * olm->customWidth) + ox) * 3); + + // FIXME gamma + VectorScale(color, lm->brightness <= 0.0f ? 1.0f : lm->brightness, hdrPixel); + } +#endif /* store direction */ if( deluxemap ) @@ -2971,6 +3054,13 @@ void StoreSurfaceLightmaps( void ) { free( outLightmaps[ i ].lightBits ); free( outLightmaps[ i ].bspLightBytes ); +#if defined(USE_HDR_LIGHTMAPS) + if(exporthdr) + { + free(outLightmaps[i].bspLightFloats); + } +#endif + } free( outLightmaps ); outLightmaps = NULL; @@ -3014,6 +3104,20 @@ void StoreSurfaceLightmaps( void ) store output lightmaps ----------------------------------------------------------------- */ + /* delete old conflicting external lightmaps */ + // FIXME scan for all lightmaps + for(i = 0; i < (numOutLightmaps * 2); i++) + { + /* determine if file exists */ + sprintf(filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i); + if(FileExists(filename)) + remove(filename); + + sprintf(filename, "%s/" EXTERNAL_HDRLIGHTMAP, dirname, i); + if(FileExists(filename)) + remove(filename); + } + /* note it */ Sys_Printf( "storing..." ); @@ -3070,6 +3174,15 @@ void StoreSurfaceLightmaps( void ) sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps ); Sys_FPrintf( SYS_VRB, "\nwriting %s", filename ); WriteTGA24( filename, olm->bspLightBytes, olm->customWidth, olm->customHeight, qtrue ); + +#if defined(USE_HDR_LIGHTMAPS) + if(exporthdr) + { + sprintf(filename, "%s/" EXTERNAL_HDRLIGHTMAP, dirname, numExtLightmaps); + Sys_FPrintf(SYS_VRB, "\nwriting %s", filename); + WriteRGBE(filename, olm->bspLightFloats, olm->customWidth, olm->customHeight); + } +#endif numExtLightmaps++; /* write deluxemap */ @@ -3084,6 +3197,20 @@ void StoreSurfaceLightmaps( void ) olm->extLightmapNum++; } } + +#if defined(USE_HDR_LIGHTMAPS) + /* HDR lightmaps are always exported */ + if (exporthdr && !externalLightmaps && olm->lightmapNum >= 0) + { + /* make a directory for the lightmaps */ + Q_mkdir( dirname ); + + sprintf(filename, "%s/" EXTERNAL_HDRLIGHTMAP, dirname, olm->lightmapNum); + Sys_FPrintf(SYS_VRB, "\nwriting %s", filename); + WriteRGBE(filename, olm->bspLightFloats, olm->customWidth, olm->customHeight); + } +#endif + } if( numExtLightmaps > 0 ) @@ -3093,12 +3220,15 @@ void StoreSurfaceLightmaps( void ) for( i = numExtLightmaps; i; i++ ) { /* determine if file exists */ - sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i ); - if( !FileExists( filename ) ) + sprintf(filename, "%s/" EXTERNAL_HDRLIGHTMAP, dirname, i); + if(FileExists(filename)) + remove(filename); + + sprintf(filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i); + if(FileExists(filename)) + remove( filename ); + else break; - - /* delete it */ - remove( filename ); } /* ----------------------------------------------------------------- diff --git a/tools/quake3/q3map2/q3map2.h b/tools/quake3/q3map2/q3map2.h index e912d15..03a5bd1 100644 --- a/tools/quake3/q3map2/q3map2.h +++ b/tools/quake3/q3map2/q3map2.h @@ -306,6 +306,7 @@ abstracted bsp file ------------------------------------------------------------------------------- */ #define EXTERNAL_LIGHTMAP "lm_%04d.tga" +#define EXTERNAL_HDRLIGHTMAP "lm_%04d.hdr" #define MAX_LIGHTMAPS 4 /* RBSP */ #define MAX_LIGHT_STYLES 64 @@ -1427,6 +1428,7 @@ typedef struct outLightmap_s shaderInfo_t *shaders[ MAX_LIGHTMAP_SHADERS ]; byte *lightBits; byte *bspLightBytes; + float *bspLightFloats; byte *bspDirBytes; } outLightmap_t; @@ -2220,6 +2222,8 @@ Q_EXTERN qboolean deluxemap Q_ASSIGN( qfalse ); Q_EXTERN qboolean debugDeluxemap Q_ASSIGN( qfalse ); Q_EXTERN int deluxemode Q_ASSIGN( 0 ); /* deluxemap format (0 - modelspace, 1 - tangentspace with renormalization, 2 - tangentspace without renormalization) */ +Q_EXTERN qboolean exporthdr Q_ASSIGN( qfalse ); + Q_EXTERN qboolean fast Q_ASSIGN( qfalse ); Q_EXTERN qboolean faster Q_ASSIGN( qfalse ); Q_EXTERN qboolean fastgrid Q_ASSIGN( qfalse );