From f6b5ecda0bc947aa19472738121158e9797326a5 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Wed, 23 Feb 2011 11:12:03 +0100 Subject: [PATCH] use q3map2 from NetRadiant (VOLUNTEERS: split this commit into functional parts!) --- tools/quake3/q3map2/brush.c | 2 - tools/quake3/q3map2/bsp.c | 75 +- tools/quake3/q3map2/bspfile_abstract.c | 93 +- tools/quake3/q3map2/bspfile_ibsp.c | 28 +- tools/quake3/q3map2/bspfile_rbsp.c | 18 +- tools/quake3/q3map2/convert_ase.c | 80 +- tools/quake3/q3map2/convert_map.c | 460 ++++++++- tools/quake3/q3map2/convert_obj.c | 328 +++++++ tools/quake3/q3map2/decals.c | 1 + tools/quake3/q3map2/facebsp.c | 98 +- tools/quake3/q3map2/game__null.h | 98 ++ tools/quake3/q3map2/game_darkplaces.h | 150 +++ tools/quake3/q3map2/game_dq.h | 150 +++ tools/quake3/q3map2/game_ef.h | 16 + tools/quake3/q3map2/game_etut.h | 16 + tools/quake3/q3map2/game_ja.h | 16 + tools/quake3/q3map2/game_jk2.h | 16 + tools/quake3/q3map2/game_nexuiz.h | 17 + tools/quake3/q3map2/game_prophecy.h | 150 +++ tools/quake3/q3map2/game_qfusion.h | 16 + tools/quake3/q3map2/game_quake3.h | 16 + tools/quake3/q3map2/game_quakelive.h | 22 +- tools/quake3/q3map2/game_reaction.h | 16 + tools/quake3/q3map2/game_sof2.h | 16 + tools/quake3/q3map2/game_tenebrae.h | 16 + tools/quake3/q3map2/game_tremulous.h | 16 + tools/quake3/q3map2/game_wolf.h | 16 + tools/quake3/q3map2/game_wolfet.h | 16 + tools/quake3/q3map2/game_xonotic.h | 155 +++ tools/quake3/q3map2/image.c | 6 +- tools/quake3/q3map2/leakfile.c | 6 +- tools/quake3/q3map2/light.c | 730 ++++++++++++-- tools/quake3/q3map2/light_bounce.c | 7 +- tools/quake3/q3map2/light_trace.c | 88 +- tools/quake3/q3map2/light_ydnar.c | 1031 ++++++++++++++++++-- tools/quake3/q3map2/lightmaps.c | 381 +------- tools/quake3/q3map2/lightmaps_ydnar.c | 375 +++++++- tools/quake3/q3map2/main.c | 1228 ++++++++++++++++++++++-- tools/quake3/q3map2/map.c | 175 +++- tools/quake3/q3map2/model.c | 437 ++++++--- tools/quake3/q3map2/patch.c | 1 - tools/quake3/q3map2/path_init.c | 38 +- tools/quake3/q3map2/portals.c | 12 +- tools/quake3/q3map2/prtfile.c | 108 ++- tools/quake3/q3map2/q3map2.h | 277 +++++- tools/quake3/q3map2/q3map2.rc | 2 +- tools/quake3/q3map2/shaders.c | 133 ++- tools/quake3/q3map2/surface.c | 217 +++-- tools/quake3/q3map2/surface_extra.c | 2 +- tools/quake3/q3map2/surface_foliage.c | 2 +- tools/quake3/q3map2/surface_meta.c | 409 ++++++-- tools/quake3/q3map2/tjunction.c | 61 +- tools/quake3/q3map2/vis.c | 77 +- tools/quake3/q3map2/writebsp.c | 62 +- 54 files changed, 6682 insertions(+), 1300 deletions(-) create mode 100644 tools/quake3/q3map2/convert_obj.c create mode 100644 tools/quake3/q3map2/game__null.h create mode 100644 tools/quake3/q3map2/game_darkplaces.h create mode 100644 tools/quake3/q3map2/game_dq.h create mode 100644 tools/quake3/q3map2/game_prophecy.h create mode 100644 tools/quake3/q3map2/game_xonotic.h diff --git a/tools/quake3/q3map2/brush.c b/tools/quake3/q3map2/brush.c index 1093be3b..b7c50f4c 100644 --- a/tools/quake3/q3map2/brush.c +++ b/tools/quake3/q3map2/brush.c @@ -321,8 +321,6 @@ void SnapWeldVectorAccu(vec3_accu_t a, vec3_accu_t b, vec3_accu_t out) } } - - /* FixWinding() - ydnar removes degenerate edges from a winding diff --git a/tools/quake3/q3map2/bsp.c b/tools/quake3/q3map2/bsp.c index 3a16b0c2..79019792 100644 --- a/tools/quake3/q3map2/bsp.c +++ b/tools/quake3/q3map2/bsp.c @@ -44,7 +44,6 @@ functions ------------------------------------------------------------------------------- */ - /* ProcessAdvertisements() copies advertisement info into the BSP structures @@ -268,7 +267,6 @@ void ProcessWorldModel( void ) char level[ 2 ], shader[ 1024 ]; const char *value; - /* sets integer blockSize from worldspawn "_blocksize" key if it exists */ value = ValueForKey( &entities[ 0 ], "_blocksize" ); if( value[ 0 ] == '\0' ) @@ -342,12 +340,12 @@ void ProcessWorldModel( void ) Sys_FPrintf( SYS_NOXML, "******* leaked *******\n" ); Sys_FPrintf( SYS_NOXML, "**********************\n" ); polyline = LeakFile( tree ); - leaknode = xmlNewNode( NULL, "message" ); - xmlNodeSetContent( leaknode, "MAP LEAKED\n" ); + leaknode = xmlNewNode( NULL, (xmlChar*)"message" ); + xmlNodeSetContent( leaknode, (xmlChar*)"MAP LEAKED\n" ); xmlAddChild( leaknode, polyline ); level[0] = (int) '0' + SYS_ERR; level[1] = 0; - xmlSetProp( leaknode, "level", (char*) &level ); + xmlSetProp( leaknode, (xmlChar*)"level", (xmlChar*) &level ); xml_SendNode( leaknode ); if( leaktest ) { @@ -460,7 +458,7 @@ void ProcessWorldModel( void ) VectorSet( normal, 0, 0, -1 ); /* create the flare surface (note shader defaults automatically) */ - DrawSurfaceForFlare( mapEntityNum, origin, normal, color, (char*) flareShader, lightStyle ); + DrawSurfaceForFlare( mapEntityNum, origin, normal, color, flareShader, lightStyle ); } } } @@ -605,6 +603,9 @@ void ProcessModels( void ) /* write fogs */ EmitFogs(); + + /* vortex: emit meta stats */ + EmitMetaStats(); } @@ -618,18 +619,34 @@ void OnlyEnts( void ) { char out[ 1024 ]; + char save_cmdline[1024], save_version[1024]; + const char *p; /* note it */ Sys_Printf( "--- OnlyEnts ---\n" ); sprintf( out, "%s.bsp", source ); LoadBSPFile( out ); + + ParseEntities(); + p = ValueForKey(&entities[0], "_q3map2_cmdline"); + strncpy(save_cmdline, p, sizeof(save_cmdline)); + save_cmdline[sizeof(save_cmdline)-1] = 0; + p = ValueForKey(&entities[0], "_q3map2_version"); + strncpy(save_version, p, sizeof(save_version)); + save_version[sizeof(save_version)-1] = 0; + numEntities = 0; LoadShaderInfo(); - LoadMapFile( name, qfalse ); + LoadMapFile( name, qfalse, qfalse ); SetModelNumbers(); SetLightStyles(); + + if(*save_cmdline) + SetKeyValue(&entities[0], "_q3map2_cmdline", save_cmdline); + if(*save_version) + SetKeyValue(&entities[0], "_q3map2_version", save_version); numBSPEntities = numEntities; UnparseEntities(); @@ -660,6 +677,7 @@ int BSPMain( int argc, char **argv ) numMapDrawSurfs = 0; tempSource[ 0 ] = '\0'; + globalCelShader[0] = 0; /* set standard game flags */ maxSurfaceVerts = game->maxSurfaceVerts; @@ -736,6 +754,14 @@ int BSPMain( int argc, char **argv ) i++; Sys_Printf( "Lightmap sample size set to %dx%d units\n", sampleSize, sampleSize ); } + else if( !strcmp( argv[ i ], "-minsamplesize" ) ) + { + minSampleSize = atoi( argv[ i + 1 ] ); + if( minSampleSize < 1 ) + minSampleSize = 1; + i++; + Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize ); + } else if( !strcmp( argv[ i ], "-custinfoparms") ) { Sys_Printf( "Custom info parms enabled\n" ); @@ -816,6 +842,15 @@ int BSPMain( int argc, char **argv ) Sys_Printf( "Flatshading enabled\n" ); flat = qtrue; } + else if( !strcmp( argv[ i ], "-celshader" ) ) + { + ++i; + if(argv[i][0]) + sprintf( globalCelShader, "textures/%s", argv[ i ] ); + else + *globalCelShader = 0; + Sys_Printf( "Global cel shader set to \"%s\"\n", globalCelShader ); + } else if( !strcmp( argv[ i ], "-meta" ) ) { Sys_Printf( "Creating meta surfaces from brush faces\n" ); @@ -856,10 +891,27 @@ int BSPMain( int argc, char **argv ) Sys_Printf( "Debug portal surfaces enabled\n" ); debugPortals = qtrue; } + else if( !strcmp( argv[ i ], "-altsplit" ) ) + { + Sys_Printf( "Alternate BSP splitting (by 27) enabled\n" ); + bspAlternateSplitWeights = qtrue; + } + else if( !strcmp( argv[ i ], "-deep" ) ) + { + Sys_Printf( "Deep BSP tree generation enabled\n" ); + deepBSP = qtrue; + } + else if( !strcmp( argv[ i ], "-maxarea" ) ) + { + Sys_Printf( "Max Area face surface generation enabled\n" ); + maxAreaFaceSurface = qtrue; + } else if( !strcmp( argv[ i ], "-bsp" ) ) Sys_Printf( "-bsp argument unnecessary\n" ); else + { Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] ); + } } /* fixme: print more useful usage here */ @@ -903,9 +955,12 @@ int BSPMain( int argc, char **argv ) /* load original file from temp spot in case it was renamed by the editor on the way in */ if( strlen( tempSource ) > 0 ) - LoadMapFile( tempSource, qfalse ); + LoadMapFile( tempSource, qfalse, qfalse ); else - LoadMapFile( name, qfalse ); + LoadMapFile( name, qfalse, qfalse ); + + /* div0: inject command line parameters */ + InjectCommandLine(argv, 1, argc - 1); /* ydnar: decal setup */ ProcessDecals(); @@ -923,7 +978,7 @@ int BSPMain( int argc, char **argv ) ProcessAdvertisements(); /* finish and write bsp */ - EndBSPFile(); + EndBSPFile(qtrue); /* remove temp map source file if appropriate */ if( strlen( tempSource ) > 0) diff --git a/tools/quake3/q3map2/bspfile_abstract.c b/tools/quake3/q3map2/bspfile_abstract.c index 31b6f171..ef78160f 100644 --- a/tools/quake3/q3map2/bspfile_abstract.c +++ b/tools/quake3/q3map2/bspfile_abstract.c @@ -64,7 +64,7 @@ void IncDrawVerts() if(bspDrawVerts == 0) { - numBSPDrawVertsBuffer = MAX_MAP_DRAW_VERTS / 37; + numBSPDrawVertsBuffer = 1024; bspDrawVerts = safe_malloc_info(sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer, "IncDrawVerts"); @@ -74,9 +74,6 @@ void IncDrawVerts() numBSPDrawVertsBuffer *= 3; // multiply by 1.5 numBSPDrawVertsBuffer /= 2; - if(numBSPDrawVertsBuffer > MAX_MAP_DRAW_VERTS) - numBSPDrawVertsBuffer = MAX_MAP_DRAW_VERTS; - bspDrawVerts = realloc(bspDrawVerts, sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer); if(!bspDrawVerts) @@ -332,6 +329,13 @@ int CopyLump( bspHeader_t *header, int lump, void *dest, int size ) return length / size; } +int CopyLump_Allocate( bspHeader_t *header, int lump, void **dest, int size, int *allocationVariable ) +{ + /* get lump length and offset */ + *allocationVariable = header->lumps[ lump ].length / size; + *dest = realloc(*dest, size * *allocationVariable); + return CopyLump(header, lump, *dest, size); +} /* @@ -581,7 +585,44 @@ void ParseEntities( void ) numBSPEntities = numEntities; } +/* + * must be called before UnparseEntities + */ +void InjectCommandLine(char **argv, int beginArgs, int endArgs) +{ + const char *previousCommandLine; + char newCommandLine[1024]; + const char *inpos; + char *outpos = newCommandLine; + char *sentinel = newCommandLine + sizeof(newCommandLine) - 1; + int i; + + previousCommandLine = ValueForKey(&entities[0], "_q3map2_cmdline"); + if(previousCommandLine && *previousCommandLine) + { + inpos = previousCommandLine; + while(outpos != sentinel && *inpos) + *outpos++ = *inpos++; + if(outpos != sentinel) + *outpos++ = ';'; + if(outpos != sentinel) + *outpos++ = ' '; + } + for(i = beginArgs; i < endArgs; ++i) + { + if(outpos != sentinel && i != beginArgs) + *outpos++ = ' '; + inpos = argv[i]; + while(outpos != sentinel && *inpos) + if(*inpos != '\\' && *inpos != '"' && *inpos != ';' && (unsigned char) *inpos >= ' ') + *outpos++ = *inpos++; + } + + *outpos = 0; + SetKeyValue(&entities[0], "_q3map2_cmdline", newCommandLine); + SetKeyValue(&entities[0], "_q3map2_version", Q3MAP_VERSION); +} /* UnparseEntities() @@ -601,13 +642,22 @@ void UnparseEntities( void ) /* setup */ + AUTOEXPAND_BY_REALLOC(bspEntData, 0, allocatedBSPEntData, 1024); buf = bspEntData; end = buf; *end = 0; + /* run through entity list */ for( i = 0; i < numBSPEntities && i < numEntities; i++ ) { + { + int sz = end - buf; + AUTOEXPAND_BY_REALLOC(bspEntData, sz + 65536, allocatedBSPEntData, 1024); + buf = bspEntData; + end = buf + sz; + } + /* get epair */ ep = entities[ i ].epairs; if( ep == NULL ) @@ -644,7 +694,7 @@ void UnparseEntities( void ) end += 2; /* check for overflow */ - if( end > buf + MAX_MAP_ENTSTRING ) + if( end > buf + allocatedBSPEntData ) Error( "Entity text too long" ); } @@ -701,7 +751,25 @@ void SetKeyValue( entity_t *ent, const char *key, const char *value ) ep->value = copystring( value ); } +/* +KeyExists() +returns true if entity has this key +*/ + +qboolean KeyExists( const entity_t *ent, const char *key ) +{ + epair_t *ep; + + /* walk epair list */ + for( ep = ent->epairs; ep != NULL; ep = ep->next ) + { + if( !EPAIR_STRCMP( ep->key, key ) ) + return qtrue; + } + /* no match */ + return qfalse; +} /* ValueForKey() @@ -821,7 +889,6 @@ void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castS { const char *value; - /* get cast shadows */ if( castShadows != NULL ) { @@ -849,5 +916,19 @@ void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castS if( value[ 0 ] != '\0' ) *recvShadows = atoi( value ); } + + /* vortex: game-specific default eneity keys */ + value = ValueForKey( ent, "classname" ); + if (!Q_stricmp( game->magic, "dq" ) || !Q_stricmp( game->magic, "prophecy" ) ) + { + /* vortex: deluxe quake default shadow flags */ + if (!Q_stricmp( value, "func_wall" ) ) + { + if( recvShadows != NULL ) + *recvShadows = 1; + if( castShadows != NULL ) + *castShadows = 1; + } + } } diff --git a/tools/quake3/q3map2/bspfile_ibsp.c b/tools/quake3/q3map2/bspfile_ibsp.c index 26fc56dc..77ffd704 100644 --- a/tools/quake3/q3map2/bspfile_ibsp.c +++ b/tools/quake3/q3map2/bspfile_ibsp.c @@ -101,14 +101,14 @@ static void CopyBrushSidesLump( ibspHeader_t *header ) /* copy */ in = GetLump( (bspHeader_t*) header, LUMP_BRUSHSIDES ); - out = bspBrushSides; for( i = 0; i < numBSPBrushSides; i++ ) { + AUTOEXPAND_BY_REALLOC(bspBrushSides, i, allocatedBSPBrushSides, 1024); + out = &bspBrushSides[i]; out->planeNum = in->planeNum; out->shaderNum = in->shaderNum; out->surfaceNum = -1; in++; - out++; } } @@ -477,21 +477,21 @@ void LoadIBSPFile( const char *filename ) Error( "%s is version %d, not %d", filename, header->version, game->bspVersion ); /* load/convert lumps */ - numBSPShaders = CopyLump( (bspHeader_t*) header, LUMP_SHADERS, bspShaders, sizeof( bspShader_t ) ); + numBSPShaders = CopyLump_Allocate( (bspHeader_t*) header, LUMP_SHADERS, (void **) &bspShaders, sizeof( bspShader_t ), &allocatedBSPShaders ); - numBSPModels = CopyLump( (bspHeader_t*) header, LUMP_MODELS, bspModels, sizeof( bspModel_t ) ); + numBSPModels = CopyLump_Allocate( (bspHeader_t*) header, LUMP_MODELS, (void **) &bspModels, sizeof( bspModel_t ), &allocatedBSPModels ); - numBSPPlanes = CopyLump( (bspHeader_t*) header, LUMP_PLANES, bspPlanes, sizeof( bspPlane_t ) ); + numBSPPlanes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_PLANES, (void **) &bspPlanes, sizeof( bspPlane_t ), &allocatedBSPPlanes ); - numBSPLeafs = CopyLump( (bspHeader_t*) header, LUMP_LEAFS, bspLeafs, sizeof( bspLeaf_t ) ); + numBSPLeafs = CopyLump( (bspHeader_t*) header, LUMP_LEAFS, bspLeafs, sizeof( bspLeaf_t ) ); // TODO fix overflow - numBSPNodes = CopyLump( (bspHeader_t*) header, LUMP_NODES, bspNodes, sizeof( bspNode_t ) ); + numBSPNodes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_NODES, (void **) &bspNodes, sizeof( bspNode_t ), &allocatedBSPNodes ); - numBSPLeafSurfaces = CopyLump( (bspHeader_t*) header, LUMP_LEAFSURFACES, bspLeafSurfaces, sizeof( bspLeafSurfaces[ 0 ] ) ); + numBSPLeafSurfaces = CopyLump_Allocate( (bspHeader_t*) header, LUMP_LEAFSURFACES, (void **) &bspLeafSurfaces, sizeof( bspLeafSurfaces[ 0 ] ), &allocatedBSPLeafSurfaces ); - numBSPLeafBrushes = CopyLump( (bspHeader_t*) header, LUMP_LEAFBRUSHES, bspLeafBrushes, sizeof( bspLeafBrushes[ 0 ] ) ); + numBSPLeafBrushes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_LEAFBRUSHES, (void **) &bspLeafBrushes, sizeof( bspLeafBrushes[ 0 ] ), &allocatedBSPLeafBrushes ); - numBSPBrushes = CopyLump( (bspHeader_t*) header, LUMP_BRUSHES, bspBrushes, sizeof( bspBrush_t ) ); + numBSPBrushes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_BRUSHES, (void **) &bspBrushes, sizeof( bspBrush_t ), &allocatedBSPLeafBrushes ); CopyBrushSidesLump( header ); @@ -499,17 +499,17 @@ void LoadIBSPFile( const char *filename ) CopyDrawSurfacesLump( header ); - numBSPFogs = CopyLump( (bspHeader_t*) header, LUMP_FOGS, bspFogs, sizeof( bspFog_t ) ); + numBSPFogs = CopyLump( (bspHeader_t*) header, LUMP_FOGS, bspFogs, sizeof( bspFog_t ) ); // TODO fix overflow numBSPDrawIndexes = CopyLump( (bspHeader_t*) header, LUMP_DRAWINDEXES, bspDrawIndexes, sizeof( bspDrawIndexes[ 0 ] ) ); - numBSPVisBytes = CopyLump( (bspHeader_t*) header, LUMP_VISIBILITY, bspVisBytes, 1 ); + numBSPVisBytes = CopyLump( (bspHeader_t*) header, LUMP_VISIBILITY, bspVisBytes, 1 ); // TODO fix overflow - numBSPLightBytes = GetLumpElements( (bspHeader_t*) header, LUMP_LIGHTMAPS, 1 ); + numBSPLightBytes = GetLumpElements( (bspHeader_t*) header, LUMP_LIGHTMAPS, 1 ); // TODO change to CopyLump_Allocate bspLightBytes = safe_malloc( numBSPLightBytes ); CopyLump( (bspHeader_t*) header, LUMP_LIGHTMAPS, bspLightBytes, 1 ); - bspEntDataSize = CopyLump( (bspHeader_t*) header, LUMP_ENTITIES, bspEntData, 1); + bspEntDataSize = CopyLump_Allocate( (bspHeader_t*) header, LUMP_ENTITIES, (void **) &bspEntData, 1, &allocatedBSPEntData); CopyLightGridLumps( header ); diff --git a/tools/quake3/q3map2/bspfile_rbsp.c b/tools/quake3/q3map2/bspfile_rbsp.c index 74d77ae9..79f177ea 100644 --- a/tools/quake3/q3map2/bspfile_rbsp.c +++ b/tools/quake3/q3map2/bspfile_rbsp.c @@ -229,23 +229,23 @@ void LoadRBSPFile( const char *filename ) Error( "%s is version %d, not %d", filename, header->version, game->bspVersion ); /* load/convert lumps */ - numBSPShaders = CopyLump( (bspHeader_t*) header, LUMP_SHADERS, bspShaders, sizeof( bspShader_t ) ); + numBSPShaders = CopyLump_Allocate( (bspHeader_t*) header, LUMP_SHADERS, (void **) &bspShaders, sizeof( bspShader_t ), &allocatedBSPShaders ); - numBSPModels = CopyLump( (bspHeader_t*) header, LUMP_MODELS, bspModels, sizeof( bspModel_t ) ); + numBSPModels = CopyLump_Allocate( (bspHeader_t*) header, LUMP_MODELS, (void **) &bspModels, sizeof( bspModel_t ), &allocatedBSPModels ); - numBSPPlanes = CopyLump( (bspHeader_t*) header, LUMP_PLANES, bspPlanes, sizeof( bspPlane_t ) ); + numBSPPlanes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_PLANES, (void **) &bspPlanes, sizeof( bspPlane_t ), &allocatedBSPPlanes ); numBSPLeafs = CopyLump( (bspHeader_t*) header, LUMP_LEAFS, bspLeafs, sizeof( bspLeaf_t ) ); - numBSPNodes = CopyLump( (bspHeader_t*) header, LUMP_NODES, bspNodes, sizeof( bspNode_t ) ); + numBSPNodes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_NODES, (void **) &bspNodes, sizeof( bspNode_t ), &allocatedBSPNodes ); - numBSPLeafSurfaces = CopyLump( (bspHeader_t*) header, LUMP_LEAFSURFACES, bspLeafSurfaces, sizeof( bspLeafSurfaces[ 0 ] ) ); + numBSPLeafSurfaces = CopyLump_Allocate( (bspHeader_t*) header, LUMP_LEAFSURFACES, (void **) &bspLeafSurfaces, sizeof( bspLeafSurfaces[ 0 ] ), &allocatedBSPLeafSurfaces ); - numBSPLeafBrushes = CopyLump( (bspHeader_t*) header, LUMP_LEAFBRUSHES, bspLeafBrushes, sizeof( bspLeafBrushes[ 0 ] ) ); + numBSPLeafBrushes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_LEAFBRUSHES, (void **) &bspLeafBrushes, sizeof( bspLeafBrushes[ 0 ] ), &allocatedBSPLeafBrushes ); - numBSPBrushes = CopyLump( (bspHeader_t*) header, LUMP_BRUSHES, bspBrushes, sizeof( bspBrush_t ) ); + numBSPBrushes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_BRUSHES, (void **) &bspBrushes, sizeof( bspBrush_t ), &allocatedBSPLeafBrushes ); - numBSPBrushSides = CopyLump( (bspHeader_t*) header, LUMP_BRUSHSIDES, bspBrushSides, sizeof( bspBrushSide_t ) ); + numBSPBrushSides = CopyLump_Allocate( (bspHeader_t*) header, LUMP_BRUSHSIDES, (void **) &bspBrushSides, sizeof( bspBrushSide_t ), &allocatedBSPBrushSides ); numBSPDrawVerts = GetLumpElements( (bspHeader_t*) header, LUMP_DRAWVERTS, sizeof( bspDrawVerts[ 0 ] ) ); SetDrawVerts( numBSPDrawVerts ); @@ -265,7 +265,7 @@ void LoadRBSPFile( const char *filename ) bspLightBytes = safe_malloc( numBSPLightBytes ); CopyLump( (bspHeader_t*) header, LUMP_LIGHTMAPS, bspLightBytes, 1 ); - bspEntDataSize = CopyLump( (bspHeader_t*) header, LUMP_ENTITIES, bspEntData, 1); + bspEntDataSize = CopyLump_Allocate( (bspHeader_t*) header, LUMP_ENTITIES, (void **) &bspEntData, 1, &allocatedBSPEntData); CopyLightGridLumps( header ); diff --git a/tools/quake3/q3map2/convert_ase.c b/tools/quake3/q3map2/convert_ase.c index 2be25a43..56262311 100644 --- a/tools/quake3/q3map2/convert_ase.c +++ b/tools/quake3/q3map2/convert_ase.c @@ -43,6 +43,7 @@ ConvertSurface() converts a bsp drawsurface to an ase chunk */ +int numLightmapsASE = 0; static void ConvertSurface( FILE *f, bspModel_t *model, int modelNum, bspDrawSurface_t *ds, int surfaceNum, vec3_t origin ) { int i, v, face, a, b, c; @@ -162,7 +163,15 @@ static void ConvertSurface( FILE *f, bspModel_t *model, int modelNum, bspDrawSur fprintf( f, "\t*PROP_MOTIONBLUR\t0\r\n" ); fprintf( f, "\t*PROP_CASTSHADOW\t1\r\n" ); fprintf( f, "\t*PROP_RECVSHADOW\t1\r\n" ); - fprintf( f, "\t*MATERIAL_REF\t%d\r\n", ds->shaderNum ); + if(lightmapsAsTexcoord) + { + if(ds->lightmapNum[0] >= 0 && ds->lightmapNum[0] + deluxemap < numLightmapsASE) + fprintf( f, "\t*MATERIAL_REF\t%d\r\n", ds->lightmapNum[0] + deluxemap ); + else + Sys_Printf( "WARNING: lightmap %d out of range, not exporting\n", ds->lightmapNum[0] + deluxemap ); + } + else + fprintf( f, "\t*MATERIAL_REF\t%d\r\n", ds->shaderNum ); fprintf( f, "}\r\n" ); } @@ -271,12 +280,40 @@ static void ConvertShader( FILE *f, bspShader_t *shader, int shaderNum ) fprintf( f, "\t\t\t*MAP_SUBNO\t1\r\n" ); fprintf( f, "\t\t\t*MAP_AMOUNT\t1.0\r\n" ); fprintf( f, "\t\t\t*MAP_TYPE\tScreen\r\n" ); - fprintf( f, "\t\t\t*BITMAP\t\"..\\%s\"\r\n", filename ); + if(shadersAsBitmap) + fprintf( f, "\t\t\t*BITMAP\t\"%s\"\r\n", shader->shader ); + else + fprintf( f, "\t\t\t*BITMAP\t\"..\\%s\"\r\n", filename ); fprintf( f, "\t\t\t*BITMAP_FILTER\tPyramidal\r\n" ); fprintf( f, "\t\t}\r\n" ); fprintf( f, "\t}\r\n" ); } +static void ConvertLightmap( FILE *f, const char *base, int lightmapNum ) +{ + /* print shader info */ + fprintf( f, "\t*MATERIAL\t%d\t{\r\n", lightmapNum ); + fprintf( f, "\t\t*MATERIAL_NAME\t\"lm_%04d\"\r\n", lightmapNum ); + fprintf( f, "\t\t*MATERIAL_CLASS\t\"Standard\"\r\n" ); + fprintf( f, "\t\t*MATERIAL_DIFFUSE\t1\t1\t1\r\n"); + fprintf( f, "\t\t*MATERIAL_SHADING Phong\r\n" ); + + /* print map info */ + if(lightmapNum >= 0) + { + fprintf( f, "\t\t*MAP_DIFFUSE\t{\r\n" ); + fprintf( f, "\t\t\t*MAP_NAME\t\"lm_%04d\"\r\n", lightmapNum ); + fprintf( f, "\t\t\t*MAP_CLASS\t\"Bitmap\"\r\n"); + fprintf( f, "\t\t\t*MAP_SUBNO\t1\r\n" ); + fprintf( f, "\t\t\t*MAP_AMOUNT\t1.0\r\n" ); + fprintf( f, "\t\t\t*MAP_TYPE\tScreen\r\n" ); + fprintf( f, "\t\t\t*BITMAP\t\"%s\\lm_%04d.tga\"\r\n", base, lightmapNum ); + fprintf( f, "\t\t\t*BITMAP_FILTER\tPyramidal\r\n" ); + fprintf( f, "\t\t}\r\n" ); + } + + fprintf( f, "\t}\r\n" ); +} @@ -294,20 +331,21 @@ int ConvertBSPToASE( char *bspName ) entity_t *e; vec3_t origin; const char *key; - char name[ 1024 ], base[ 1024 ]; + char name[ 1024 ], base[ 1024 ], dirname[ 1024 ]; /* note it */ Sys_Printf( "--- Convert BSP to ASE ---\n" ); /* create the ase filename from the bsp name */ + strcpy( dirname, bspName ); + StripExtension( dirname ); strcpy( name, bspName ); StripExtension( name ); strcat( name, ".ase" ); Sys_Printf( "writing %s\n", name ); ExtractFileBase( bspName, base ); - strcat( base, ".bsp" ); /* open it */ f = fopen( name, "wb" ); @@ -318,7 +356,7 @@ int ConvertBSPToASE( char *bspName ) fprintf( f, "*3DSMAX_ASCIIEXPORT\t200\r\n" ); fprintf( f, "*COMMENT\t\"Generated by Q3Map2 (ydnar) -convert -format ase\"\r\n" ); fprintf( f, "*SCENE\t{\r\n" ); - fprintf( f, "\t*SCENE_FILENAME\t\"%s\"\r\n", base ); + fprintf( f, "\t*SCENE_FILENAME\t\"%s.bsp\"\r\n", base ); fprintf( f, "\t*SCENE_FIRSTFRAME\t0\r\n" ); fprintf( f, "\t*SCENE_LASTFRAME\t100\r\n" ); fprintf( f, "\t*SCENE_FRAMESPEED\t30\r\n" ); @@ -329,11 +367,35 @@ int ConvertBSPToASE( char *bspName ) /* print materials */ fprintf( f, "*MATERIAL_LIST\t{\r\n" ); - fprintf( f, "\t*MATERIAL_COUNT\t%d\r\n", numBSPShaders ); - for( i = 0; i < numBSPShaders; i++ ) + if(lightmapsAsTexcoord) { - shader = &bspShaders[ i ]; - ConvertShader( f, shader, i ); + int lightmapCount; + for( lightmapCount = 0; lightmapCount < numBSPLightmaps; lightmapCount++ ) + ; + for( ; ; lightmapCount++ ) + { + char buf[1024]; + FILE *tmp; + snprintf(buf, sizeof(buf), "%s/lm_%04d.tga", dirname, lightmapCount); + buf[sizeof(buf) - 1] = 0; + tmp = fopen(buf, "rb"); + if(!tmp) + break; + fclose(tmp); + } + fprintf( f, "\t*MATERIAL_COUNT\t%d\r\n", lightmapCount ); + for( i = 0; i < lightmapCount; i++ ) + ConvertLightmap( f, base, i ); + numLightmapsASE = lightmapCount; + } + else + { + fprintf( f, "\t*MATERIAL_COUNT\t%d\r\n", numBSPShaders ); + for( i = 0; i < numBSPShaders; i++ ) + { + shader = &bspShaders[ i ]; + ConvertShader( f, shader, i ); + } } fprintf( f, "}\r\n" ); diff --git a/tools/quake3/q3map2/convert_map.c b/tools/quake3/q3map2/convert_map.c index 1fabbc63..0f37665d 100644 --- a/tools/quake3/q3map2/convert_map.c +++ b/tools/quake3/q3map2/convert_map.c @@ -46,7 +46,169 @@ exports a map brush #define SNAP_FLOAT_TO_INT 4 #define SNAP_INT_TO_FLOAT (1.0 / SNAP_FLOAT_TO_INT) -static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin ) +typedef vec_t vec2_t[2]; + +static vec_t Det3x3(vec_t a00, vec_t a01, vec_t a02, + vec_t a10, vec_t a11, vec_t a12, + vec_t a20, vec_t a21, vec_t a22) +{ + return + a00 * (a11 * a22 - a12 * a21) + - a01 * (a10 * a22 - a12 * a20) + + a02 * (a10 * a21 - a11 * a20); +} + +void GetBestSurfaceTriangleMatchForBrushside(side_t *buildSide, bspDrawVert_t *bestVert[3]) +{ + bspDrawSurface_t *s; + int i; + int t; + vec_t best = 0; + vec_t thisarea; + vec3_t normdiff; + vec3_t v1v0, v2v0, norm; + bspDrawVert_t *vert[3]; + winding_t *polygon; + plane_t *buildPlane = &mapplanes[buildSide->planenum]; + int matches = 0; + + // first, start out with NULLs + bestVert[0] = bestVert[1] = bestVert[2] = NULL; + + // brute force through all surfaces + for(s = bspDrawSurfaces; s != bspDrawSurfaces + numBSPDrawSurfaces; ++s) + { + if(s->surfaceType != MST_PLANAR && s->surfaceType != MST_TRIANGLE_SOUP) + continue; + if(strcmp(buildSide->shaderInfo->shader, bspShaders[s->shaderNum].shader)) + continue; + for(t = 0; t + 3 <= s->numIndexes; t += 3) + { + vert[0] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 0]]; + vert[1] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 1]]; + vert[2] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 2]]; + if(s->surfaceType == MST_PLANAR && VectorCompare(vert[0]->normal, vert[1]->normal) && VectorCompare(vert[1]->normal, vert[2]->normal)) + { + VectorSubtract(vert[0]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue; + VectorSubtract(vert[1]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue; + VectorSubtract(vert[2]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue; + } + else + { + // this is more prone to roundoff errors, but with embedded + // models, there is no better way + VectorSubtract(vert[1]->xyz, vert[0]->xyz, v1v0); + VectorSubtract(vert[2]->xyz, vert[0]->xyz, v2v0); + CrossProduct(v2v0, v1v0, norm); + VectorNormalize(norm, norm); + VectorSubtract(norm, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue; + } + if(abs(DotProduct(vert[0]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue; + if(abs(DotProduct(vert[1]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue; + if(abs(DotProduct(vert[2]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue; + // Okay. Correct surface type, correct shader, correct plane. Let's start with the business... + polygon = CopyWinding(buildSide->winding); + for(i = 0; i < 3; ++i) + { + // 0: 1, 2 + // 1: 2, 0 + // 2; 0, 1 + vec3_t *v1 = &vert[(i+1)%3]->xyz; + vec3_t *v2 = &vert[(i+2)%3]->xyz; + vec3_t triNormal; + vec_t triDist; + vec3_t sideDirection; + // we now need to generate triNormal and triDist so that they represent the plane spanned by normal and (v2 - v1). + VectorSubtract(*v2, *v1, sideDirection); + CrossProduct(sideDirection, buildPlane->normal, triNormal); + triDist = DotProduct(*v1, triNormal); + ChopWindingInPlace(&polygon, triNormal, triDist, distanceEpsilon); + if(!polygon) + goto exwinding; + } + thisarea = WindingArea(polygon); + if(thisarea > 0) + ++matches; + if(thisarea > best) + { + best = thisarea; + bestVert[0] = vert[0]; + bestVert[1] = vert[1]; + bestVert[2] = vert[2]; + } + FreeWinding(polygon); +exwinding: + ; + } + } + //if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16)) + // fprintf(stderr, "brushside with %s: %d matches (%f area)\n", buildSide->shaderInfo->shader, matches, best); +} + +#define FRAC(x) ((x) - floor(x)) +static void ConvertOriginBrush( FILE *f, int num, vec3_t origin, qboolean brushPrimitives ) +{ + int originSize = 256; + + char pattern[6][7][3] = { + { "+++", "+-+", "-++", "- ", " + ", " - ", "- " }, + { "+++", "-++", "++-", "- ", " +", "+ ", " +" }, + { "+++", "++-", "+-+", " - ", " +", " - ", " +" }, + { "---", "+--", "-+-", "- ", " + ", " - ", "+ " }, + { "---", "--+", "+--", "- ", " +", "- ", " +" }, + { "---", "-+-", "--+", " - ", " +", " + ", " +" } + }; + int i; +#define S(a,b,c) (pattern[a][b][c] == '+' ? +1 : pattern[a][b][c] == '-' ? -1 : 0) + + /* start brush */ + fprintf( f, "\t// brush %d\n", num ); + fprintf( f, "\t{\n" ); + if(brushPrimitives) + { + fprintf( f, "\tbrushDef\n" ); + fprintf( f, "\t{\n" ); + } + /* print brush side */ + /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */ + + for(i = 0; i < 6; ++i) + { + if(brushPrimitives) + { + fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n", + origin[0] + 8 * S(i,0,0), origin[1] + 8 * S(i,0,1), origin[2] + 8 * S(i,0,2), + origin[0] + 8 * S(i,1,0), origin[1] + 8 * S(i,1,1), origin[2] + 8 * S(i,1,2), + origin[0] + 8 * S(i,2,0), origin[1] + 8 * S(i,2,1), origin[2] + 8 * S(i,2,2), + 1.0f/16.0f, 0.0f, FRAC((S(i,5,0) * origin[0] + S(i,5,1) * origin[1] + S(i,5,2) * origin[2]) / 16.0 + 0.5), + 0.0f, 1.0f/16.0f, FRAC((S(i,6,0) * origin[0] + S(i,6,1) * origin[1] + S(i,6,2) * origin[2]) / 16.0 + 0.5), + "common/origin", + 0 + ); + } + else + { + fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s %.8f %.8f %.8f %.8f %.8f %d 0 0\n", + origin[0] + 8 * S(i,0,0), origin[1] + 8 * S(i,0,1), origin[2] + 8 * S(i,0,2), + origin[0] + 8 * S(i,1,0), origin[1] + 8 * S(i,1,1), origin[2] + 8 * S(i,1,2), + origin[0] + 8 * S(i,2,0), origin[1] + 8 * S(i,2,1), origin[2] + 8 * S(i,2,2), + "common/origin", + FRAC((S(i,3,0) * origin[0] + S(i,3,1) * origin[1] + S(i,3,2) * origin[2]) / 16.0 + 0.5) * originSize, + FRAC((S(i,4,0) * origin[0] + S(i,4,1) * origin[1] + S(i,4,2) * origin[2]) / 16.0 + 0.5) * originSize, + 0.0f, 16.0 / originSize, 16.0 / originSize, + 0 + ); + } + } +#undef S + + /* end brush */ + if(brushPrimitives) + fprintf( f, "\t}\n" ); + fprintf( f, "\t}\n\n" ); +} + +static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin, qboolean brushPrimitives ) { int i, j; bspBrushSide_t *side; @@ -54,12 +216,20 @@ static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin ) bspShader_t *shader; char *texture; bspPlane_t *plane; + plane_t *buildPlane; vec3_t pts[ 3 ]; + bspDrawVert_t *vert[3]; + int valid; /* start brush */ fprintf( f, "\t// brush %d\n", num ); fprintf( f, "\t{\n" ); + if(brushPrimitives) + { + fprintf( f, "\tbrushDef\n" ); + fprintf( f, "\t{\n" ); + } /* clear out build brush */ for( i = 0; i < buildBrush->numsides; i++ ) @@ -83,8 +253,8 @@ static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin ) if( side->shaderNum < 0 || side->shaderNum >= numBSPShaders ) continue; shader = &bspShaders[ side->shaderNum ]; - if( !Q_stricmp( shader->shader, "default" ) || !Q_stricmp( shader->shader, "noshader" ) ) - continue; + //if( !Q_stricmp( shader->shader, "default" ) || !Q_stricmp( shader->shader, "noshader" ) ) + // continue; /* get plane */ plane = &bspPlanes[ side->planeNum ]; @@ -101,7 +271,10 @@ static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin ) /* make brush windings */ if( !CreateBrushWindings( buildBrush ) ) + { + Sys_Printf( "CreateBrushWindings failed\n" ); return; + } /* iterate through build brush sides */ for( i = 0; i < buildBrush->numsides; i++ ) @@ -109,10 +282,26 @@ static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin ) /* get build side */ buildSide = &buildBrush->sides[ i ]; + /* get plane */ + buildPlane = &mapplanes[ buildSide->planenum ]; + /* dummy check */ if( buildSide->shaderInfo == NULL || buildSide->winding == NULL ) continue; - + + // st-texcoords -> texMat block + // start out with dummy + VectorSet(buildSide->texMat[0], 1/32.0, 0, 0); + VectorSet(buildSide->texMat[1], 0, 1/32.0, 0); + + // find surface for this side (by brute force) + // surface format: + // - meshverts point in pairs of three into verts + // - (triangles) + // - find the triangle that has most in common with our side + GetBestSurfaceTriangleMatchForBrushside(buildSide, vert); + valid = 0; + /* get texture name */ if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) ) texture = buildSide->shaderInfo->shader + 9; @@ -127,19 +316,228 @@ static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin ) //% pts[ j ][ 1 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 1 ] * SNAP_FLOAT_TO_INT + 0.5f ); //% pts[ j ][ 2 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 2 ] * SNAP_FLOAT_TO_INT + 0.5f ); } - - /* print brush side */ - /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */ - fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s 0 0 0 0.5 0.5 0 0 0\n", - pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ], - pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ], - pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ], - texture ); + + if(vert[0] && vert[1] && vert[2]) + { + if(brushPrimitives) + { + int i; + vec3_t texX, texY; + vec2_t xyI, xyJ, xyK; + vec2_t stI, stJ, stK; + vec_t D, D0, D1, D2; + + ComputeAxisBase(buildPlane->normal, texX, texY); + + xyI[0] = DotProduct(vert[0]->xyz, texX); + xyI[1] = DotProduct(vert[0]->xyz, texY); + xyJ[0] = DotProduct(vert[1]->xyz, texX); + xyJ[1] = DotProduct(vert[1]->xyz, texY); + xyK[0] = DotProduct(vert[2]->xyz, texX); + xyK[1] = DotProduct(vert[2]->xyz, texY); + stI[0] = vert[0]->st[0]; stI[1] = vert[0]->st[1]; + stJ[0] = vert[1]->st[0]; stJ[1] = vert[1]->st[1]; + stK[0] = vert[2]->st[0]; stK[1] = vert[2]->st[1]; + + // - solve linear equations: + // - (x, y) := xyz . (texX, texY) + // - st[i] = texMat[i][0]*x + texMat[i][1]*y + texMat[i][2] + // (for three vertices) + D = Det3x3( + xyI[0], xyI[1], 1, + xyJ[0], xyJ[1], 1, + xyK[0], xyK[1], 1 + ); + if(D != 0) + { + for(i = 0; i < 2; ++i) + { + D0 = Det3x3( + stI[i], xyI[1], 1, + stJ[i], xyJ[1], 1, + stK[i], xyK[1], 1 + ); + D1 = Det3x3( + xyI[0], stI[i], 1, + xyJ[0], stJ[i], 1, + xyK[0], stK[i], 1 + ); + D2 = Det3x3( + xyI[0], xyI[1], stI[i], + xyJ[0], xyJ[1], stJ[i], + xyK[0], xyK[1], stK[i] + ); + VectorSet(buildSide->texMat[i], D0 / D, D1 / D, D2 / D); + } + valid = 1; + } + else + fprintf(stderr, "degenerate triangle found when solving texMat equations for\n(%f %f %f) (%f %f %f) (%f %f %f)\n( %f %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n", + buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2], + vert[0]->normal[0], vert[0]->normal[1], vert[0]->normal[2], + texX[0], texX[1], texX[2], texY[0], texY[1], texY[2], + vert[0]->xyz[0], vert[0]->xyz[1], vert[0]->xyz[2], xyI[0], xyI[1], + vert[1]->xyz[0], vert[1]->xyz[1], vert[1]->xyz[2], xyJ[0], xyJ[1], + vert[2]->xyz[0], vert[2]->xyz[1], vert[2]->xyz[2], xyK[0], xyK[1] + ); + + /* print brush side */ + /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */ + fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n", + pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ], + pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ], + pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ], + buildSide->texMat[0][0], buildSide->texMat[0][1], FRAC(buildSide->texMat[0][2]), + buildSide->texMat[1][0], buildSide->texMat[1][1], FRAC(buildSide->texMat[1][2]), + texture, + // DEBUG: valid ? 0 : C_DETAIL + 0 + ); + } + else + { + // invert QuakeTextureVecs + int i; + vec3_t vecs[2]; + int sv, tv; + vec2_t stI, stJ, stK; + vec3_t sts[2]; + vec2_t shift, scale; + vec_t rotate; + vec_t D, D0, D1, D2; + + TextureAxisFromPlane(buildPlane, vecs[0], vecs[1]); + if (vecs[0][0]) + sv = 0; + else if (vecs[0][1]) + sv = 1; + else + sv = 2; + if (vecs[1][0]) + tv = 0; + else if (vecs[1][1]) + tv = 1; + else + tv = 2; + + stI[0] = vert[0]->st[0] * buildSide->shaderInfo->shaderWidth; stI[1] = vert[0]->st[1] * buildSide->shaderInfo->shaderHeight; + stJ[0] = vert[1]->st[0] * buildSide->shaderInfo->shaderWidth; stJ[1] = vert[1]->st[1] * buildSide->shaderInfo->shaderHeight; + stK[0] = vert[2]->st[0] * buildSide->shaderInfo->shaderWidth; stK[1] = vert[2]->st[1] * buildSide->shaderInfo->shaderHeight; + + D = Det3x3( + vert[0]->xyz[sv], vert[0]->xyz[tv], 1, + vert[1]->xyz[sv], vert[1]->xyz[tv], 1, + vert[2]->xyz[sv], vert[2]->xyz[tv], 1 + ); + if(D != 0) + { + for(i = 0; i < 2; ++i) + { + D0 = Det3x3( + stI[i], vert[0]->xyz[tv], 1, + stJ[i], vert[1]->xyz[tv], 1, + stK[i], vert[2]->xyz[tv], 1 + ); + D1 = Det3x3( + vert[0]->xyz[sv], stI[i], 1, + vert[1]->xyz[sv], stJ[i], 1, + vert[2]->xyz[sv], stK[i], 1 + ); + D2 = Det3x3( + vert[0]->xyz[sv], vert[0]->xyz[tv], stI[i], + vert[1]->xyz[sv], vert[1]->xyz[tv], stJ[i], + vert[2]->xyz[sv], vert[2]->xyz[tv], stK[i] + ); + VectorSet(sts[i], D0 / D, D1 / D, D2 / D); + } + valid = 1; + } + else + fprintf(stderr, "degenerate triangle found when solving texDef equations\n"); // FIXME add stuff here + + // now we must solve: + // // now we must invert: + // ang = rotate / 180 * Q_PI; + // sinv = sin(ang); + // cosv = cos(ang); + // ns = cosv * vecs[0][sv]; + // nt = sinv * vecs[0][sv]; + // vecsrotscaled[0][sv] = ns / scale[0]; + // vecsrotscaled[0][tv] = nt / scale[0]; + // ns = -sinv * vecs[1][tv]; + // nt = cosv * vecs[1][tv]; + // vecsrotscaled[1][sv] = ns / scale[1]; + // vecsrotscaled[1][tv] = nt / scale[1]; + scale[0] = 1.0/sqrt(sts[0][0] * sts[0][0] + sts[0][1] * sts[0][1]); + scale[1] = 1.0/sqrt(sts[1][0] * sts[1][0] + sts[1][1] * sts[1][1]); + rotate = atan2(sts[0][1] * vecs[0][sv] - sts[1][0] * vecs[1][tv], sts[0][0] * vecs[0][sv] + sts[1][1] * vecs[1][tv]) * (180.0f / Q_PI); + shift[0] = buildSide->shaderInfo->shaderWidth * FRAC(sts[0][2] / buildSide->shaderInfo->shaderWidth); + shift[1] = buildSide->shaderInfo->shaderHeight * FRAC(sts[1][2] / buildSide->shaderInfo->shaderHeight); + + /* print brush side */ + /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */ + fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s %.8f %.8f %.8f %.8f %.8f %d 0 0\n", + pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ], + pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ], + pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ], + texture, + shift[0], shift[1], rotate, scale[0], scale[1], + // DEBUG: valid ? 0 : C_DETAIL + 0 + ); + } + } + else + { + vec3_t vecs[ 2 ]; + if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16)) + if(strcmp(buildSide->shaderInfo->shader, "noshader")) + if(strcmp(buildSide->shaderInfo->shader, "default")) + { + fprintf(stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader); + texture = "common/WTF"; + } + + MakeNormalVectors( buildPlane->normal, vecs[ 0 ], vecs[ 1 ] ); + VectorMA( vec3_origin, buildPlane->dist, buildPlane->normal, pts[ 0 ] ); + VectorMA( pts[ 0 ], 256.0f, vecs[ 0 ], pts[ 1 ] ); + VectorMA( pts[ 0 ], 256.0f, vecs[ 1 ], pts[ 2 ] ); + if(brushPrimitives) + { + fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n", + pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ], + pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ], + pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ], + 1.0f/16.0f, 0.0f, 0.0f, + 0.0f, 1.0f/16.0f, 0.0f, + texture, + // DEBUG: valid ? 0 : C_DETAIL + 0 + ); + } + else + { + fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s %.8f %.8f %.8f %.8f %.8f %d 0 0\n", + pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ], + pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ], + pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ], + texture, + 0.0f, 0.0f, 0.0f, 0.25f, 0.25f, + // DEBUG: valid ? 0 : C_DETAIL + 0 + ); + } + } } /* end brush */ + if(brushPrimitives) + { + fprintf( f, "\t}\n" ); + } fprintf( f, "\t}\n\n" ); } +#undef FRAC #if 0 /* iterate through the brush sides (ignore the first 6 bevel planes) */ @@ -278,7 +676,7 @@ ConvertModel() exports a bsp model to a map file */ -static void ConvertModel( FILE *f, bspModel_t *model, int modelNum, vec3_t origin ) +static void ConvertModel( FILE *f, bspModel_t *model, int modelNum, vec3_t origin, qboolean brushPrimitives ) { int i, num; bspBrush_t *brush; @@ -287,25 +685,29 @@ static void ConvertModel( FILE *f, bspModel_t *model, int modelNum, vec3_t origi /* convert bsp planes to map planes */ nummapplanes = numBSPPlanes; + AUTOEXPAND_BY_REALLOC(mapplanes, nummapplanes, allocatedmapplanes, 1024); for( i = 0; i < numBSPPlanes; i++ ) { VectorCopy( bspPlanes[ i ].normal, mapplanes[ i ].normal ); mapplanes[ i ].dist = bspPlanes[ i ].dist; mapplanes[ i ].type = PlaneTypeForNormal( mapplanes[ i ].normal ); - mapplanes[ i ].hash_chain = NULL; + mapplanes[ i ].hash_chain = 0; } /* allocate a build brush */ buildBrush = AllocBrush( 512 ); buildBrush->entityNum = 0; buildBrush->original = buildBrush; + + if(origin[0] != 0 || origin[1] != 0 || origin[2] != 0) + ConvertOriginBrush(f, -1, origin, brushPrimitives); /* go through each brush in the model */ for( i = 0; i < model->numBSPBrushes; i++ ) { num = i + model->firstBSPBrush; brush = &bspBrushes[ num ]; - ConvertBrush( f, num, brush, origin ); + ConvertBrush( f, num, brush, origin, brushPrimitives ); } /* free the build brush */ @@ -330,7 +732,7 @@ ConvertEPairs() exports entity key/value pairs to a map file */ -static void ConvertEPairs( FILE *f, entity_t *e ) +static void ConvertEPairs( FILE *f, entity_t *e, qboolean skip_origin ) { epair_t *ep; @@ -346,6 +748,10 @@ static void ConvertEPairs( FILE *f, entity_t *e ) if( !Q_stricmp( ep->key, "model" ) && ep->value[ 0 ] == '*' ) continue; + /* ignore origin keys if skip_origin is set */ + if( skip_origin && !Q_stricmp( ep->key, "origin" ) ) + continue; + /* emit the epair */ fprintf( f, "\t\"%s\" \"%s\"\n", ep->key, ep->value ); } @@ -358,7 +764,7 @@ ConvertBSPToMap() exports an quake map file from the bsp */ -int ConvertBSPToMap( char *bspName ) +int ConvertBSPToMap_Ext( char *bspName, qboolean brushPrimitives ) { int i, modelNum; FILE *f; @@ -399,10 +805,6 @@ int ConvertBSPToMap( char *bspName ) fprintf( f, "// entity %d\n", i ); fprintf( f, "{\n" ); - /* export keys */ - ConvertEPairs( f, e ); - fprintf( f, "\n" ); - /* get model num */ if( i == 0 ) modelNum = 0; @@ -415,6 +817,10 @@ int ConvertBSPToMap( char *bspName ) modelNum = -1; } + /* export keys */ + ConvertEPairs( f, e, modelNum >= 0 ); + fprintf( f, "\n" ); + /* only handle bsp models */ if( modelNum >= 0 ) { @@ -429,7 +835,7 @@ int ConvertBSPToMap( char *bspName ) GetVectorForKey( e, "origin", origin ); /* convert model */ - ConvertModel( f, model, modelNum, origin ); + ConvertModel( f, model, modelNum, origin, brushPrimitives ); } /* end entity */ @@ -442,3 +848,13 @@ int ConvertBSPToMap( char *bspName ) /* return to sender */ return 0; } + +int ConvertBSPToMap( char *bspName ) +{ + return ConvertBSPToMap_Ext(bspName, qfalse); +} + +int ConvertBSPToMap_BP( char *bspName ) +{ + return ConvertBSPToMap_Ext(bspName, qtrue); +} diff --git a/tools/quake3/q3map2/convert_obj.c b/tools/quake3/q3map2/convert_obj.c new file mode 100644 index 00000000..08e75e11 --- /dev/null +++ b/tools/quake3/q3map2/convert_obj.c @@ -0,0 +1,328 @@ +/* ------------------------------------------------------------------------------- + +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#define CONVERT_ASE_C + + + +/* dependencies */ +#include "q3map2.h" + + + +/* +ConvertSurface() +converts a bsp drawsurface to an obj chunk +*/ + +int firstLightmap = 0; +int lastLightmap = -1; +static void ConvertLightmapToMTL( FILE *f, const char *base, int lightmapNum ); + +int objVertexCount = 0; +int objLastShaderNum = -1; +static void ConvertSurfaceToOBJ( FILE *f, bspModel_t *model, int modelNum, bspDrawSurface_t *ds, int surfaceNum, vec3_t origin ) +{ + int i, v, face, a, b, c; + bspDrawVert_t *dv; + + /* ignore patches for now */ + if( ds->surfaceType != MST_PLANAR && ds->surfaceType != MST_TRIANGLE_SOUP ) + return; + + fprintf(f, "g mat%dmodel%dsurf%d\r\n", ds->shaderNum, modelNum, surfaceNum); + switch( ds->surfaceType ) + { + case MST_PLANAR: + fprintf( f, "# SURFACETYPE MST_PLANAR\r\n" ); + break; + case MST_TRIANGLE_SOUP: + fprintf( f, "# SURFACETYPE MST_TRIANGLE_SOUP\r\n" ); + break; + } + + /* export shader */ + if(lightmapsAsTexcoord) + { + if(objLastShaderNum != ds->lightmapNum[0]) + { + fprintf(f, "usemtl lm_%04d\r\n", ds->lightmapNum[0] + deluxemap); + objLastShaderNum = ds->lightmapNum[0] + deluxemap; + } + if(ds->lightmapNum[0] + deluxemap < firstLightmap) + { + Sys_Printf( "WARNING: lightmap %d out of range (exporting anyway)\n", ds->lightmapNum[0] + deluxemap ); + firstLightmap = ds->lightmapNum[0] + deluxemap; + } + if(ds->lightmapNum[0] > lastLightmap) + { + Sys_Printf( "WARNING: lightmap %d out of range (exporting anyway)\n", ds->lightmapNum[0] + deluxemap ); + lastLightmap = ds->lightmapNum[0] + deluxemap; + } + } + else + { + if(objLastShaderNum != ds->shaderNum) + { + fprintf(f, "usemtl %s\r\n", bspShaders[ds->shaderNum].shader); + objLastShaderNum = ds->shaderNum; + } + } + + /* export vertex */ + for( i = 0; i < ds->numVerts; i++ ) + { + v = i + ds->firstVert; + dv = &bspDrawVerts[ v ]; + fprintf(f, "# vertex %d\r\n", i + objVertexCount + 1); + fprintf(f, "v %f %f %f\r\n", dv->xyz[ 0 ], dv->xyz[ 1 ], dv->xyz[ 2 ]); + fprintf(f, "vn %f %f %f\r\n", dv->normal[ 0 ], dv->normal[ 1 ], dv->normal[ 2 ]); + if(lightmapsAsTexcoord) + fprintf(f, "vt %f %f\r\n", dv->lightmap[0][0], 1.0 - dv->lightmap[0][1]); + else + fprintf(f, "vt %f %f\r\n", dv->st[ 0 ], 1.0 - dv->st[ 1 ]); + } + + /* export faces */ + for( i = 0; i < ds->numIndexes; i += 3 ) + { + face = (i / 3); + a = bspDrawIndexes[ i + ds->firstIndex ]; + c = bspDrawIndexes[ i + ds->firstIndex + 1 ]; + b = bspDrawIndexes[ i + ds->firstIndex + 2 ]; + fprintf(f, "f %d/%d/%d %d/%d/%d %d/%d/%d\r\n", + a + objVertexCount + 1, a + objVertexCount + 1, a + objVertexCount + 1, + b + objVertexCount + 1, b + objVertexCount + 1, b + objVertexCount + 1, + c + objVertexCount + 1, c + objVertexCount + 1, c + objVertexCount + 1 + ); + } + + objVertexCount += ds->numVerts; +} + + + +/* +ConvertModel() +exports a bsp model to an ase chunk +*/ + +static void ConvertModelToOBJ( FILE *f, bspModel_t *model, int modelNum, vec3_t origin ) +{ + int i, s; + bspDrawSurface_t *ds; + + + /* go through each drawsurf in the model */ + for( i = 0; i < model->numBSPSurfaces; i++ ) + { + s = i + model->firstBSPSurface; + ds = &bspDrawSurfaces[ s ]; + ConvertSurfaceToOBJ( f, model, modelNum, ds, s, origin ); + } +} + + + +/* +ConvertShader() +exports a bsp shader to an ase chunk +*/ + +static void ConvertShaderToMTL( FILE *f, bspShader_t *shader, int shaderNum ) +{ + shaderInfo_t *si; + char *c, filename[ 1024 ]; + + + /* get shader */ + si = ShaderInfoForShader( shader->shader ); + if( si == NULL ) + { + Sys_Printf( "WARNING: NULL shader in BSP\n" ); + return; + } + + /* set bitmap filename */ + if( si->shaderImage->filename[ 0 ] != '*' ) + strcpy( filename, si->shaderImage->filename ); + else + sprintf( filename, "%s.tga", si->shader ); + + /* blender hates this, so let's not do it + for( c = filename; *c != '\0'; c++ ) + if( *c == '/' ) + *c = '\\'; + */ + + /* print shader info */ + fprintf( f, "newmtl %s\r\n", shader->shader ); + fprintf( f, "Kd %f %f %f\r\n", si->color[ 0 ], si->color[ 1 ], si->color[ 2 ] ); + if(shadersAsBitmap) + fprintf( f, "map_Kd %s\r\n", shader->shader ); + else + /* blender hates this, so let's not do it + fprintf( f, "map_Kd ..\\%s\r\n", filename ); + */ + fprintf( f, "map_Kd ../%s\r\n", filename ); +} + +static void ConvertLightmapToMTL( FILE *f, const char *base, int lightmapNum ) +{ + /* print shader info */ + fprintf( f, "newmtl lm_%04d\r\n", lightmapNum ); + if(lightmapNum >= 0) + /* blender hates this, so let's not do it + fprintf( f, "map_Kd %s\\lm_%04d.tga\r\n", base, lightmapNum ); + */ + fprintf( f, "map_Kd %s/lm_%04d.tga\r\n", base, lightmapNum ); +} + + + +/* +ConvertBSPToASE() +exports an 3d studio ase file from the bsp +*/ + +int ConvertBSPToOBJ( char *bspName ) +{ + int i, modelNum; + FILE *f, *fmtl; + bspShader_t *shader; + bspModel_t *model; + entity_t *e; + vec3_t origin; + const char *key; + char name[ 1024 ], base[ 1024 ], mtlname[ 1024 ], dirname[ 1024 ]; + + + /* note it */ + Sys_Printf( "--- Convert BSP to OBJ ---\n" ); + + /* create the ase filename from the bsp name */ + strcpy( dirname, bspName ); + StripExtension( dirname ); + strcpy( name, bspName ); + StripExtension( name ); + strcat( name, ".obj" ); + Sys_Printf( "writing %s\n", name ); + strcpy( mtlname, bspName ); + StripExtension( mtlname ); + strcat( mtlname, ".mtl" ); + Sys_Printf( "writing %s\n", mtlname ); + + ExtractFileBase( bspName, base ); + + /* open it */ + f = fopen( name, "wb" ); + if( f == NULL ) + Error( "Open failed on %s\n", name ); + fmtl = fopen( mtlname, "wb" ); + if( fmtl == NULL ) + Error( "Open failed on %s\n", mtlname ); + + /* print header */ + fprintf( f, "o %s\r\n", base ); + fprintf( f, "# Generated by Q3Map2 (ydnar) -convert -format obj\r\n" ); + fprintf( f, "mtllib %s.mtl\r\n", base ); + + fprintf( fmtl, "# Generated by Q3Map2 (ydnar) -convert -format obj\r\n" ); + if(lightmapsAsTexcoord) + { + int lightmapCount; + for( lightmapCount = 0; lightmapCount < numBSPLightmaps; lightmapCount++ ) + ; + for( ; ; lightmapCount++ ) + { + char buf[1024]; + FILE *tmp; + snprintf(buf, sizeof(buf), "%s/lm_%04d.tga", dirname, lightmapCount); + buf[sizeof(buf) - 1] = 0; + tmp = fopen(buf, "rb"); + if(!tmp) + break; + fclose(tmp); + } + lastLightmap = lightmapCount - 1; + } + else + { + for( i = 0; i < numBSPShaders; i++ ) + { + shader = &bspShaders[ i ]; + ConvertShaderToMTL( fmtl, shader, i ); + } + } + + /* walk entity list */ + for( i = 0; i < numEntities; i++ ) + { + /* get entity and model */ + e = &entities[ i ]; + if( i == 0 ) + modelNum = 0; + else + { + key = ValueForKey( e, "model" ); + if( key[ 0 ] != '*' ) + continue; + modelNum = atoi( key + 1 ); + } + model = &bspModels[ modelNum ]; + + /* get entity origin */ + key = ValueForKey( e, "origin" ); + if( key[ 0 ] == '\0' ) + VectorClear( origin ); + else + GetVectorForKey( e, "origin", origin ); + + /* convert model */ + ConvertModelToOBJ( f, model, modelNum, origin ); + } + + if(lightmapsAsTexcoord) + { + for( i = firstLightmap; i <= lastLightmap; i++ ) + ConvertLightmapToMTL( fmtl, base, i ); + } + + /* close the file and return */ + fclose( f ); + fclose( fmtl ); + + /* return to sender */ + return 0; +} + + + diff --git a/tools/quake3/q3map2/decals.c b/tools/quake3/q3map2/decals.c index f4de7cea..a130334f 100644 --- a/tools/quake3/q3map2/decals.c +++ b/tools/quake3/q3map2/decals.c @@ -626,6 +626,7 @@ static void ProjectDecalOntoWinding( decalProjector_t *dp, mapDrawSurface_t *ds, ds2->shaderInfo = dp->si; ds2->fogNum = ds->fogNum; /* why was this -1? */ ds2->lightmapScale = ds->lightmapScale; + ds2->shadeAngleDegrees = ds->shadeAngleDegrees; ds2->numVerts = w->numpoints; ds2->verts = safe_malloc( ds2->numVerts * sizeof( *ds2->verts ) ); memset( ds2->verts, 0, ds2->numVerts * sizeof( *ds2->verts ) ); diff --git a/tools/quake3/q3map2/facebsp.c b/tools/quake3/q3map2/facebsp.c index 270eefe2..9291f564 100644 --- a/tools/quake3/q3map2/facebsp.c +++ b/tools/quake3/q3map2/facebsp.c @@ -89,7 +89,10 @@ static void SelectSplitPlaneNum( node_t *node, face_t *list, int *splitPlaneNum, vec3_t normal; float dist; int planenum; - + float sizeBias; + + //int frontC,backC,splitsC,facingC; + /* ydnar: set some defaults */ *splitPlaneNum = -1; /* leaf */ @@ -118,14 +121,16 @@ static void SelectSplitPlaneNum( node_t *node, face_t *list, int *splitPlaneNum, bestValue = -99999; bestSplit = list; - for( split = list; split; split = split->next ) - split->checked = qfalse; + + // div0: this check causes detail/structural mixes + //for( split = list; split; split = split->next ) + // split->checked = qfalse; for( split = list; split; split = split->next ) { - if ( split->checked ) - continue; - + //if ( split->checked ) + // continue; + plane = &mapplanes[ split->planenum ]; splits = 0; facing = 0; @@ -134,7 +139,7 @@ static void SelectSplitPlaneNum( node_t *node, face_t *list, int *splitPlaneNum, for ( check = list ; check ; check = check->next ) { if ( check->planenum == split->planenum ) { facing++; - check->checked = qtrue; // won't need to test this plane again + //check->checked = qtrue; // won't need to test this plane again continue; } side = WindingOnPlaneSide( check->w, plane->normal, plane->dist ); @@ -146,15 +151,38 @@ static void SelectSplitPlaneNum( node_t *node, face_t *list, int *splitPlaneNum, back++; } } - value = 5*facing - 5*splits; // - abs(front-back); - if ( plane->type < 3 ) { - value+=5; // axial is better + + if(bspAlternateSplitWeights) + { + // from 27 + + //Bigger is better + sizeBias=WindingArea(split->w); + + //Base score = 20000 perfectly balanced + value = 20000-(abs(front-back)); + value -= plane->counter;// If we've already used this plane sometime in the past try not to use it again + value -= facing ; // if we're going to have alot of other surfs use this plane, we want to get it in quickly. + value -= splits*5; //more splits = bad + value += sizeBias*10; //We want a huge score bias based on plane size + } + else + { + value = 5*facing - 5*splits; // - abs(front-back); + if ( plane->type < 3 ) { + value+=5; // axial is better + } } + value += split->priority; // prioritize hints higher if ( value > bestValue ) { bestValue = value; bestSplit = split; + //frontC=front; + //backC=back; + //splitsC=splits; + //facingC=facing; } } @@ -162,9 +190,22 @@ static void SelectSplitPlaneNum( node_t *node, face_t *list, int *splitPlaneNum, if( bestValue == -99999 ) return; + //Sys_FPrintf (SYS_VRB, "F: %d B:%d S:%d FA:%ds\n",frontC,backC,splitsC,facingC ); + /* set best split data */ *splitPlaneNum = bestSplit->planenum; *compileFlags = bestSplit->compileFlags; + +#if 0 + if(bestSplit->compileFlags & C_DETAIL) + for( split = list; split; split = split->next ) + if(!(split->compileFlags & C_DETAIL)) + Sys_FPrintf(SYS_ERR, "DON'T DO SUCH SPLITS (1)\n"); + if((node->compileFlags & C_DETAIL) && !(bestSplit->compileFlags & C_DETAIL)) + Sys_FPrintf(SYS_ERR, "DON'T DO SUCH SPLITS (2)\n"); +#endif + + if (*splitPlaneNum>-1) mapplanes[ *splitPlaneNum ].counter++; } @@ -203,6 +244,7 @@ void BuildFaceTree_r( node_t *node, face_t *list ) winding_t *frontWinding, *backWinding; int i; int splitPlaneNum, compileFlags; + qboolean isstruct = qfalse; /* count faces left */ @@ -215,6 +257,7 @@ void BuildFaceTree_r( node_t *node, face_t *list ) if ( splitPlaneNum == -1 ) { node->planenum = PLANENUM_LEAF; + node->has_structural_children = qfalse; c_faceLeafs++; return; } @@ -222,9 +265,11 @@ void BuildFaceTree_r( node_t *node, face_t *list ) /* partition the list */ node->planenum = splitPlaneNum; node->compileFlags = compileFlags; + node->has_structural_children = !(compileFlags & C_DETAIL) && !node->opaque; plane = &mapplanes[ splitPlaneNum ]; childLists[0] = NULL; childLists[1] = NULL; + for( split = list; split; split = next ) { /* set next */ @@ -236,6 +281,9 @@ void BuildFaceTree_r( node_t *node, face_t *list ) FreeBspFace( split ); continue; } + + if(!(split->compileFlags & C_DETAIL)) + isstruct = 1; /* determine which side the face falls on */ side = WindingOnPlaneSide( split->w, plane->normal, plane->dist ); @@ -290,9 +338,22 @@ void BuildFaceTree_r( node_t *node, face_t *list ) } } +#if 0 + if((node->compileFlags & C_DETAIL) && isstruct) + Sys_FPrintf(SYS_ERR, "I am detail, my child is structural, this is a wtf1\n", node->has_structural_children); +#endif + for ( i = 0 ; i < 2 ; i++ ) { BuildFaceTree_r ( node->children[i], childLists[i]); + node->has_structural_children |= node->children[i]->has_structural_children; } + +#if 0 + if((node->compileFlags & C_DETAIL) && !(node->children[0]->compileFlags & C_DETAIL) && node->children[0]->planenum != PLANENUM_LEAF) + Sys_FPrintf(SYS_ERR, "I am detail, my child is structural\n", node->has_structural_children); + if((node->compileFlags & C_DETAIL) && isstruct) + Sys_FPrintf(SYS_ERR, "I am detail, my child is structural, this is a wtf2\n", node->has_structural_children); +#endif } @@ -324,6 +385,11 @@ tree_t *FaceBSP( face_t *list ) { } Sys_FPrintf( SYS_VRB, "%9d faces\n", count ); + for( i = 0; i < nummapplanes; i++) + { + mapplanes[ i ].counter=0; + } + tree->headnode = AllocNode(); VectorCopy( tree->mins, tree->headnode->mins ); VectorCopy( tree->maxs, tree->headnode->maxs ); @@ -355,7 +421,7 @@ face_t *MakeStructuralBSPFaceList( brush_t *list ) flist = NULL; for( b = list; b != NULL; b = b->next ) { - if( b->detail ) + if( !deepBSP && b->detail ) continue; for( i = 0; i < b->numsides; i++ ) @@ -375,6 +441,8 @@ face_t *MakeStructuralBSPFaceList( brush_t *list ) f->w = CopyWinding( w ); f->planenum = s->planenum & ~1; f->compileFlags = s->compileFlags; /* ydnar */ + if(b->detail) + f->compileFlags |= C_DETAIL; /* ydnar: set priority */ f->priority = 0; @@ -384,6 +452,8 @@ face_t *MakeStructuralBSPFaceList( brush_t *list ) f->priority += ANTIPORTAL_PRIORITY; if( f->compileFlags & C_AREAPORTAL ) f->priority += AREAPORTAL_PRIORITY; + if( f->compileFlags & C_DETAIL ) + f->priority += DETAIL_PRIORITY; /* get next face */ f->next = flist; @@ -413,7 +483,7 @@ face_t *MakeVisibleBSPFaceList( brush_t *list ) flist = NULL; for( b = list; b != NULL; b = b->next ) { - if( b->detail ) + if( !deepBSP && b->detail ) continue; for( i = 0; i < b->numsides; i++ ) @@ -433,6 +503,8 @@ face_t *MakeVisibleBSPFaceList( brush_t *list ) f->w = CopyWinding( w ); f->planenum = s->planenum & ~1; f->compileFlags = s->compileFlags; /* ydnar */ + if(b->detail) + f->compileFlags |= C_DETAIL; /* ydnar: set priority */ f->priority = 0; @@ -442,6 +514,8 @@ face_t *MakeVisibleBSPFaceList( brush_t *list ) f->priority += ANTIPORTAL_PRIORITY; if( f->compileFlags & C_AREAPORTAL ) f->priority += AREAPORTAL_PRIORITY; + if( f->compileFlags & C_DETAIL ) + f->priority += DETAIL_PRIORITY; /* get next face */ f->next = flist; diff --git a/tools/quake3/q3map2/game__null.h b/tools/quake3/q3map2/game__null.h new file mode 100644 index 00000000..c2f24849 --- /dev/null +++ b/tools/quake3/q3map2/game__null.h @@ -0,0 +1,98 @@ +/* ------------------------------------------------------------------------------- + +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef GAME__NULL_H +#define GAME__NULL_H + + + +/* ------------------------------------------------------------------------------- + +content and surface flags +are in game_quake3.h + +------------------------------------------------------------------------------- */ + + + +/* ------------------------------------------------------------------------------- + +game_t struct + +------------------------------------------------------------------------------- */ + +{ + NULL, /* -game x */ + NULL, /* default base game data dir */ + NULL, /* unix home sub-dir */ + NULL, /* magic path word */ + NULL, /* shader directory */ + 0, /* max lightmapped surface verts */ + 0, /* max surface verts */ + 0, /* max surface indexes */ + qfalse, /* flares */ + NULL, /* default flare shader */ + qfalse, /* wolf lighting model? */ + 0, /* lightmap width/height */ + 0, /* lightmap gamma */ + 0, /* lightmap exposure */ + 0, /* lightmap compensate */ + 0, /* lightgrid scale */ + 0, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qfalse, /* disable shader lightstyles hack */ + qfalse, /* keep light entities on bsp */ + 0, /* default patchMeta subdivisions tolerance */ + qfalse, /* patch casting enabled */ + qfalse, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 0, /* minimap size */ + 0, /* minimap sharpener */ + 0, /* minimap border */ + qfalse, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + NULL, /* minimap name format */ + NULL, /* bsp file prefix */ + 0, /* bsp file version */ + qfalse, /* cod-style lump len/ofs order */ + NULL, /* bsp load function */ + NULL, /* bsp write function */ + + { + { NULL, 0, 0, 0, 0, 0, 0 } + } +} + + + +/* end marker */ +#endif + diff --git a/tools/quake3/q3map2/game_darkplaces.h b/tools/quake3/q3map2/game_darkplaces.h new file mode 100644 index 00000000..e91fdb76 --- /dev/null +++ b/tools/quake3/q3map2/game_darkplaces.h @@ -0,0 +1,150 @@ +/* ------------------------------------------------------------------------------- + +Copyright (C) 1999-2006 Id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef GAME_DARKPLACES_H +#define GAME_DARKPLACES_H + +/* content and surface flags get form quake3 */ + +/* ------------------------------------------------------------------------------- + +game_t struct + +------------------------------------------------------------------------------- */ + +{ + "darkplaces", /* -game x */ + "id1", /* default base game data dir */ + ".darkplaces ", /* unix home sub-dir */ + "darkplaces", /* magic path word */ + "scripts", /* shader directory */ + 999, /* max lightmapped surface verts */ + 999, /* max surface verts */ + 6000, /* max surface indexes */ + qfalse, /* flares */ + "flareshader", /* default flare shader */ + qfalse, /* wolf lighting model? */ + 128, /* lightmap width/height */ + 1.0f, /* lightmap gamma */ + 200.0f, /* lightmap exposure */ + 1.0f, /* lightmap compensate */ + 0.3f, /* lightgrid scale */ + 0.6f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qtrue, /* disable shader lightstyles hack */ + qtrue, /* keep light entities on bsp */ + 4, /* default patchMeta subdivisions tolerance */ + qfalse, /* patch casting enabled */ + qfalse, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 0.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "%s.tga", /* minimap name format */ + "IBSP", /* bsp file prefix */ + 46, /* bsp file version */ + qfalse, /* cod-style lump len/ofs order */ + LoadIBSPFile, /* bsp load function */ + WriteIBSPFile, /* bsp write function */ + + { + /* name contentFlags contentFlagsClear surfaceFlags surfaceFlagsClear compileFlags compileFlagsClear */ + + /* default */ + { "default", Q_CONT_SOLID, -1, 0, -1, C_SOLID, -1 }, + + + /* ydnar */ + { "lightgrid", 0, 0, 0, 0, C_LIGHTGRID, 0 }, + { "antiportal", 0, 0, 0, 0, C_ANTIPORTAL, 0 }, + { "skip", 0, 0, 0, 0, C_SKIP, 0 }, + + + /* compiler */ + { "origin", Q_CONT_ORIGIN, Q_CONT_SOLID, 0, 0, C_ORIGIN | C_TRANSLUCENT, C_SOLID }, + { "areaportal", Q_CONT_AREAPORTAL, Q_CONT_SOLID, 0, 0, C_AREAPORTAL | C_TRANSLUCENT, C_SOLID }, + { "trans", Q_CONT_TRANSLUCENT, 0, 0, 0, C_TRANSLUCENT, 0 }, + { "detail", Q_CONT_DETAIL, 0, 0, 0, C_DETAIL, 0 }, + { "structural", Q_CONT_STRUCTURAL, 0, 0, 0, C_STRUCTURAL, 0 }, + { "hint", 0, 0, Q_SURF_HINT, 0, C_HINT, 0 }, + { "nodraw", 0, 0, Q_SURF_NODRAW, 0, C_NODRAW, 0 }, + + { "alphashadow", 0, 0, Q_SURF_ALPHASHADOW, 0, C_ALPHASHADOW | C_TRANSLUCENT, 0 }, + { "lightfilter", 0, 0, Q_SURF_LIGHTFILTER, 0, C_LIGHTFILTER | C_TRANSLUCENT, 0 }, + { "nolightmap", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + { "pointlight", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + + + /* game */ + { "nonsolid", 0, Q_CONT_SOLID, Q_SURF_NONSOLID, 0, 0, C_SOLID }, + + { "trigger", Q_CONT_TRIGGER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "water", Q_CONT_WATER, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "slime", Q_CONT_SLIME, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "lava", Q_CONT_LAVA, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + + { "playerclip", Q_CONT_PLAYERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "monsterclip", Q_CONT_MONSTERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "nodrop", Q_CONT_NODROP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "clusterportal", Q_CONT_CLUSTERPORTAL, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "donotenter", Q_CONT_DONOTENTER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "botclip", Q_CONT_BOTCLIP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "fog", Q_CONT_FOG, Q_CONT_SOLID, 0, 0, C_FOG, C_SOLID }, + { "sky", 0, 0, Q_SURF_SKY, 0, C_SKY, 0 }, + + { "slick", 0, 0, Q_SURF_SLICK, 0, 0, 0 }, + + { "noimpact", 0, 0, Q_SURF_NOIMPACT, 0, 0, 0 }, + { "nomarks", 0, 0, Q_SURF_NOMARKS, 0, C_NOMARKS, 0 }, + { "ladder", 0, 0, Q_SURF_LADDER, 0, 0, 0 }, + { "nodamage", 0, 0, Q_SURF_NODAMAGE, 0, 0, 0 }, + { "metalsteps", 0, 0, Q_SURF_METALSTEPS, 0, 0, 0 }, + { "flesh", 0, 0, Q_SURF_FLESH, 0, 0, 0 }, + { "nosteps", 0, 0, Q_SURF_NOSTEPS, 0, 0, 0 }, + { "nodlight", 0, 0, Q_SURF_NODLIGHT, 0, 0, 0 }, + { "dust", 0, 0, Q_SURF_DUST, 0, 0, 0 }, + + + /* null */ + { NULL, 0, 0, 0, 0, 0, 0 } + } +} + + + +/* end marker */ +#endif + diff --git a/tools/quake3/q3map2/game_dq.h b/tools/quake3/q3map2/game_dq.h new file mode 100644 index 00000000..97d2d6d5 --- /dev/null +++ b/tools/quake3/q3map2/game_dq.h @@ -0,0 +1,150 @@ +/* ------------------------------------------------------------------------------- + +Copyright (C) 1999-2006 Id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef GAME_DQ_H +#define GAME_DQ_H + +/* content and surface flags get form quake3 */ + +/* ------------------------------------------------------------------------------- + +game_t struct + +------------------------------------------------------------------------------- */ + +{ + "dq", /* -game x */ + "basedq", /* default base game data dir */ + ".dq", /* unix home sub-dir */ + "dq", /* magic path word */ + "scripts", /* shader directory */ + 64, /* max lightmapped surface verts */ + 999, /* max surface verts */ + 6000, /* max surface indexes */ + qfalse, /* flares */ + "flareshader", /* default flare shader */ + qfalse, /* wolf lighting model? */ + 128, /* lightmap width/height */ + 1.2f, /* lightmap gamma */ + 200.0f, /* lightmap exposure */ + 1.0f, /* lightmap compensate */ + 0.3f, /* lightgrid scale */ + 0.6f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qtrue, /* disable shader lightstyles hack */ + qtrue, /* keep light entities on bsp */ + 4, /* default patchMeta subdivisions tolerance */ + qtrue, /* patch casting enabled */ + qtrue, /* compile deluxemaps */ + 1, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 0.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "%s.tga", /* minimap name format */ + "IBSP", /* bsp file prefix */ + 46, /* bsp file version */ + qfalse, /* cod-style lump len/ofs order */ + LoadIBSPFile, /* bsp load function */ + WriteIBSPFile, /* bsp write function */ + + { + /* name contentFlags contentFlagsClear surfaceFlags surfaceFlagsClear compileFlags compileFlagsClear */ + + /* default */ + { "default", Q_CONT_SOLID, -1, 0, -1, C_SOLID, -1 }, + + + /* ydnar */ + { "lightgrid", 0, 0, 0, 0, C_LIGHTGRID, 0 }, + { "antiportal", 0, 0, 0, 0, C_ANTIPORTAL, 0 }, + { "skip", 0, 0, 0, 0, C_SKIP, 0 }, + + + /* compiler */ + { "origin", Q_CONT_ORIGIN, Q_CONT_SOLID, 0, 0, C_ORIGIN | C_TRANSLUCENT, C_SOLID }, + { "areaportal", Q_CONT_AREAPORTAL, Q_CONT_SOLID, 0, 0, C_AREAPORTAL | C_TRANSLUCENT, C_SOLID }, + { "trans", Q_CONT_TRANSLUCENT, 0, 0, 0, C_TRANSLUCENT, 0 }, + { "detail", Q_CONT_DETAIL, 0, 0, 0, C_DETAIL, 0 }, + { "structural", Q_CONT_STRUCTURAL, 0, 0, 0, C_STRUCTURAL, 0 }, + { "hint", 0, 0, Q_SURF_HINT, 0, C_HINT, 0 }, + { "nodraw", 0, 0, Q_SURF_NODRAW, 0, C_NODRAW, 0 }, + + { "alphashadow", 0, 0, Q_SURF_ALPHASHADOW, 0, C_ALPHASHADOW | C_TRANSLUCENT, 0 }, + { "lightfilter", 0, 0, Q_SURF_LIGHTFILTER, 0, C_LIGHTFILTER | C_TRANSLUCENT, 0 }, + { "nolightmap", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + { "pointlight", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + + + /* game */ + { "nonsolid", 0, Q_CONT_SOLID, Q_SURF_NONSOLID, 0, 0, C_SOLID }, + + { "trigger", Q_CONT_TRIGGER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "water", Q_CONT_WATER, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "slime", Q_CONT_SLIME, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "lava", Q_CONT_LAVA, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + + { "playerclip", Q_CONT_PLAYERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "monsterclip", Q_CONT_MONSTERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "nodrop", Q_CONT_NODROP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "clusterportal", Q_CONT_CLUSTERPORTAL, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "donotenter", Q_CONT_DONOTENTER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "botclip", Q_CONT_BOTCLIP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "fog", Q_CONT_FOG, Q_CONT_SOLID, 0, 0, C_FOG, C_SOLID }, + { "sky", 0, 0, Q_SURF_SKY, 0, C_SKY, 0 }, + + { "slick", 0, 0, Q_SURF_SLICK, 0, 0, 0 }, + + { "noimpact", 0, 0, Q_SURF_NOIMPACT, 0, 0, 0 }, + { "nomarks", 0, 0, Q_SURF_NOMARKS, 0, C_NOMARKS, 0 }, + { "ladder", 0, 0, Q_SURF_LADDER, 0, 0, 0 }, + { "nodamage", 0, 0, Q_SURF_NODAMAGE, 0, 0, 0 }, + { "metalsteps", 0, 0, Q_SURF_METALSTEPS, 0, 0, 0 }, + { "flesh", 0, 0, Q_SURF_FLESH, 0, 0, 0 }, + { "nosteps", 0, 0, Q_SURF_NOSTEPS, 0, 0, 0 }, + { "nodlight", 0, 0, Q_SURF_NODLIGHT, 0, 0, 0 }, + { "dust", 0, 0, Q_SURF_DUST, 0, 0, 0 }, + + + /* null */ + { NULL, 0, 0, 0, 0, 0, 0 } + } +} + + + +/* end marker */ +#endif + diff --git a/tools/quake3/q3map2/game_ef.h b/tools/quake3/q3map2/game_ef.h index f8d21d1a..84ea664c 100644 --- a/tools/quake3/q3map2/game_ef.h +++ b/tools/quake3/q3map2/game_ef.h @@ -113,7 +113,23 @@ game_t struct qfalse, /* wolf lighting model? */ 128, /* lightmap width/height */ 1.0f, /* lightmap gamma */ + 1.0f, /* lightmap exposure */ 1.0f, /* lightmap compensate */ + 1.0f, /* lightgrid scale */ + 1.0f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qfalse, /* disable shader lightstyles hack */ + qfalse, /* keep light entities on bsp */ + 8, /* default patchMeta subdivisions tolerance */ + qfalse, /* patch casting enabled */ + qfalse, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 0.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "%s.tga", /* minimap name format */ "IBSP", /* bsp file prefix */ 46, /* bsp file version */ qfalse, /* cod-style lump len/ofs order */ diff --git a/tools/quake3/q3map2/game_etut.h b/tools/quake3/q3map2/game_etut.h index 9823ff96..8add5bbe 100644 --- a/tools/quake3/q3map2/game_etut.h +++ b/tools/quake3/q3map2/game_etut.h @@ -148,7 +148,23 @@ game_t struct qfalse, /* wolf lighting model? */ 128, /* lightmap width/height */ 2.2f, /* lightmap gamma */ + 1.0f, /* lightmap exposure */ 1.0f, /* lightmap compensate */ + 1.0f, /* lightgrid scale */ + 1.0f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qfalse, /* disable shader lightstyles hack */ + qfalse, /* keep light entities on bsp */ + 8, /* default patchMeta subdivisions tolerance */ + qfalse, /* patch casting enabled */ + qfalse, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 0.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "%s.tga", /* minimap name format */ "IBSP", /* bsp file prefix */ 47, /* bsp file version */ qfalse, /* cod-style lump len/ofs order */ diff --git a/tools/quake3/q3map2/game_ja.h b/tools/quake3/q3map2/game_ja.h index 79007ed6..3d25129e 100644 --- a/tools/quake3/q3map2/game_ja.h +++ b/tools/quake3/q3map2/game_ja.h @@ -67,7 +67,23 @@ game_t struct qfalse, /* wolf lighting model? */ 128, /* lightmap width/height */ 1.0f, /* lightmap gamma */ + 1.0f, /* lightmap exposure */ 1.0f, /* lightmap compensate */ + 1.0f, /* lightgrid scale */ + 1.0f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qfalse, /* disable shader lightstyles hack */ + qfalse, /* keep light entities on bsp */ + 8, /* default patchMeta subdivisions tolerance */ + qfalse, /* patch casting enabled */ + qfalse, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 0.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "%s.tga", /* minimap name format */ "RBSP", /* bsp file prefix */ 1, /* bsp file version */ qfalse, /* cod-style lump len/ofs order */ diff --git a/tools/quake3/q3map2/game_jk2.h b/tools/quake3/q3map2/game_jk2.h index a8dc01a0..056baf01 100644 --- a/tools/quake3/q3map2/game_jk2.h +++ b/tools/quake3/q3map2/game_jk2.h @@ -64,7 +64,23 @@ game_t struct qfalse, /* wolf lighting model? */ 128, /* lightmap width/height */ 1.0f, /* lightmap gamma */ + 1.0f, /* lightmap exposure */ 1.0f, /* lightmap compensate */ + 1.0f, /* lightgrid scale */ + 1.0f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qfalse, /* disable shader lightstyles hack */ + qfalse, /* keep light entities on bsp */ + 8, /* default patchMeta subdivisions tolerance */ + qfalse, /* patch casting enabled */ + qfalse, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 0.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "%s.tga", /* minimap name format */ "RBSP", /* bsp file prefix */ 1, /* bsp file version */ qfalse, /* cod-style lump len/ofs order */ diff --git a/tools/quake3/q3map2/game_nexuiz.h b/tools/quake3/q3map2/game_nexuiz.h index 0d23766d..4d496c33 100644 --- a/tools/quake3/q3map2/game_nexuiz.h +++ b/tools/quake3/q3map2/game_nexuiz.h @@ -63,7 +63,23 @@ game_t struct qfalse, /* wolf lighting model? */ 128, /* lightmap width/height */ 1.0f, /* lightmap gamma */ + 1.0f, /* lightmap exposure */ 1.0f, /* lightmap compensate */ + 1.0f, /* lightgrid scale */ + 1.0f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qtrue, /* disable shader lightstyles hack */ + qtrue, /* keep light entities on bsp */ + 8, /* default patchMeta subdivisions tolerance */ + qfalse, /* patch casting enabled */ + qfalse, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 1.0f/66.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "../gfx/%s_mini.tga", /* minimap name format */ "IBSP", /* bsp file prefix */ 46, /* bsp file version */ qfalse, /* cod-style lump len/ofs order */ @@ -130,6 +146,7 @@ game_t struct { "nodlight", 0, 0, Q_SURF_NODLIGHT, 0, 0, 0 }, { "dust", 0, 0, Q_SURF_DUST, 0, 0, 0 }, + /* null */ { NULL, 0, 0, 0, 0, 0, 0 } } diff --git a/tools/quake3/q3map2/game_prophecy.h b/tools/quake3/q3map2/game_prophecy.h new file mode 100644 index 00000000..60e299d3 --- /dev/null +++ b/tools/quake3/q3map2/game_prophecy.h @@ -0,0 +1,150 @@ +/* ------------------------------------------------------------------------------- + +Copyright (C) 1999-2006 Id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef GAME_PROPHECY_H +#define GAME_PROPHECY_H + +/* content and surface flags get form quake3 */ + +/* ------------------------------------------------------------------------------- + +game_t struct + +------------------------------------------------------------------------------- */ + +{ + "prophecy", /* -game x */ + "base", /* default base game data dir */ + ".prophecy", /* unix home sub-dir */ + "prophecy", /* magic path word */ + "scripts", /* shader directory */ + 64, /* max lightmapped surface verts */ + 999, /* max surface verts */ + 6000, /* max surface indexes */ + qfalse, /* flares */ + "flareshader", /* default flare shader */ + qfalse, /* wolf lighting model? */ + 128, /* lightmap width/height */ + 1.0f, /* lightmap gamma */ + 200.0f, /* lightmap exposure */ + 1.0f, /* lightmap compensate */ + 0.4f, /* lightgrid scale */ + 0.6f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qtrue, /* disable shader lightstyles hack */ + qtrue, /* keep light entities on bsp */ + 4, /* default patchMeta subdivisions tolerance */ + qtrue, /* patch casting enabled */ + qtrue, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 0.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "%s.tga", /* minimap name format */ + "IBSP", /* bsp file prefix */ + 46, /* bsp file version */ + qfalse, /* cod-style lump len/ofs order */ + LoadIBSPFile, /* bsp load function */ + WriteIBSPFile, /* bsp write function */ + + { + /* name contentFlags contentFlagsClear surfaceFlags surfaceFlagsClear compileFlags compileFlagsClear */ + + /* default */ + { "default", Q_CONT_SOLID, -1, 0, -1, C_SOLID, -1 }, + + + /* ydnar */ + { "lightgrid", 0, 0, 0, 0, C_LIGHTGRID, 0 }, + { "antiportal", 0, 0, 0, 0, C_ANTIPORTAL, 0 }, + { "skip", 0, 0, 0, 0, C_SKIP, 0 }, + + + /* compiler */ + { "origin", Q_CONT_ORIGIN, Q_CONT_SOLID, 0, 0, C_ORIGIN | C_TRANSLUCENT, C_SOLID }, + { "areaportal", Q_CONT_AREAPORTAL, Q_CONT_SOLID, 0, 0, C_AREAPORTAL | C_TRANSLUCENT, C_SOLID }, + { "trans", Q_CONT_TRANSLUCENT, 0, 0, 0, C_TRANSLUCENT, 0 }, + { "detail", Q_CONT_DETAIL, 0, 0, 0, C_DETAIL, 0 }, + { "structural", Q_CONT_STRUCTURAL, 0, 0, 0, C_STRUCTURAL, 0 }, + { "hint", 0, 0, Q_SURF_HINT, 0, C_HINT, 0 }, + { "nodraw", 0, 0, Q_SURF_NODRAW, 0, C_NODRAW, 0 }, + + { "alphashadow", 0, 0, Q_SURF_ALPHASHADOW, 0, C_ALPHASHADOW | C_TRANSLUCENT, 0 }, + { "lightfilter", 0, 0, Q_SURF_LIGHTFILTER, 0, C_LIGHTFILTER | C_TRANSLUCENT, 0 }, + { "nolightmap", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + { "pointlight", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + + + /* game */ + { "nonsolid", 0, Q_CONT_SOLID, Q_SURF_NONSOLID, 0, 0, C_SOLID }, + + { "trigger", Q_CONT_TRIGGER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "water", Q_CONT_WATER, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "slime", Q_CONT_SLIME, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "lava", Q_CONT_LAVA, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + + { "playerclip", Q_CONT_PLAYERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "monsterclip", Q_CONT_MONSTERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "nodrop", Q_CONT_NODROP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "clusterportal", Q_CONT_CLUSTERPORTAL, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "donotenter", Q_CONT_DONOTENTER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "botclip", Q_CONT_BOTCLIP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "fog", Q_CONT_FOG, Q_CONT_SOLID, 0, 0, C_FOG, C_SOLID }, + { "sky", 0, 0, Q_SURF_SKY, 0, C_SKY, 0 }, + + { "slick", 0, 0, Q_SURF_SLICK, 0, 0, 0 }, + + { "noimpact", 0, 0, Q_SURF_NOIMPACT, 0, 0, 0 }, + { "nomarks", 0, 0, Q_SURF_NOMARKS, 0, C_NOMARKS, 0 }, + { "ladder", 0, 0, Q_SURF_LADDER, 0, 0, 0 }, + { "nodamage", 0, 0, Q_SURF_NODAMAGE, 0, 0, 0 }, + { "metalsteps", 0, 0, Q_SURF_METALSTEPS, 0, 0, 0 }, + { "flesh", 0, 0, Q_SURF_FLESH, 0, 0, 0 }, + { "nosteps", 0, 0, Q_SURF_NOSTEPS, 0, 0, 0 }, + { "nodlight", 0, 0, Q_SURF_NODLIGHT, 0, 0, 0 }, + { "dust", 0, 0, Q_SURF_DUST, 0, 0, 0 }, + + + /* null */ + { NULL, 0, 0, 0, 0, 0, 0 } + } +} + + + +/* end marker */ +#endif + diff --git a/tools/quake3/q3map2/game_qfusion.h b/tools/quake3/q3map2/game_qfusion.h index 43c27fc5..7645ad0a 100644 --- a/tools/quake3/q3map2/game_qfusion.h +++ b/tools/quake3/q3map2/game_qfusion.h @@ -115,7 +115,23 @@ game_t struct qfalse, /* wolf lighting model? */ 512, /* lightmap width/height */ 1.0f, /* lightmap gamma */ + 1.0f, /* lightmap exposure */ 1.0f, /* lightmap compensate */ + 1.0f, /* lightgrid scale */ + 1.0f, /* lightgrid ambient scale */ + qtrue, /* light angle attenuation uses half-lambert curve */ + qtrue, /* disable shader lightstyles hack */ + qtrue, /* keep light entities on bsp */ + 8, /* default patchMeta subdivisions tolerance */ + qtrue, /* patch casting enabled */ + qtrue, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 256, /* minimap size */ + 1.0f, /* minimap sharpener */ + 0.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_WHITE, /* minimap mode */ + "../minimaps/%s.tga", /* minimap name format */ "FBSP", /* bsp file prefix */ 1, /* bsp file version */ qfalse, /* cod-style lump len/ofs order */ diff --git a/tools/quake3/q3map2/game_quake3.h b/tools/quake3/q3map2/game_quake3.h index be1f3397..98d4c4b8 100644 --- a/tools/quake3/q3map2/game_quake3.h +++ b/tools/quake3/q3map2/game_quake3.h @@ -112,7 +112,23 @@ game_t struct qfalse, /* wolf lighting model? */ 128, /* lightmap width/height */ 1.0f, /* lightmap gamma */ + 1.0f, /* lightmap exposure */ 1.0f, /* lightmap compensate */ + 1.0f, /* lightgrid scale */ + 1.0f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qfalse, /* disable shader lightstyles hack */ + qfalse, /* keep light entities on bsp */ + 8, /* default patchMeta subdivisions tolerance */ + qfalse, /* patch casting enabled */ + qfalse, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 0.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "%s.tga", /* minimap name format */ "IBSP", /* bsp file prefix */ 46, /* bsp file version */ qfalse, /* cod-style lump len/ofs order */ diff --git a/tools/quake3/q3map2/game_quakelive.h b/tools/quake3/q3map2/game_quakelive.h index 18fd90f3..1a509272 100644 --- a/tools/quake3/q3map2/game_quakelive.h +++ b/tools/quake3/q3map2/game_quakelive.h @@ -52,9 +52,9 @@ game_t struct { "quakelive", /* -game x */ - "baseq3", /* default base game data dir */ - ".q3a", /* unix home sub-dir */ - "quake", /* magic path word */ + "baseq3", /* default base game data dir (FIXME what does quake live really use?) */ + ".q3a", /* unix home sub-dir (FIXME what does quake live really use?) */ + "quake", /* magic path word (FIXME where does quake live install to?) */ "scripts", /* shader directory */ 64, /* max lightmapped surface verts */ 999, /* max surface verts */ @@ -64,7 +64,23 @@ game_t struct qfalse, /* wolf lighting model? */ 128, /* lightmap width/height */ 1.0f, /* lightmap gamma */ + 1.0f, /* lightmap exposure */ 1.0f, /* lightmap compensate */ + 1.0f, /* lightgrid scale */ + 1.0f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qfalse, /* disable shader lightstyles hack */ + qfalse, /* keep light entities on bsp */ + 8, /* default patchMeta subdivisions tolerance */ + qfalse, /* patch casting enabled */ + qfalse, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 0.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "%s.tga", /* minimap name format */ "IBSP", /* bsp file prefix */ 47, /* bsp file version */ qfalse, /* cod-style lump len/ofs order */ diff --git a/tools/quake3/q3map2/game_reaction.h b/tools/quake3/q3map2/game_reaction.h index 22e3e8ef..c81e7245 100644 --- a/tools/quake3/q3map2/game_reaction.h +++ b/tools/quake3/q3map2/game_reaction.h @@ -84,7 +84,23 @@ game_t struct qfalse, /* wolf lighting model? */ 128, /* lightmap width/height */ 1.0f, /* lightmap gamma */ + 1.0f, /* lightmap exposure */ 1.0f, /* lightmap compensate */ + 1.0f, /* lightgrid scale */ + 1.0f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qfalse, /* disable shader lightstyles hack */ + qfalse, /* keep light entities on bsp */ + 8, /* default patchMeta subdivisions tolerance */ + qfalse, /* patch casting enabled */ + qfalse, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 0.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "%s.tga", /* minimap name format */ "IBSP", /* bsp file prefix */ 46, /* bsp file version */ qfalse, /* cod-style lump len/ofs order */ diff --git a/tools/quake3/q3map2/game_sof2.h b/tools/quake3/q3map2/game_sof2.h index c9760392..931ec69c 100644 --- a/tools/quake3/q3map2/game_sof2.h +++ b/tools/quake3/q3map2/game_sof2.h @@ -139,7 +139,23 @@ game_t struct qfalse, /* wolf lighting model? */ 128, /* lightmap width/height */ 1.0f, /* lightmap gamma */ + 1.0f, /* lightmap exposure */ 1.0f, /* lightmap compensate */ + 1.0f, /* lightgrid scale */ + 1.0f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qfalse, /* disable shader lightstyles hack */ + qfalse, /* keep light entities on bsp */ + 8, /* default patchMeta subdivisions tolerance */ + qfalse, /* patch casting enabled */ + qfalse, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 0.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "%s.tga", /* minimap name format */ "RBSP", /* bsp file prefix */ 1, /* bsp file version */ qfalse, /* cod-style lump len/ofs order */ diff --git a/tools/quake3/q3map2/game_tenebrae.h b/tools/quake3/q3map2/game_tenebrae.h index 355c9263..ab312158 100644 --- a/tools/quake3/q3map2/game_tenebrae.h +++ b/tools/quake3/q3map2/game_tenebrae.h @@ -112,7 +112,23 @@ game_t struct qfalse, /* wolf lighting model? */ 512, /* lightmap width/height */ 2.0f, /* lightmap gamma */ + 1.0f, /* lightmap exposure */ 1.0f, /* lightmap compensate */ + 1.0f, /* lightgrid scale */ + 1.0f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qtrue, /* disable shader lightstyles hack */ + qfalse, /* keep light entities on bsp */ + 8, /* default patchMeta subdivisions tolerance */ + qfalse, /* patch casting enabled */ + qtrue, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 0.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "%s.tga", /* minimap name format */ "IBSP", /* bsp file prefix */ 46, /* bsp file version */ qfalse, /* cod-style lump len/ofs order */ diff --git a/tools/quake3/q3map2/game_tremulous.h b/tools/quake3/q3map2/game_tremulous.h index 9864cb9c..5d422629 100644 --- a/tools/quake3/q3map2/game_tremulous.h +++ b/tools/quake3/q3map2/game_tremulous.h @@ -70,7 +70,23 @@ game_t struct qfalse, /* wolf lighting model? */ 128, /* lightmap width/height */ 1.0f, /* lightmap gamma */ + 1.0f, /* lightmap exposure */ 1.0f, /* lightmap compensate */ + 1.0f, /* lightgrid scale */ + 1.0f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qfalse, /* disable shader lightstyles hack */ + qfalse, /* keep light entities on bsp */ + 8, /* default patchMeta subdivisions tolerance */ + qfalse, /* patch casting enabled */ + qfalse, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 0.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "%s.tga", /* minimap name format */ "IBSP", /* bsp file prefix */ 46, /* bsp file version */ qfalse, /* cod-style lump len/ofs order */ diff --git a/tools/quake3/q3map2/game_wolf.h b/tools/quake3/q3map2/game_wolf.h index 3200d162..157bfe3a 100644 --- a/tools/quake3/q3map2/game_wolf.h +++ b/tools/quake3/q3map2/game_wolf.h @@ -129,7 +129,23 @@ game_t struct qtrue, /* wolf lighting model? */ 128, /* lightmap width/height */ 1.0f, /* lightmap gamma */ + 1.0f, /* lightmap exposure */ 1.0f, /* lightmap compensate */ + 1.0f, /* lightgrid scale */ + 1.0f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qfalse, /* disable shader lightstyles hack */ + qfalse, /* keep light entities on bsp */ + 8, /* default patchMeta subdivisions tolerance */ + qfalse, /* patch casting enabled */ + qfalse, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 0.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "%s.tga", /* minimap name format */ "IBSP", /* bsp file prefix */ 47, /* bsp file version */ qfalse, /* cod-style lump len/ofs order */ diff --git a/tools/quake3/q3map2/game_wolfet.h b/tools/quake3/q3map2/game_wolfet.h index a6ca181f..3495f0dc 100644 --- a/tools/quake3/q3map2/game_wolfet.h +++ b/tools/quake3/q3map2/game_wolfet.h @@ -66,7 +66,23 @@ game_t struct qtrue, /* wolf lighting model? */ 128, /* lightmap width/height */ 1.0f, /* lightmap gamma */ + 1.0f, /* lightmap exposure */ 1.0f, /* lightmap compensate */ + 1.0f, /* lightgrid scale */ + 1.0f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qfalse, /* disable shader lightstyles hack */ + qfalse, /* keep light entities on bsp */ + 8, /* default patchMeta subdivisions tolerance */ + qfalse, /* patch casting enabled */ + qfalse, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 0.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "%s.tga", /* minimap name format */ "IBSP", /* bsp file prefix */ 47, /* bsp file version */ qfalse, /* cod-style lump len/ofs order */ diff --git a/tools/quake3/q3map2/game_xonotic.h b/tools/quake3/q3map2/game_xonotic.h new file mode 100644 index 00000000..568c263e --- /dev/null +++ b/tools/quake3/q3map2/game_xonotic.h @@ -0,0 +1,155 @@ +/* ------------------------------------------------------------------------------- + +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +---------------------------------------------------------------------------------- + +This code has been altered significantly from its original form, to support +several games based on the Quake III Arena engine, in the form of "Q3Map2." + +------------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef GAME_XONOTIC_H +#define GAME_XONOTIC_H + + + +/* ------------------------------------------------------------------------------- + +content and surface flags +are in game_quake3.h + +------------------------------------------------------------------------------- */ + + + +/* ------------------------------------------------------------------------------- + +game_t struct + +------------------------------------------------------------------------------- */ + +{ + "xonotic", /* -game x */ + "data", /* default base game data dir */ + ".xonotic", /* unix home sub-dir */ + "xonotic", /* magic path word */ + "scripts", /* shader directory */ + 1048575, /* max lightmapped surface verts */ + 1048575, /* max surface verts */ + 1048575, /* max surface indexes */ + qfalse, /* flares */ + "flareshader", /* default flare shader */ + qfalse, /* wolf lighting model? */ + 128, /* lightmap width/height */ + 1.0f, /* lightmap gamma */ + 1.0f, /* lightmap exposure */ + 1.0f, /* lightmap compensate */ + 1.0f, /* lightgrid scale */ + 1.0f, /* lightgrid ambient scale */ + qfalse, /* light angle attenuation uses half-lambert curve */ + qtrue, /* disable shader lightstyles hack */ + qtrue, /* keep light entities on bsp */ + 4, /* default patchMeta subdivisions tolerance */ + qtrue, /* patch casting enabled */ + qtrue, /* compile deluxemaps */ + 0, /* deluxemaps default mode */ + 512, /* minimap size */ + 1.0f, /* minimap sharpener */ + 1.0f/66.0f, /* minimap border */ + qtrue, /* minimap keep aspect */ + MINIMAP_MODE_GRAY, /* minimap mode */ + "../gfx/%s_mini.tga", /* minimap name format */ + "IBSP", /* bsp file prefix */ + 46, /* bsp file version */ + qfalse, /* cod-style lump len/ofs order */ + LoadIBSPFile, /* bsp load function */ + WriteIBSPFile, /* bsp write function */ + + { + /* name contentFlags contentFlagsClear surfaceFlags surfaceFlagsClear compileFlags compileFlagsClear */ + + /* default */ + { "default", Q_CONT_SOLID, -1, 0, -1, C_SOLID, -1 }, + + /* ydnar */ + { "lightgrid", 0, 0, 0, 0, C_LIGHTGRID, 0 }, + { "antiportal", 0, 0, 0, 0, C_ANTIPORTAL, 0 }, + { "skip", 0, 0, 0, 0, C_SKIP, 0 }, + + /* compiler */ + { "origin", Q_CONT_ORIGIN, Q_CONT_SOLID, 0, 0, C_ORIGIN | C_TRANSLUCENT, C_SOLID }, + { "areaportal", Q_CONT_AREAPORTAL, Q_CONT_SOLID, 0, 0, C_AREAPORTAL | C_TRANSLUCENT, C_SOLID }, + { "trans", Q_CONT_TRANSLUCENT, 0, 0, 0, C_TRANSLUCENT, 0 }, + { "detail", Q_CONT_DETAIL, 0, 0, 0, C_DETAIL, 0 }, + { "structural", Q_CONT_STRUCTURAL, 0, 0, 0, C_STRUCTURAL, 0 }, + { "hint", 0, 0, Q_SURF_HINT, 0, C_HINT, 0 }, + { "nodraw", 0, 0, Q_SURF_NODRAW, 0, C_NODRAW, 0 }, + + { "alphashadow", 0, 0, Q_SURF_ALPHASHADOW, 0, C_ALPHASHADOW | C_TRANSLUCENT, 0 }, + { "lightfilter", 0, 0, Q_SURF_LIGHTFILTER, 0, C_LIGHTFILTER | C_TRANSLUCENT, 0 }, + { "nolightmap", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + { "pointlight", 0, 0, Q_SURF_VERTEXLIT, 0, C_VERTEXLIT, 0 }, + + /* game */ + { "nonsolid", 0, Q_CONT_SOLID, Q_SURF_NONSOLID, 0, 0, C_SOLID }, + + { "trigger", Q_CONT_TRIGGER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "water", Q_CONT_WATER, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "slime", Q_CONT_SLIME, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + { "lava", Q_CONT_LAVA, Q_CONT_SOLID, 0, 0, C_LIQUID | C_TRANSLUCENT, C_SOLID }, + + { "playerclip", Q_CONT_PLAYERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "monsterclip", Q_CONT_MONSTERCLIP, Q_CONT_SOLID, 0, 0, C_DETAIL | C_TRANSLUCENT, C_SOLID }, + { "nodrop", Q_CONT_NODROP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "clusterportal", Q_CONT_CLUSTERPORTAL, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "donotenter", Q_CONT_DONOTENTER, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + { "botclip", Q_CONT_BOTCLIP, Q_CONT_SOLID, 0, 0, C_TRANSLUCENT, C_SOLID }, + + { "fog", Q_CONT_FOG, Q_CONT_SOLID, 0, 0, C_FOG, C_SOLID }, + { "sky", 0, 0, Q_SURF_SKY, 0, C_SKY, 0 }, + + { "slick", 0, 0, Q_SURF_SLICK, 0, 0, 0 }, + + { "noimpact", 0, 0, Q_SURF_NOIMPACT, 0, 0, 0 }, + { "nomarks", 0, 0, Q_SURF_NOMARKS, 0, C_NOMARKS, 0 }, + { "ladder", 0, 0, Q_SURF_LADDER, 0, 0, 0 }, + { "nodamage", 0, 0, Q_SURF_NODAMAGE, 0, 0, 0 }, + { "metalsteps", 0, 0, Q_SURF_METALSTEPS, 0, 0, 0 }, + { "flesh", 0, 0, Q_SURF_FLESH, 0, 0, 0 }, + { "nosteps", 0, 0, Q_SURF_NOSTEPS, 0, 0, 0 }, + { "nodlight", 0, 0, Q_SURF_NODLIGHT, 0, 0, 0 }, + { "dust", 0, 0, Q_SURF_DUST, 0, 0, 0 }, + + /* null */ + { NULL, 0, 0, 0, 0, 0, 0 } + } +} + + + +/* end marker */ +#endif + diff --git a/tools/quake3/q3map2/image.c b/tools/quake3/q3map2/image.c index 0ddcaf86..0289e77c 100644 --- a/tools/quake3/q3map2/image.c +++ b/tools/quake3/q3map2/image.c @@ -99,7 +99,7 @@ note: this function is a total hack, as it reads/writes the png struct directly! typedef struct pngBuffer_s { byte *buffer; - int size, offset; + png_size_t size, offset; } pngBuffer_t; @@ -127,8 +127,8 @@ static void LoadPNGBuffer( byte *buffer, int size, byte **pixels, int *width, in png_struct *png; png_info *info, *end; pngBuffer_t pb; - int i, bitDepth, colorType, channels; - png_uint_32 w, h; + int bitDepth, colorType, channels; + png_uint_32 w, h, i; byte **rowPointers; diff --git a/tools/quake3/q3map2/leakfile.c b/tools/quake3/q3map2/leakfile.c index 51fda300..fc5a3191 100644 --- a/tools/quake3/q3map2/leakfile.c +++ b/tools/quake3/q3map2/leakfile.c @@ -81,15 +81,15 @@ xmlNodePtr LeakFile (tree_t *tree) if (!linefile) Error ("Couldn't open %s\n", filename); - xml_node = xmlNewNode (NULL, "polyline"); + xml_node = xmlNewNode (NULL, (xmlChar*)"polyline"); count = 0; node = &tree->outside_node; while (node->occupied > 1) { int next; - portal_t *p, *nextportal; - node_t *nextnode; + portal_t *p, *nextportal = NULL; + node_t *nextnode = NULL; int s; // find the best portal exit diff --git a/tools/quake3/q3map2/light.c b/tools/quake3/q3map2/light.c index 8520edd7..9323b8c8 100644 --- a/tools/quake3/q3map2/light.c +++ b/tools/quake3/q3map2/light.c @@ -313,7 +313,15 @@ void CreateEntityLights( void ) flags |= LIGHT_GRID; flags &= ~LIGHT_SURFACES; } - + + /* vortex: unnormalized? */ + if (spawnflags & 32) + flags |= LIGHT_UNNORMALIZED; + + /* vortex: distance atten? */ + if (spawnflags & 64) + flags |= LIGHT_ATTEN_DISTANCE; + /* store the flags */ light->flags = flags; @@ -385,14 +393,21 @@ void CreateEntityLights( void ) if( _color && _color[ 0 ] ) { sscanf( _color, "%f %f %f", &light->color[ 0 ], &light->color[ 1 ], &light->color[ 2 ] ); - ColorNormalize( light->color, light->color ); + if (!(light->flags & LIGHT_UNNORMALIZED)) + { + ColorNormalize( light->color, light->color ); + } } else light->color[ 0 ] = light->color[ 1 ] = light->color[ 2 ] = 1.0f; + + light->extraDist = FloatForKey( e, "_extradist" ); + if(light->extraDist == 0.0f) + light->extraDist = extraDist; intensity = intensity * pointScale; light->photons = intensity; - + light->type = EMIT_POINT; /* set falloff threshold */ @@ -734,13 +749,21 @@ int LightContributionToSample( trace_t *trace ) float angle; float add; float dist; - + float addDeluxe = 0.0f, addDeluxeBounceScale = 0.25f; + qboolean angledDeluxe = qtrue; + float colorBrightness; + qboolean doAddDeluxe = qtrue; /* get light */ light = trace->light; /* clear color */ + trace->forceSubsampling = 0.0f; /* to make sure */ VectorClear( trace->color ); + VectorClear( trace->colorNoShadow ); + VectorClear( trace->directionContribution ); + + colorBrightness = RGBTOGRAY( light->color ) * ( 1.0f/255.0f ); /* ydnar: early out */ if( !(light->flags & LIGHT_SURFACES) || light->envelope <= 0.0f ) @@ -766,7 +789,6 @@ int LightContributionToSample( trace_t *trace ) float d; vec3_t pushedOrigin; - /* project sample point into light plane */ d = DotProduct( trace->origin, light->normal ) - light->dist; if( d < 3.0f ) @@ -781,7 +803,7 @@ int LightContributionToSample( trace_t *trace ) } /* nudge the point so that it is clearly forward of the light */ - /* so that surfaces meeting a light emiter don't get black edges */ + /* so that surfaces meeting a light emitter don't get black edges */ if( d > -8.0f && d < 8.0f ) VectorMA( trace->origin, (8.0f - d), light->normal, pushedOrigin ); else @@ -800,8 +822,13 @@ int LightContributionToSample( trace_t *trace ) angle = DotProduct( trace->normal, trace->direction ); /* twosided lighting */ - if( trace->twoSided ) - angle = fabs( angle ); + if( trace->twoSided && angle < 0 ) + { + angle = -angle; + + /* no deluxemap contribution from "other side" light */ + doAddDeluxe = qfalse; + } /* attenuate */ angle *= -DotProduct( light->normal, trace->direction ); @@ -809,8 +836,27 @@ int LightContributionToSample( trace_t *trace ) return 0; else if( angle < 0.0f && (trace->twoSided || (light->flags & LIGHT_TWOSIDED)) ) + { angle = -angle; + + /* no deluxemap contribution from "other side" light */ + doAddDeluxe = qfalse; + } + + /* clamp the distance to prevent super hot spots */ + dist = sqrt(dist * dist + light->extraDist * light->extraDist); + if( dist < 16.0f ) + dist = 16.0f; + add = light->photons / (dist * dist) * angle; + + if( deluxemap ) + { + if( angledDeluxe ) + addDeluxe = light->photons / (dist * dist) * angle; + else + addDeluxe = light->photons / (dist * dist); + } } else { @@ -830,13 +876,26 @@ int LightContributionToSample( trace_t *trace ) dist = SetupTrace( trace ); if( dist >= light->envelope ) return 0; + + /* no deluxemap contribution from "other side" light */ + doAddDeluxe = qfalse; } else return 0; } + + /* also don't deluxe if the direction is on the wrong side */ + if(DotProduct(trace->normal, trace->direction) < 0) + { + /* no deluxemap contribution from "other side" light */ + doAddDeluxe = qfalse; + } /* ydnar: moved to here */ add = factor * light->add; + + if( deluxemap ) + addDeluxe = add; } } @@ -848,13 +907,45 @@ int LightContributionToSample( trace_t *trace ) dist = SetupTrace( trace ); if( dist >= light->envelope ) return 0; - + /* clamp the distance to prevent super hot spots */ + dist = sqrt(dist * dist + light->extraDist * light->extraDist); if( dist < 16.0f ) dist = 16.0f; - + /* angle attenuation */ - angle = (light->flags & LIGHT_ATTEN_ANGLE) ? DotProduct( trace->normal, trace->direction ) : 1.0f; + if( light->flags & LIGHT_ATTEN_ANGLE ) + { + /* standard Lambert attenuation */ + float dot = DotProduct( trace->normal, trace->direction ); + + /* twosided lighting */ + if( trace->twoSided && dot < 0 ) + { + dot = -dot; + + /* no deluxemap contribution from "other side" light */ + doAddDeluxe = qfalse; + } + + /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */ + if( lightAngleHL ) + { + if( dot > 0.001f ) // skip coplanar + { + if( dot > 1.0f ) dot = 1.0f; + dot = ( dot * 0.5f ) + 0.5f; + dot *= dot; + } + else + dot = 0; + } + + angle = dot; + } + else + angle = 1.0f; + if( light->angleScale != 0.0f ) { angle /= light->angleScale; @@ -862,27 +953,48 @@ int LightContributionToSample( trace_t *trace ) angle = 1.0f; } - /* twosided lighting */ - if( trace->twoSided ) - angle = fabs( angle ); - /* attenuate */ if( light->flags & LIGHT_ATTEN_LINEAR ) { add = angle * light->photons * linearScale - (dist * light->fade); if( add < 0.0f ) add = 0.0f; + + if( deluxemap ) + { + if( angledDeluxe ) + addDeluxe = angle * light->photons * linearScale - (dist * light->fade); + else + addDeluxe = light->photons * linearScale - (dist * light->fade); + + if( addDeluxe < 0.0f ) + addDeluxe = 0.0f; + } } else - add = light->photons / (dist * dist) * angle; + { + add = (light->photons / (dist * dist)) * angle; + if( add < 0.0f ) + add = 0.0f; + + if( deluxemap ) + { + if( angledDeluxe ) + addDeluxe = (light->photons / (dist * dist)) * angle; + else + addDeluxe = (light->photons / (dist * dist)); + } + + if( addDeluxe < 0.0f ) + addDeluxe = 0.0f; + } /* handle spotlights */ if( light->type == EMIT_SPOT ) { float distByNormal, radiusAtDist, sampleRadius; vec3_t pointAtDist, distToSample; - - + /* do cone calculation */ distByNormal = -DotProduct( trace->displacement, light->normal ); if( distByNormal < 0.0f ) @@ -898,7 +1010,16 @@ int LightContributionToSample( trace_t *trace ) /* attenuate */ if( sampleRadius > (radiusAtDist - 32.0f) ) + { add *= ((radiusAtDist - sampleRadius) / 32.0f); + if( add < 0.0f ) + add = 0.0f; + + addDeluxe *= ((radiusAtDist - sampleRadius) / 32.0f); + + if( addDeluxe < 0.0f ) + addDeluxe = 0.0f; + } } } @@ -908,20 +1029,70 @@ int LightContributionToSample( trace_t *trace ) /* get origin and direction */ VectorAdd( trace->origin, light->origin, trace->end ); dist = SetupTrace( trace ); - + /* angle attenuation */ - angle = (light->flags & LIGHT_ATTEN_ANGLE) - ? DotProduct( trace->normal, trace->direction ) - : 1.0f; - - /* twosided lighting */ - if( trace->twoSided ) - angle = fabs( angle ); + if( light->flags & LIGHT_ATTEN_ANGLE ) + { + /* standard Lambert attenuation */ + float dot = DotProduct( trace->normal, trace->direction ); + + /* twosided lighting */ + if( trace->twoSided && dot < 0 ) + { + dot = -dot; + + /* no deluxemap contribution from "other side" light */ + doAddDeluxe = qfalse; + } + + /* jal: optional half Lambert attenuation (http://developer.valvesoftware.com/wiki/Half_Lambert) */ + if( lightAngleHL ) + { + if( dot > 0.001f ) // skip coplanar + { + if( dot > 1.0f ) dot = 1.0f; + dot = ( dot * 0.5f ) + 0.5f; + dot *= dot; + } + else + dot = 0; + } + + angle = dot; + } + else + angle = 1.0f; /* attenuate */ add = light->photons * angle; + + if( deluxemap ) + { + if( angledDeluxe ) + addDeluxe = light->photons * angle; + else + addDeluxe = light->photons; + + if( addDeluxe < 0.0f ) + addDeluxe = 0.0f; + } + if( add <= 0.0f ) return 0; + + /* VorteX: set noShadow color */ + VectorScale(light->color, add, trace->colorNoShadow); + + addDeluxe *= colorBrightness; + + if( bouncing ) + { + addDeluxe *= addDeluxeBounceScale; + if( addDeluxe < 0.00390625f ) + addDeluxe = 0.00390625f; + } + + VectorScale( trace->direction, addDeluxe, trace->directionContribution ); /* setup trace */ trace->testAll = qtrue; @@ -932,9 +1103,12 @@ int LightContributionToSample( trace_t *trace ) { /* trace */ TraceLine( trace ); + trace->forceSubsampling *= add; if( !(trace->compileFlags & C_SKY) || trace->opaque ) { VectorClear( trace->color ); + VectorClear( trace->directionContribution ); + return -1; } } @@ -942,10 +1116,43 @@ int LightContributionToSample( trace_t *trace ) /* return to sender */ return 1; } + else + Error("Light of undefined type!"); + + /* VorteX: set noShadow color */ + VectorScale(light->color, add, trace->colorNoShadow); /* ydnar: changed to a variable number */ if( add <= 0.0f || (add <= light->falloffTolerance && (light->flags & LIGHT_FAST_ACTUAL)) ) return 0; + + addDeluxe *= colorBrightness; + + /* hack land: scale down the radiosity contribution to light directionality. + Deluxemaps fusion many light directions into one. In a rtl process all lights + would contribute individually to the bump map, so several light sources together + would make it more directional (example: a yellow and red lights received from + opposing sides would light one side in red and the other in blue, adding + the effect of 2 directions applied. In the deluxemapping case, this 2 lights would + neutralize each other making it look like having no direction. + Same thing happens with radiosity. In deluxemapping case the radiosity contribution + is modifying the direction applied from directional lights, making it go closer and closer + to the surface normal the bigger is the amount of radiosity received. + So, for preserving the directional lights contributions, we scale down the radiosity + contribution. It's a hack, but there's a reason behind it */ + if( bouncing ) + { + addDeluxe *= addDeluxeBounceScale; + /* better NOT increase it beyond the original value + if( addDeluxe < 0.00390625f ) + addDeluxe = 0.00390625f; + */ + } + + if(doAddDeluxe) + { + VectorScale( trace->direction, addDeluxe, trace->directionContribution ); + } /* setup trace */ trace->testAll = qfalse; @@ -953,9 +1160,12 @@ int LightContributionToSample( trace_t *trace ) /* raytrace */ TraceLine( trace ); + trace->forceSubsampling *= add; if( trace->passSolid || trace->opaque ) { VectorClear( trace->color ); + VectorClear( trace->directionContribution ); + return -1; } @@ -1099,9 +1309,10 @@ int LightContributionToPoint( trace_t *trace ) if( light->type == EMIT_AREA && faster ) { /* clamp the distance to prevent super hot spots */ + dist = sqrt(dist * dist + light->extraDist * light->extraDist); if( dist < 16.0f ) dist = 16.0f; - + /* attenuate */ add = light->photons / (dist * dist); } @@ -1145,6 +1356,7 @@ int LightContributionToPoint( trace_t *trace ) else if( light->type == EMIT_POINT || light->type == EMIT_SPOT ) { /* clamp the distance to prevent super hot spots */ + dist = sqrt(dist * dist + light->extraDist * light->extraDist); if( dist < 16.0f ) dist = 16.0f; @@ -1244,27 +1456,27 @@ grid samples are for quickly determining the lighting of dynamically placed entities in the world */ -#define MAX_CONTRIBUTIONS 1024 +#define MAX_CONTRIBUTIONS 32768 typedef struct { vec3_t dir; vec3_t color; + vec3_t ambient; int style; } contribution_t; void TraceGrid( int num ) { - int i, j, x, y, z, mod, step, numCon, numStyles; - float d; - vec3_t baseOrigin, cheapColor, color; + int i, j, x, y, z, mod, numCon, numStyles; + float d, step; + vec3_t baseOrigin, cheapColor, color, thisdir; rawGridPoint_t *gp; bspGridPoint_t *bgp; contribution_t contributions[ MAX_CONTRIBUTIONS ]; trace_t trace; - /* get grid points */ gp = &rawGridPoints[ num ]; bgp = &bspGridPoints[ num ]; @@ -1295,38 +1507,21 @@ void TraceGrid( int num ) { /* try to nudge the origin around to find a valid point */ VectorCopy( trace.origin, baseOrigin ); - for( step = 9; step <= 18; step += 9 ) + for( step = 0; (step += 0.005) <= 1.0; ) { - for( i = 0; i < 8; i++ ) - { - VectorCopy( baseOrigin, trace.origin ); - if( i & 1 ) - trace.origin[ 0 ] += step; - else - trace.origin[ 0 ] -= step; - - if( i & 2 ) - trace.origin[ 1 ] += step; - else - trace.origin[ 1 ] -= step; + VectorCopy( baseOrigin, trace.origin ); + trace.origin[ 0 ] += step * (Random() - 0.5) * gridSize[0]; + trace.origin[ 1 ] += step * (Random() - 0.5) * gridSize[1]; + trace.origin[ 2 ] += step * (Random() - 0.5) * gridSize[2]; - if( i & 4 ) - trace.origin[ 2 ] += step; - else - trace.origin[ 2 ] -= step; - - /* ydnar: changed to find cluster num */ - trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON ); - if( trace.cluster >= 0 ) - break; - } - - if( i != 8 ) + /* ydnar: changed to find cluster num */ + trace.cluster = ClusterForPointExt( trace.origin, VERTEX_EPSILON ); + if( trace.cluster >= 0 ) break; } /* can't find a valid point at all */ - if( step > 18 ) + if( step > 1.0 ) return; } @@ -1361,6 +1556,7 @@ void TraceGrid( int num ) /* add a contribution */ VectorCopy( trace.color, contributions[ numCon ].color ); VectorCopy( trace.direction, contributions[ numCon ].dir ); + VectorClear( contributions[ numCon ].ambient ); contributions[ numCon ].style = trace.light->style; numCon++; @@ -1378,16 +1574,74 @@ void TraceGrid( int num ) break; } + /////// Floodlighting for point ////////////////// + //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir + if( floodlighty ) + { + int k; + float addSize, f; + vec3_t dir = { 0, 0, 1 }; + float ambientFrac = 0.25f; + + trace.testOcclusion = qtrue; + trace.forceSunlight = qfalse; + trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS; + trace.testAll = qtrue; + + for( k = 0; k < 2; k++ ) + { + if( k == 0 ) // upper hemisphere + { + trace.normal[0] = 0; + trace.normal[1] = 0; + trace.normal[2] = 1; + } + else //lower hemisphere + { + trace.normal[0] = 0; + trace.normal[1] = 0; + trace.normal[2] = -1; + } + + f = FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality ); + + /* add a fraction as pure ambient, half as top-down direction */ + contributions[ numCon ].color[0]= floodlightRGB[0] * floodlightIntensity * f * ( 1.0f - ambientFrac ); + contributions[ numCon ].color[1]= floodlightRGB[1] * floodlightIntensity * f * ( 1.0f - ambientFrac ); + contributions[ numCon ].color[2]= floodlightRGB[2] * floodlightIntensity * f * ( 1.0f - ambientFrac ); + + contributions[ numCon ].ambient[0]= floodlightRGB[0] * floodlightIntensity * f * ambientFrac; + contributions[ numCon ].ambient[1]= floodlightRGB[1] * floodlightIntensity * f * ambientFrac; + contributions[ numCon ].ambient[2]= floodlightRGB[2] * floodlightIntensity * f * ambientFrac; + + contributions[ numCon ].dir[0] = dir[0]; + contributions[ numCon ].dir[1] = dir[1]; + contributions[ numCon ].dir[2] = dir[2]; + + contributions[ numCon ].style = 0; + + /* push average direction around */ + addSize = VectorLength( contributions[ numCon ].color ); + VectorMA( gp->dir, addSize, dir, gp->dir ); + + numCon++; + } + } + ///////////////////// + /* normalize to get primary light direction */ - VectorNormalize( gp->dir, gp->dir ); + VectorNormalize( gp->dir, thisdir ); /* now that we have identified the primary light direction, go back and separate all the light into directed and ambient */ + numStyles = 1; for( i = 0; i < numCon; i++ ) { /* get relative directed strength */ - d = DotProduct( contributions[ i ].dir, gp->dir ); + d = DotProduct( contributions[ i ].dir, thisdir ); + /* we map 1 to gridDirectionality, and 0 to gridAmbientDirectionality */ + d = gridAmbientDirectionality + d * (gridDirectionality - gridAmbientDirectionality); if( d < 0.0f ) d = 0.0f; @@ -1420,25 +1674,47 @@ void TraceGrid( int num ) /* ambient light will be at 1/4 the value of directed light */ /* (ydnar: nuke this in favor of more dramatic lighting?) */ + /* (PM: how about actually making it work? d=1 when it got here for single lights/sun :P */ +// d = 0.25f; + /* (Hobbes: always setting it to .25 is hardly any better) */ d = 0.25f * (1.0f - d); VectorMA( gp->ambient[ j ], d, contributions[ i ].color, gp->ambient[ j ] ); + + VectorAdd( gp->ambient[ j ], contributions[ i ].ambient, gp->ambient[ j ] ); + +/* + * div0: + * the total light average = ambient value + 0.25 * sum of all directional values + * we can also get the total light average as 0.25 * the sum of all contributions + * + * 0.25 * sum(contribution_i) == ambient + 0.25 * sum(d_i contribution_i) + * + * THIS YIELDS: + * ambient == 0.25 * sum((1 - d_i) contribution_i) + * + * So, 0.25f * (1.0f - d) IS RIGHT. If you want to tune it, tune d BEFORE. + */ } /* store off sample */ for( i = 0; i < MAX_LIGHTMAPS; i++ ) { +#if 0 /* do some fudging to keep the ambient from being too low (2003-07-05: 0.25 -> 0.125) */ if( !bouncing ) VectorMA( gp->ambient[ i ], 0.125f, gp->directed[ i ], gp->ambient[ i ] ); +#endif /* set minimum light and copy off to bytes */ VectorCopy( gp->ambient[ i ], color ); for( j = 0; j < 3; j++ ) if( color[ j ] < minGridLight[ j ] ) color[ j ] = minGridLight[ j ]; - ColorToBytes( color, bgp->ambient[ i ], 1.0f ); - ColorToBytes( gp->directed[ i ], bgp->directed[ i ], 1.0f ); + + /* vortex: apply gridscale and gridambientscale here */ + ColorToBytes( color, bgp->ambient[ i ], gridScale*gridAmbientScale ); + ColorToBytes( gp->directed[ i ], bgp->directed[ i ], gridScale ); } /* debug code */ @@ -1451,8 +1727,7 @@ void TraceGrid( int num ) #endif /* store direction */ - if( !bouncing ) - NormalToLatLong( gp->dir, bgp->latLong ); + NormalToLatLong( thisdir, bgp->latLong ); } @@ -1631,7 +1906,9 @@ void LightWorld( void ) SetupEnvelopes( qtrue, fastgrid ); Sys_Printf( "--- TraceGrid ---\n" ); + inGrid = qtrue; RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid ); + inGrid = qfalse; Sys_Printf( "%d x %d x %d = %d grid\n", gridBounds[ 0 ], gridBounds[ 1 ], gridBounds[ 2 ], numBSPGridPoints ); @@ -1654,13 +1931,11 @@ void LightWorld( void ) if( dirty ) { Sys_Printf( "--- DirtyRawLightmap ---\n" ); - - - - RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap ); } + /* floodlight pass */ + FloodlightRawLightmaps(); /* ydnar: set up light envelopes */ SetupEnvelopes( qfalse, fast ); @@ -1694,6 +1969,7 @@ void LightWorld( void ) { /* store off the bsp between bounces */ StoreSurfaceLightmaps(); + UnparseEntities(); Sys_Printf( "Writing %s\n", source ); WriteBSPFile( source ); @@ -1703,6 +1979,7 @@ void LightWorld( void ) /* flag bouncing */ bouncing = qtrue; VectorClear( ambientColor ); + floodlighty = qfalse; /* generate diffuse lights */ RadFreeLights(); @@ -1723,7 +2000,9 @@ void LightWorld( void ) gridBoundsCulled = 0; Sys_Printf( "--- BounceGrid ---\n" ); + inGrid = qtrue; RunThreadsOnIndividual( numRawGridPoints, qtrue, TraceGrid ); + inGrid = qfalse; Sys_FPrintf( SYS_VRB, "%9d grid points envelope culled\n", gridEnvelopeCulled ); Sys_FPrintf( SYS_VRB, "%9d grid points bounds culled\n", gridBoundsCulled ); } @@ -1770,16 +2049,74 @@ int LightMain( int argc, char **argv ) float f; char mapSource[ 1024 ]; const char *value; + int lightmapMergeSize = 0; + qboolean lightSamplesInsist = qfalse; /* note it */ Sys_Printf( "--- Light ---\n" ); - + Sys_Printf( "--- ProcessGameSpecific ---\n" ); + /* set standard game flags */ wolfLight = game->wolfLight; + if (wolfLight == qtrue) + Sys_Printf( " lightning model: wolf\n" ); + else + Sys_Printf( " lightning model: quake3\n" ); + lmCustomSize = game->lightmapSize; + Sys_Printf( " lightmap size: %d x %d pixels\n", lmCustomSize, lmCustomSize ); + lightmapGamma = game->lightmapGamma; + Sys_Printf( " lightning gamma: %f\n", lightmapGamma ); + lightmapCompensate = game->lightmapCompensate; + Sys_Printf( " lightning compensation: %f\n", lightmapCompensate ); + + lightmapExposure = game->lightmapExposure; + Sys_Printf( " lightning exposure: %f\n", lightmapExposure ); + + gridScale = game->gridScale; + Sys_Printf( " lightgrid scale: %f\n", gridScale ); + + gridAmbientScale = game->gridAmbientScale; + Sys_Printf( " lightgrid ambient scale: %f\n", gridAmbientScale ); + + lightAngleHL = game->lightAngleHL; + if( lightAngleHL ) + Sys_Printf( " half lambert light angle attenuation enabled \n" ); + + noStyles = game->noStyles; + if (noStyles == qtrue) + Sys_Printf( " shader lightstyles hack: disabled\n" ); + else + Sys_Printf( " shader lightstyles hack: enabled\n" ); + + keepLights = game->keepLights; + if (keepLights == qtrue) + Sys_Printf( " keep lights: enabled\n" ); + else + Sys_Printf( " keep lights: disabled\n" ); + + patchShadows = game->patchShadows; + if (patchShadows == qtrue) + Sys_Printf( " patch shadows: enabled\n" ); + else + Sys_Printf( " patch shadows: disabled\n" ); + + deluxemap = game->deluxeMap; + deluxemode = game->deluxeMode; + if (deluxemap == qtrue) + { + if (deluxemode) + Sys_Printf( " deluxemapping: enabled with tangentspace deluxemaps\n" ); + else + Sys_Printf( " deluxemapping: enabled with modelspace deluxemaps\n" ); + } + else + Sys_Printf( " deluxemapping: disabled\n" ); + + Sys_Printf( "--- ProcessCommandLine ---\n" ); /* process commandline arguments */ for( i = 1; i < (argc - 1); i++ ) @@ -1827,6 +2164,42 @@ int LightMain( int argc, char **argv ) Sys_Printf( "All light scaled by %f\n", f ); i++; } + + else if( !strcmp( argv[ i ], "-gridscale" ) ) + { + f = atof( argv[ i + 1 ] ); + Sys_Printf( "Grid lightning scaled by %f\n", f ); + gridScale *= f; + i++; + } + + else if( !strcmp( argv[ i ], "-gridambientscale" ) ) + { + f = atof( argv[ i + 1 ] ); + Sys_Printf( "Grid ambient lightning scaled by %f\n", f ); + gridAmbientScale *= f; + i++; + } + + else if( !strcmp( argv[ i ], "-griddirectionality" ) ) + { + f = atof( argv[ i + 1 ] ); + if(f > 1) f = 1; + if(f < gridAmbientDirectionality) gridAmbientDirectionality = f; + Sys_Printf( "Grid directionality is %f\n", f ); + gridDirectionality = f; + i++; + } + + else if( !strcmp( argv[ i ], "-gridambientdirectionality" ) ) + { + f = atof( argv[ i + 1 ] ); + if(f < -1) f = -1; + if(f > gridDirectionality) gridDirectionality = f; + Sys_Printf( "Grid ambient directionality is %f\n", f ); + gridAmbientDirectionality = f; + i++; + } else if( !strcmp( argv[ i ], "-gamma" ) ) { @@ -1836,6 +2209,14 @@ int LightMain( int argc, char **argv ) i++; } + else if( !strcmp( argv[ i ], "-exposure" ) ) + { + f = atof( argv[ i + 1 ] ); + lightmapExposure = f; + Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure ); + i++; + } + else if( !strcmp( argv[ i ], "-compensate" ) ) { f = atof( argv[ i + 1 ] ); @@ -1867,8 +2248,18 @@ int LightMain( int argc, char **argv ) i++; } + else if( !strcmp( argv[ i ], "-randomsamples" ) ) + { + lightRandomSamples = qtrue; + Sys_Printf( "Random sampling enabled\n", lightRandomSamples ); + } + else if( !strcmp( argv[ i ], "-samples" ) ) { + if(*argv[i+1] == '+') + lightSamplesInsist = qtrue; + else + lightSamplesInsist = qfalse; lightSamples = atoi( argv[ i + 1 ] ); if( lightSamples < 1 ) lightSamples = 1; @@ -1877,6 +2268,18 @@ int LightMain( int argc, char **argv ) i++; } + else if( !strcmp( argv[ i ], "-samplessearchboxsize" ) ) + { + lightSamplesSearchBoxSize = atoi( argv[ i + 1 ] ); + if( lightSamplesSearchBoxSize <= 0 ) + lightSamplesSearchBoxSize = 1; + if( lightSamplesSearchBoxSize > 4 ) + lightSamplesSearchBoxSize = 4; /* more makes no sense */ + else if( lightSamplesSearchBoxSize != 1 ) + Sys_Printf( "Adaptive supersampling uses %f times the normal search box size\n", lightSamplesSearchBoxSize ); + i++; + } + else if( !strcmp( argv[ i ], "-filter" ) ) { filter = qtrue; @@ -1889,12 +2292,6 @@ int LightMain( int argc, char **argv ) Sys_Printf( "Dark lightmap seams enabled\n" ); } - - - - - - else if( !strcmp( argv[ i ], "-shadeangle" ) ) { shadeAngleDegrees = atof( argv[ i + 1 ] ); @@ -1927,13 +2324,28 @@ int LightMain( int argc, char **argv ) Sys_Printf( "Approximating lightmaps within a byte tolerance of %d\n", approximateTolerance ); i++; } - else if( !strcmp( argv[ i ], "-deluxe" ) || !strcmp( argv[ i ], "-deluxemap" ) ) { deluxemap = qtrue; Sys_Printf( "Generating deluxemaps for average light direction\n" ); } - + else if( !strcmp( argv[ i ], "-deluxemode" )) + { + deluxemode = atoi( argv[ i + 1 ] ); + if (deluxemode == 0 || deluxemode > 1 || deluxemode < 0) + { + Sys_Printf( "Generating modelspace deluxemaps\n" ); + deluxemode = 0; + } + else + Sys_Printf( "Generating tangentspace deluxemaps\n" ); + i++; + } + else if( !strcmp( argv[ i ], "-nodeluxe" ) || !strcmp( argv[ i ], "-nodeluxemap" ) ) + { + deluxemap = qfalse; + Sys_Printf( "Disabling generating of deluxemaps for average light direction\n" ); + } else if( !strcmp( argv[ i ], "-external" ) ) { externalLightmaps = qtrue; @@ -1961,6 +2373,23 @@ int LightMain( int argc, char **argv ) } } + else if( !strcmp( argv[ i ], "-rawlightmapsizelimit" ) ) + { + lmLimitSize = atoi( argv[ i + 1 ] ); + + i++; + Sys_Printf( "Raw lightmap size limit set to %d x %d pixels\n", lmLimitSize, lmLimitSize ); + } + + else if( !strcmp( argv[ i ], "-lightmapdir" ) ) + { + lmCustomDir = argv[i + 1]; + i++; + Sys_Printf( "Lightmap directory set to %s\n", lmCustomDir ); + externalLightmaps = qtrue; + Sys_Printf( "Storing all lightmaps externally\n" ); + } + /* ydnar: add this to suppress warnings */ else if( !strcmp( argv[ i ], "-custinfoparms") ) { @@ -1981,6 +2410,15 @@ int LightMain( int argc, char **argv ) wolfLight = qfalse; Sys_Printf( "Enabling Quake 3 lighting model (nonlinear default)\n" ); } + + else if( !strcmp( argv[ i ], "-extradist" ) ) + { + extraDist = atof( argv[ i + 1 ] ); + if( extraDist < 0 ) + extraDist = 0; + i++; + Sys_Printf( "Default extra radius set to %f units\n", extraDist ); + } else if( !strcmp( argv[ i ], "-sunonly" ) ) { @@ -1999,6 +2437,26 @@ int LightMain( int argc, char **argv ) noCollapse = qtrue; Sys_Printf( "Identical lightmap collapsing disabled\n" ); } + + else if( !strcmp( argv[ i ], "-nolightmapsearch" ) ) + { + lightmapSearchBlockSize = 1; + Sys_Printf( "No lightmap searching - all lightmaps will be sequential\n" ); + } + + else if( !strcmp( argv[ i ], "-lightmapsearchpower" ) ) + { + lightmapMergeSize = (game->lightmapSize << atoi(argv[i+1])); + ++i; + Sys_Printf( "Restricted lightmap searching enabled - optimize for lightmap merge power %d (size %d)\n", atoi(argv[i]), lightmapMergeSize ); + } + + else if( !strcmp( argv[ i ], "-lightmapsearchblocksize" ) ) + { + lightmapSearchBlockSize = atoi(argv[i+1]); + ++i; + Sys_Printf( "Restricted lightmap searching enabled - block size set to %d\n", lightmapSearchBlockSize ); + } else if( !strcmp( argv[ i ], "-shade" ) ) { @@ -2151,6 +2609,20 @@ int LightMain( int argc, char **argv ) i++; Sys_Printf( "Default lightmap sample size set to %dx%d units\n", sampleSize, sampleSize ); } + else if( !strcmp( argv[ i ], "-minsamplesize" ) ) + { + minSampleSize = atoi( argv[ i + 1 ] ); + if( minSampleSize < 1 ) + minSampleSize = 1; + i++; + Sys_Printf( "Minimum lightmap sample size set to %dx%d units\n", minSampleSize, minSampleSize ); + } + else if( !strcmp( argv[ i ], "-samplescale" ) ) + { + sampleScale = atoi( argv[ i + 1 ] ); + i++; + Sys_Printf( "Lightmaps sample scale set to %d\n", sampleScale); + } else if( !strcmp( argv[ i ], "-novertex" ) ) { noVertexLighting = qtrue; @@ -2181,16 +2653,52 @@ int LightMain( int argc, char **argv ) loMem = qtrue; Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" ); } + else if( !strcmp( argv[ i ], "-lightanglehl" ) ) + { + if( ( atoi( argv[ i + 1 ] ) != 0 ) != lightAngleHL ) + { + lightAngleHL = ( atoi( argv[ i + 1 ] ) != 0 ); + if( lightAngleHL ) + Sys_Printf( "Enabling half lambert light angle attenuation\n" ); + else + Sys_Printf( "Disabling half lambert light angle attenuation\n" ); + } + } else if( !strcmp( argv[ i ], "-nostyle" ) || !strcmp( argv[ i ], "-nostyles" ) ) { noStyles = qtrue; Sys_Printf( "Disabling lightstyles\n" ); } + else if( !strcmp( argv[ i ], "-style" ) || !strcmp( argv[ i ], "-styles" ) ) + { + noStyles = qfalse; + Sys_Printf( "Enabling lightstyles\n" ); + } + else if( !strcmp( argv[ i ], "-keeplights" )) + { + keepLights = qtrue; + Sys_Printf( "Leaving light entities on map after compile\n" ); + } else if( !strcmp( argv[ i ], "-cpma" ) ) { cpmaHack = qtrue; Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" ); } + else if( !strcmp( argv[ i ], "-floodlight" ) ) + { + floodlighty = qtrue; + Sys_Printf( "FloodLighting enabled\n" ); + } + else if( !strcmp( argv[ i ], "-debugnormals" ) ) + { + debugnormals = qtrue; + Sys_Printf( "DebugNormals enabled\n" ); + } + else if( !strcmp( argv[ i ], "-lowquality" ) ) + { + floodlight_lowquality = qtrue; + Sys_Printf( "Low Quality FloodLighting enabled\n" ); + } /* r7: dirtmapping */ else if( !strcmp( argv[ i ], "-dirty" ) ) @@ -2212,6 +2720,7 @@ int LightMain( int argc, char **argv ) Sys_Printf( "Enabling randomized dirtmapping\n" ); else Sys_Printf( "Enabling ordered dir mapping\n" ); + i++; } else if( !strcmp( argv[ i ], "-dirtdepth" ) ) { @@ -2219,6 +2728,7 @@ int LightMain( int argc, char **argv ) if( dirtDepth <= 0.0f ) dirtDepth = 128.0f; Sys_Printf( "Dirtmapping depth set to %.1f\n", dirtDepth ); + i++; } else if( !strcmp( argv[ i ], "-dirtscale" ) ) { @@ -2226,6 +2736,7 @@ int LightMain( int argc, char **argv ) if( dirtScale <= 0.0f ) dirtScale = 1.0f; Sys_Printf( "Dirtmapping scale set to %.1f\n", dirtScale ); + i++; } else if( !strcmp( argv[ i ], "-dirtgain" ) ) { @@ -2233,13 +2744,70 @@ int LightMain( int argc, char **argv ) if( dirtGain <= 0.0f ) dirtGain = 1.0f; Sys_Printf( "Dirtmapping gain set to %.1f\n", dirtGain ); + i++; + } + else if( !strcmp( argv[ i ], "-trianglecheck" ) ) + { + lightmapTriangleCheck = qtrue; + } + else if( !strcmp( argv[ i ], "-extravisnudge" ) ) + { + lightmapExtraVisClusterNudge = qtrue; + } + else if( !strcmp( argv[ i ], "-fill" ) ) + { + lightmapFill = qtrue; + Sys_Printf( "Filling lightmap colors from surrounding pixels to improve JPEG compression\n" ); } - /* unhandled args */ else + { Sys_Printf( "WARNING: Unknown argument \"%s\"\n", argv[ i ] ); + } } + + /* fix up samples count */ + if(lightRandomSamples) + { + if(!lightSamplesInsist) + { + /* approximately match -samples in quality */ + switch(lightSamples) + { + /* somewhat okay */ + case 1: + case 2: + lightSamples = 16; + Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples ); + break; + + /* good */ + case 3: + lightSamples = 64; + Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples ); + break; + + /* perfect */ + case 4: + lightSamples = 256; + Sys_Printf( "Adaptive supersampling preset enabled with %d random sample(s) per lightmap texel\n", lightSamples ); + break; + + default: break; + } + } + } + + /* fix up lightmap search power */ + if(lightmapMergeSize) + { + lightmapSearchBlockSize = (lightmapMergeSize / lmCustomSize) * (lightmapMergeSize / lmCustomSize); + if(lightmapSearchBlockSize < 1) + lightmapSearchBlockSize = 1; + + Sys_Printf( "Restricted lightmap searching enabled - block size adjusted to %d\n", lightmapSearchBlockSize ); + } /* clean up map name */ strcpy( source, ExpandArg( argv[ i ] ) ); @@ -2267,11 +2835,14 @@ int LightMain( int argc, char **argv ) /* parse bsp entities */ ParseEntities(); + + /* inject command line parameters */ + InjectCommandLine(argv, 0, argc - 1); /* load map file */ value = ValueForKey( &entities[ 0 ], "_keepLights" ); if( value[ 0 ] != '1' ) - LoadMapFile( mapSource, qtrue ); + LoadMapFile( mapSource, qtrue, qfalse ); /* set the entity/model origins and init yDrawVerts */ SetEntityOrigins(); @@ -2279,6 +2850,7 @@ int LightMain( int argc, char **argv ) /* ydnar: set up optimization */ SetupBrushes(); SetupDirt(); + SetupFloodLight(); SetupSurfaceLightmaps(); /* initialize the surface facet tracing */ diff --git a/tools/quake3/q3map2/light_bounce.c b/tools/quake3/q3map2/light_bounce.c index dba5b131..7db00613 100644 --- a/tools/quake3/q3map2/light_bounce.c +++ b/tools/quake3/q3map2/light_bounce.c @@ -414,7 +414,7 @@ subdivides a radiosity winding until it is smaller than subdivide, then generate static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, qboolean original, radWinding_t *rw, clipWork_t *cw ) { - int i, style; + int i, style = 0; float dist, area, value; vec3_t mins, maxs, normal, d1, d2, cross, color, gradient; light_t *light, *splash; @@ -539,7 +539,7 @@ static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, raw light->falloffTolerance = falloffTolerance; /* bouncing light? */ - if( bouncing == qfalse ) + if( !bouncing ) { /* handle first-pass lights in normal q3a style */ value = si->value; @@ -836,6 +836,9 @@ void RadLight( int num ) /* find nodraw bit */ contentFlags = surfaceFlags = compileFlags = 0; ApplySurfaceParm( "nodraw", &contentFlags, &surfaceFlags, &compileFlags ); + + // jal : avoid bouncing on trans surfaces + ApplySurfaceParm( "trans", &contentFlags, &surfaceFlags, &compileFlags ); /* early outs? */ if( scale <= 0.0f || (si->compileFlags & C_SKY) || si->autosprite || diff --git a/tools/quake3/q3map2/light_trace.c b/tools/quake3/q3map2/light_trace.c index 2a4e7e46..8e79244e 100644 --- a/tools/quake3/q3map2/light_trace.c +++ b/tools/quake3/q3map2/light_trace.c @@ -56,7 +56,7 @@ several games based on the Quake III Arena engine, in the form of "Q3Map2." #define GROW_TRACE_NODES 16384 //% 16384 #define GROW_NODE_ITEMS 16 //% 256 -#define MAX_TW_VERTS 12 +#define MAX_TW_VERTS 24 // vortex: increased from 12 to 24 for ability co compile some insane maps with large curve count #define TRACE_ON_EPSILON 0.1f @@ -73,7 +73,7 @@ traceVert_t; typedef struct traceInfo_s { shaderInfo_t *si; - int surfaceNum, castShadows; + int surfaceNum, castShadows, skipGrid; } traceInfo_t; @@ -144,7 +144,8 @@ static int AddTraceInfo( traceInfo_t *ti ) { if( traceInfos[ num ].si == ti->si && traceInfos[ num ].surfaceNum == ti->surfaceNum && - traceInfos[ num ].castShadows == ti->castShadows ) + traceInfos[ num ].castShadows == ti->castShadows && + traceInfos[ num ].skipGrid == ti->skipGrid ) return num; } @@ -201,6 +202,9 @@ static int AllocTraceNode( void ) memset( &traceNodes[ numTraceNodes ], 0, sizeof( traceNode_t ) ); traceNodes[ numTraceNodes ].type = TRACE_LEAF; ClearBounds( traceNodes[ numTraceNodes ].mins, traceNodes[ numTraceNodes ].maxs ); + + /* Sys_Printf("alloc node %d\n", numTraceNodes); */ + numTraceNodes++; /* return the count */ @@ -362,7 +366,7 @@ recursively create the initial trace node structure from the bsp tree static int SetupTraceNodes_r( int bspNodeNum ) { - int i, nodeNum, bspLeafNum; + int i, nodeNum, bspLeafNum, newNode; bspPlane_t *plane; bspNode_t *bspNode; @@ -388,15 +392,26 @@ static int SetupTraceNodes_r( int bspNodeNum ) bspLeafNum = -bspNode->children[ i ] - 1; /* new code */ - traceNodes[ nodeNum ].children[ i ] = AllocTraceNode(); + newNode = AllocTraceNode(); + traceNodes[ nodeNum ].children[ i ] = newNode; + /* have to do this separately, as gcc first executes LHS, then RHS, and if a realloc took place, this fails */ + if( bspLeafs[ bspLeafNum ].cluster == -1 ) traceNodes[ traceNodes[ nodeNum ].children[ i ] ].type = TRACE_LEAF_SOLID; } /* normal node */ else - traceNodes[ nodeNum ].children[ i ] = SetupTraceNodes_r( bspNode->children[ i ] ); + { + newNode = SetupTraceNodes_r( bspNode->children[ i ] ); + traceNodes[ nodeNum ].children[ i ] = newNode; + } + + if(traceNodes[ nodeNum ].children[ i ] == 0) + Error( "Invalid tracenode allocated" ); } + + /* Sys_Printf("node %d children: %d %d\n", nodeNum, traceNodes[ nodeNum ].children[0], traceNodes[ nodeNum ].children[1]); */ /* return node number */ return nodeNum; @@ -506,13 +521,10 @@ void ClipTraceWinding( traceWinding_t *tw, vec4_t plane, traceWinding_t *front, mid.xyz[ k ] = -plane[ 3 ]; else mid.xyz[ k ] = a->xyz[ k ] + frac * (b->xyz[ k ] - a->xyz[ k ]); - - /* set texture coordinates */ - if( k > 1 ) - continue; - mid.st[ 0 ] = a->st[ 0 ] + frac * (b->st[ 0 ] - a->st[ 0 ]); - mid.st[ 1 ] = a->st[ 1 ] + frac * (b->st[ 1 ] - a->st[ 1 ]); } + /* set texture coordinates */ + mid.st[ 0 ] = a->st[ 0 ] + frac * (b->st[ 0 ] - a->st[ 0 ]); + mid.st[ 1 ] = a->st[ 1 ] + frac * (b->st[ 1 ] - a->st[ 1 ]); /* copy midpoint to front and back polygons */ front->v[ front->numVerts++ ] = mid; @@ -523,39 +535,6 @@ void ClipTraceWinding( traceWinding_t *tw, vec4_t plane, traceWinding_t *front, -/* -FilterPointToTraceNodes_r() - ydnar -debugging tool -*/ - -static int FilterPointToTraceNodes_r( vec3_t pt, int nodeNum ) -{ - float dot; - traceNode_t *node; - - - if( nodeNum < 0 || nodeNum >= numTraceNodes ) - return -1; - - node = &traceNodes[ nodeNum ]; - - if( node->type >= 0 ) - { - dot = DotProduct( pt, node->plane ) - node->plane[ 3 ]; - if( dot > -0.001f ) - FilterPointToTraceNodes_r( pt, node->children[ 0 ] ); - if( dot < 0.001f ) - FilterPointToTraceNodes_r( pt, node->children[ 1 ] ); - return -1; - } - - Sys_Printf( "%d ", nodeNum ); - - return nodeNum; -} - - - /* FilterTraceWindingIntoNodes_r() - ydnar filters a trace winding into the raytracing tree @@ -960,6 +939,7 @@ static void PopulateWithBSPModel( bspModel_t *model, m4x4_t transform ) ti.si = info->si; ti.castShadows = info->castShadows; ti.surfaceNum = model->firstBSPBrush + i; + ti.skipGrid = (ds->surfaceType == MST_PATCH); /* choose which node (normal or skybox) */ if( info->parentSurfaceNum >= 0 ) @@ -1129,6 +1109,7 @@ static void PopulateWithPicoModel( int castShadows, picoModel_t *model, m4x4_t t /* setup trace info */ ti.castShadows = castShadows; ti.surfaceNum = -1; + ti.skipGrid = qtrue; // also ignore picomodels when skipping patches /* setup trace winding */ memset( &tw, 0, sizeof( tw ) ); @@ -1240,7 +1221,7 @@ static void PopulateTraceNodes( void ) /* external model */ default: frame = IntForKey( e, "_frame" ); - model = LoadModel( (char*) value, frame ); + model = LoadModel( value, frame ); if( model == NULL ) continue; PopulateWithPicoModel( castShadows, model, transform ); @@ -1268,7 +1249,7 @@ static void PopulateTraceNodes( void ) /* external model */ default: frame = IntForKey( e, "_frame2" ); - model = LoadModel( (char*) value, frame ); + model = LoadModel( value, frame ); if( model == NULL ) continue; PopulateWithPicoModel( castShadows, model, transform ); @@ -1412,7 +1393,7 @@ qboolean TraceTriangle( traceInfo_t *ti, traceTriangle_t *tt, trace_t *trace ) if( ti->castShadows != 1 ) return qfalse; } - + /* receive shadows from same group and worldspawn group */ else if( trace->recvShadows > 1 ) { @@ -1428,6 +1409,13 @@ qboolean TraceTriangle( traceInfo_t *ti, traceTriangle_t *tt, trace_t *trace ) return qfalse; } + /* skip patches when doing the grid (FIXME this is an ugly hack) */ + if( inGrid ) + { + if (ti->skipGrid) + return qfalse; + } + /* begin calculating determinant - also used to calculate u parameter */ CrossProduct( trace->direction, tt->edge2, pvec ); @@ -1487,6 +1475,9 @@ qboolean TraceTriangle( traceInfo_t *ti, traceTriangle_t *tt, trace_t *trace ) trace->opaque = qtrue; return qtrue; } + + /* force subsampling because the lighting is texture dependent */ + trace->forceSubsampling = 1.0; /* try to avoid double shadows near triangle seams */ if( u < -ASLF_EPSILON || u > (1.0f + ASLF_EPSILON) || @@ -1529,6 +1520,7 @@ qboolean TraceTriangle( traceInfo_t *ti, traceTriangle_t *tt, trace_t *trace ) /* check filter for opaque */ if( trace->color[ 0 ] <= 0.001f && trace->color[ 1 ] <= 0.001f && trace->color[ 2 ] <= 0.001f ) { + VectorClear( trace->color ); VectorMA( trace->origin, depth, trace->direction, trace->hit ); trace->opaque = qtrue; return qtrue; diff --git a/tools/quake3/q3map2/light_ydnar.c b/tools/quake3/q3map2/light_ydnar.c index 44d60d8a..f60e6645 100644 --- a/tools/quake3/q3map2/light_ydnar.c +++ b/tools/quake3/q3map2/light_ydnar.c @@ -49,6 +49,7 @@ void ColorToBytes( const float *color, byte *colorBytes, float scale ) int i; float max, gamma; vec3_t sample; + float inv, dif; /* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */ @@ -72,15 +73,50 @@ void ColorToBytes( const float *color, byte *colorBytes, float scale ) /* gamma */ sample[ i ] = pow( sample[ i ] / 255.0f, gamma ) * 255.0f; } - - /* clamp with color normalization */ - max = sample[ 0 ]; - if( sample[ 1 ] > max ) - max = sample[ 1 ]; - if( sample[ 2 ] > max ) - max = sample[ 2 ]; - if( max > 255.0f ) - VectorScale( sample, (255.0f / max), sample ); + + if (lightmapExposure == 1) + { + /* clamp with color normalization */ + max = sample[ 0 ]; + if( sample[ 1 ] > max ) + max = sample[ 1 ]; + if( sample[ 2 ] > max ) + max = sample[ 2 ]; + if( max > 255.0f ) + VectorScale( sample, (255.0f / max), sample ); + } + else + { + if (lightmapExposure==0) + { + lightmapExposure=1.0f; + } + inv=1.f/lightmapExposure; + //Exposure + + max = sample[ 0 ]; + if( sample[ 1 ] > max ) + max = sample[ 1 ]; + if( sample[ 2 ] > max ) + max = sample[ 2 ]; + + dif = (1- exp(-max * inv) ) * 255; + + if (max >0) + { + dif = dif / max; + } + else + { + dif = 0; + } + + for (i=0;i<3;i++) + { + sample[i]*=dif; + } + } + /* compensate for ingame overbrighting/bitshifting */ VectorScale( sample, (1.0f / lightmapCompensate), sample ); @@ -384,7 +420,7 @@ maps a luxel for triangle bv at #define NUDGE 0.5f #define BOGUS_NUDGE -99999.0f -static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv, vec4_t plane, float pass, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] ) +static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv, vec4_t plane, float pass, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] ) { int i, x, y, numClusters, *clusters, pointCluster, *cluster; float *luxel, *origin, *normal, d, lightmapSampleOffset; @@ -392,6 +428,12 @@ static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t vec3_t pNormal; vec3_t vecs[ 3 ]; vec3_t nudged; + vec3_t cverts[ 3 ]; + vec3_t temp; + vec4_t sideplane, hostplane; + vec3_t origintwo; + int j, next; + float e; float *nudge; static float nudges[][ 2 ] = { @@ -485,6 +527,51 @@ static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t /* non axial lightmap projection (explicit xyz) */ else VectorCopy( dv->xyz, origin ); + + ////////////////////// + //27's test to make sure samples stay within the triangle boundaries + //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y) + //2) if it does, nudge it onto the correct side. + + if (worldverts!=NULL && lightmapTriangleCheck) + { + for (j=0;j<3;j++) + { + VectorCopy(worldverts[j],cverts[j]); + } + PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]); + + for (j=0;j<3;j++) + { + for (i=0;i<3;i++) + { + //build plane using 2 edges and a normal + next=(i+1)%3; + + VectorCopy(cverts[next],temp); + VectorAdd(temp,hostplane,temp); + PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp); + + //planetest sample point + e=DotProduct(origin,sideplane); + e=e-sideplane[3]; + if (e>0) + { + //we're bad. + //VectorClear(origin); + //Move the sample point back inside triangle bounds + origin[0]-=sideplane[0]*(e+1); + origin[1]-=sideplane[1]*(e+1); + origin[2]-=sideplane[2]*(e+1); +#ifdef DEBUG_27_1 + VectorClear(origin); +#endif + } + } + } + } + + //////////////////////// /* planar surfaces have precalculated lightmap vectors for nudging */ if( lm->plane != NULL ) @@ -516,8 +603,16 @@ static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t else origin[ lm->axisNum ] += lightmapSampleOffset; + VectorCopy(origin,origintwo); + if(lightmapExtraVisClusterNudge) + { + origintwo[0]+=vecs[2][0]; + origintwo[1]+=vecs[2][1]; + origintwo[2]+=vecs[2][2]; + } + /* get cluster */ - pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters ); + pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters ); /* another retarded hack, storing nudge count in luxel[ 1 ] */ luxel[ 1 ] = 0.0f; @@ -533,14 +628,14 @@ static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t for( i = 0; i < 3; i++ ) { /* set nudged point*/ - nudged[ i ] = origin[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]); + nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]); } nudge += 2; /* get pvs cluster */ pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 ); - if( pointCluster >= 0 ) - VectorCopy( nudged, origin ); + if( pointCluster >= 0 ) + VectorCopy( nudged, origin ); luxel[ 1 ] += 1.0f; } } @@ -597,7 +692,7 @@ recursively subdivides a triangle until its edges are shorter than the distance between two luxels (thanks jc :) */ -static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], vec4_t plane, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] ) +static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], vec4_t plane, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] ) { bspDrawVert_t mid, *dv2[ 3 ]; int max; @@ -645,7 +740,7 @@ static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t /* split the longest edge and map it */ LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid ); - MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv ); + MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts ); /* push the point up a little bit to account for fp creep (fixme: revisit this) */ //% VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz ); @@ -653,12 +748,12 @@ static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t /* recurse to first triangle */ VectorCopy( dv, dv2 ); dv2[ max ] = ∣ - MapTriangle_r( lm, info, dv2, plane, stv, ttv ); + MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts ); /* recurse to second triangle */ VectorCopy( dv, dv2 ); dv2[ (max + 1) % 3 ] = ∣ - MapTriangle_r( lm, info, dv2, plane, stv, ttv ); + MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts ); } @@ -674,6 +769,7 @@ static qboolean MapTriangle( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert int i; vec4_t plane; vec3_t *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ]; + vec3_t worldverts[ 3 ]; /* get plane if possible */ @@ -699,16 +795,20 @@ static qboolean MapTriangle( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert ttv = NULL; } + VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] ); + VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] ); + VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] ); + /* map the vertexes */ - MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv ); - MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv ); - MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv ); + MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts ); + MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts ); + MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts ); /* 2002-11-20: prefer axial triangle edges */ if( mapNonAxial ) { /* subdivide the triangle */ - MapTriangle_r( lm, info, dv, plane, stv, ttv ); + MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts ); return qtrue; } @@ -730,7 +830,7 @@ static qboolean MapTriangle( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert dv2[ 2 ] = dv[ (i + 1) % 3 ]; /* map the degenerate triangle */ - MapTriangle_r( lm, info, dv2, plane, stv, ttv ); + MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts ); } } @@ -792,8 +892,8 @@ static void MapQuad_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] ); /* map the vertexes */ - MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv ); - MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv ); + MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL ); + MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL ); /* 0 and 2 */ if( max == 0 ) @@ -878,10 +978,10 @@ static qboolean MapQuad( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t * } /* map the vertexes */ - MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv ); - MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv ); - MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv ); - MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv ); + MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL ); + MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL ); + MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL ); + MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL ); /* subdivide the quad */ MapQuad_r( lm, info, dv, plane, stv, ttv ); @@ -1054,13 +1154,18 @@ void MapRawLightmap( int rawLightmapNum ) if( MapQuad( lm, info, dv ) ) continue; - /* get drawverts and map first triangle */ - MapTriangle( lm, info, dv, mapNonAxial ); - - /* get drawverts and map second triangle */ - dv[ 1 ] = &verts[ pw[ r + 2 ] ]; - dv[ 2 ] = &verts[ pw[ r + 3 ] ]; - MapTriangle( lm, info, dv, mapNonAxial ); + for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ ) + { + /* get drawverts and map first triangle */ + dv[ 1 ] = &verts[ pw[ r + 1 ] ]; + dv[ 2 ] = &verts[ pw[ r + 2 ] ]; + MapTriangle( lm, info, dv, mapNonAxial ); + + /* get drawverts and map second triangle */ + dv[ 1 ] = &verts[ pw[ r + 2 ] ]; + dv[ 2 ] = &verts[ pw[ r + 3 ] ]; + MapTriangle( lm, info, dv, mapNonAxial ); + } } } @@ -1173,7 +1278,7 @@ void MapRawLightmap( int rawLightmapNum ) continue; /* map the fake vert */ - MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL ); + MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL ); } } } @@ -1325,7 +1430,7 @@ float DirtForSample( trace_t *trace ) VectorCopy( trace->normal, normal ); /* check if the normal is aligned to the world-up */ - if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f ) + if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && ( normal[ 2 ] == 1.0f || normal[ 2 ] == -1.0f ) ) { if( normal[ 2 ] == 1.0f ) { @@ -1371,7 +1476,7 @@ float DirtForSample( trace_t *trace ) /* trace */ TraceLine( trace ); - if( trace->opaque ) + if( trace->opaque && !(trace->compileFlags & C_SKY) ) { VectorSubtract( trace->hit, trace->origin, displacement ); gatherDirt += 1.0f - ooDepth * VectorLength( displacement ); @@ -1446,7 +1551,8 @@ void DirtyRawLightmap( int rawLightmapNum ) rawLightmap_t *lm; surfaceInfo_t *info; trace_t trace; - + qboolean noDirty; + /* bail if this number exceeds the number of raw lightmaps */ if( rawLightmapNum >= numRawLightmaps ) @@ -1461,7 +1567,7 @@ void DirtyRawLightmap( int rawLightmapNum ) trace.recvShadows = lm->recvShadows; trace.numSurfaces = lm->numLightSurfaces; trace.surfaces = &lightSurfaces[ lm->firstLightSurface ]; - trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS; + trace.inhibitRadius = 0.0f; trace.testAll = qfalse; /* twosided lighting (may or may not be a good idea for lightmapped stuff) */ @@ -1478,6 +1584,20 @@ void DirtyRawLightmap( int rawLightmapNum ) break; } } + + noDirty = qfalse; + for( i = 0; i < trace.numSurfaces; i++ ) + { + /* get surface */ + info = &surfaceInfos[ trace.surfaces[ i ] ]; + + /* check twosidedness */ + if( info->si->noDirty ) + { + noDirty = qtrue; + break; + } + } /* gather dirt */ for( y = 0; y < lm->sh; y++ ) @@ -1496,6 +1616,13 @@ void DirtyRawLightmap( int rawLightmapNum ) /* only look at mapped luxels */ if( *cluster < 0 ) continue; + + /* don't apply dirty on this surface */ + if( noDirty ) + { + *dirt = 1.0f; + continue; + } /* copy to trace */ trace.cluster = *cluster; @@ -1592,7 +1719,9 @@ static qboolean SubmapRawLuxel( rawLightmap_t *lm, int x, int y, float bx, float //% normal2 = SUPER_NORMAL( x, y ); } else - Sys_Printf( "WARNING: Spurious lightmap S vector\n" ); + { + Error( "Spurious lightmap S vector\n" ); + } VectorSubtract( origin2, origin, originVecs[ 0 ] ); //% VectorSubtract( normal2, normal, normalVecs[ 0 ] ); @@ -1651,14 +1780,15 @@ SubsampleRawLuxel_r() recursively subsamples a luxel until its color gradient is low enough or subsampling limit is reached */ -static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel ) +static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel, float *lightDeluxel ) { int b, samples, mapped, lighted; int cluster[ 4 ]; vec4_t luxel[ 4 ]; + vec3_t deluxel[ 3 ]; vec3_t origin[ 4 ], normal[ 4 ]; float biasDirs[ 4 ][ 2 ] = { { -1.0f, -1.0f }, { 1.0f, -1.0f }, { -1.0f, 1.0f }, { 1.0f, 1.0f } }; - vec3_t color, total; + vec3_t color, direction, total; /* limit check */ @@ -1695,9 +1825,20 @@ static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampl /* sample light */ LightContributionToSample( trace ); + if(trace->forceSubsampling > 1.0f) + { + /* alphashadow: we subsample as deep as we can */ + ++lighted; + ++mapped; + ++mapped; + } /* add to totals (fixme: make contrast function) */ VectorCopy( trace->color, luxel[ b ] ); + if(lightDeluxel) + { + VectorCopy( trace->directionContribution, deluxel[ b ] ); + } VectorAdd( total, trace->color, total ); if( (luxel[ b ][ 0 ] + luxel[ b ][ 1 ] + luxel[ b ][ 2 ]) > 0.0f ) lighted++; @@ -1712,7 +1853,7 @@ static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampl { if( cluster[ b ] < 0 ) continue; - SubsampleRawLuxel_r( lm, trace, origin[ b ], x, y, (bias * 0.25f), luxel[ b ] ); + SubsampleRawLuxel_r( lm, trace, origin[ b ], x, y, (bias * 0.5f), luxel[ b ], lightDeluxel ? deluxel[ b ] : NULL ); } } @@ -1720,12 +1861,20 @@ static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampl //% VectorClear( color ); //% samples = 0; VectorCopy( lightLuxel, color ); + if(lightDeluxel) + { + VectorCopy( lightDeluxel, direction ); + } samples = 1; for( b = 0; b < 4; b++ ) { if( cluster[ b ] < 0 ) continue; VectorAdd( color, luxel[ b ], color ); + if(lightDeluxel) + { + VectorAdd( direction, deluxel[ b ], direction ); + } samples++; } @@ -1736,10 +1885,85 @@ static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampl color[ 0 ] /= samples; color[ 1 ] /= samples; color[ 2 ] /= samples; - + /* add to color */ VectorCopy( color, lightLuxel ); lightLuxel[ 3 ] += 1.0f; + + if(lightDeluxel) + { + direction[ 0 ] /= samples; + direction[ 1 ] /= samples; + direction[ 2 ] /= samples; + VectorCopy( direction, lightDeluxel ); + } + } +} + +/* A mostly Gaussian-like bounded random distribution (sigma is expected standard deviation) */ +static void GaussLikeRandom(float sigma, float *x, float *y) +{ + float r; + r = Random() * 2 * Q_PI; + *x = sigma * 2.73861278752581783822 * cos(r); + *y = sigma * 2.73861278752581783822 * sin(r); + r = Random(); + r = 1 - sqrt(r); + r = 1 - sqrt(r); + *x *= r; + *y *= r; +} +static void RandomSubsampleRawLuxel( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel, float *lightDeluxel ) +{ + int b, mapped; + int cluster; + vec3_t origin, normal; + vec3_t total, totaldirection; + float dx, dy; + + VectorClear( total ); + VectorClear( totaldirection ); + mapped = 0; + for(b = 0; b < lightSamples; ++b) + { + /* set origin */ + VectorCopy( sampleOrigin, origin ); + GaussLikeRandom(bias, &dx, &dy); + + /* calculate position */ + if( !SubmapRawLuxel( lm, x, y, dx, dy, &cluster, origin, normal ) ) + { + cluster = -1; + continue; + } + mapped++; + + trace->cluster = cluster; + VectorCopy( origin, trace->origin ); + VectorCopy( normal, trace->normal ); + + LightContributionToSample( trace ); + VectorAdd( total, trace->color, total ); + if(lightDeluxel) + { + VectorAdd( totaldirection, trace->directionContribution, totaldirection ); + } + } + + /* add to luxel */ + if( mapped > 0 ) + { + /* average */ + lightLuxel[ 0 ] = total[ 0 ] / mapped; + lightLuxel[ 1 ] = total[ 1 ] / mapped; + lightLuxel[ 2 ] = total[ 2 ] / mapped; + + if(lightDeluxel) + { + lightDeluxel[ 0 ] = totaldirection[ 0 ] / mapped; + lightDeluxel[ 1 ] = totaldirection[ 1 ] / mapped; + lightDeluxel[ 2 ] = totaldirection[ 2 ] / mapped; + } } } @@ -1752,18 +1976,21 @@ illuminates the luxels #define STACK_LL_SIZE (SUPER_LUXEL_SIZE * 64 * 64) #define LIGHT_LUXEL( x, y ) (lightLuxels + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE)) +#define LIGHT_DELUXEL( x, y ) (lightDeluxels + ((((y) * lm->sw) + (x)) * SUPER_DELUXEL_SIZE)) void IlluminateRawLightmap( int rawLightmapNum ) { - int i, t, x, y, sx, sy, size, llSize, luxelFilterRadius, lightmapNum; + int i, t, x, y, sx, sy, size, luxelFilterRadius, lightmapNum; int *cluster, *cluster2, mapped, lighted, totalLighted; + size_t llSize, ldSize; rawLightmap_t *lm; surfaceInfo_t *info; qboolean filterColor, filterDir; float brightness; float *origin, *normal, *dirt, *luxel, *luxel2, *deluxel, *deluxel2; - float *lightLuxels, *lightLuxel, samples, filterRadius, weight; - vec3_t color, averageColor, averageDir, total, temp, temp2; + unsigned char *flag; + float *lightLuxels, *lightDeluxels, *lightLuxel, *lightDeluxel, samples, filterRadius, weight; + vec3_t color, direction, averageColor, averageDir, total, temp, temp2; float tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }; trace_t trace; float stackLightLuxels[ STACK_LL_SIZE ]; @@ -1877,10 +2104,15 @@ void IlluminateRawLightmap( int rawLightmapNum ) { /* allocate temporary per-light luxel storage */ llSize = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float ); + ldSize = lm->sw * lm->sh * SUPER_DELUXEL_SIZE * sizeof( float ); if( llSize <= (STACK_LL_SIZE * sizeof( float )) ) lightLuxels = stackLightLuxels; else lightLuxels = safe_malloc( llSize ); + if(deluxemap) + lightDeluxels = safe_malloc( ldSize ); + else + lightDeluxels = NULL; /* clear luxels */ //% memset( lm->superLuxels[ 0 ], 0, llSize ); @@ -1905,7 +2137,15 @@ void IlluminateRawLightmap( int rawLightmapNum ) { VectorCopy( ambientColor, luxel ); if( deluxemap ) - VectorScale( normal, 0.00390625f, deluxel ); + { + brightness = RGBTOGRAY( ambientColor ) * ( 1.0f/255.0f ); + + // use AT LEAST this amount of contribution from ambient for the deluxemap, fixes points that receive ZERO light + if(brightness < 0.00390625f) + brightness = 0.00390625f; + + VectorScale( normal, brightness, deluxel ); + } luxel[ 3 ] = 1.0f; } } @@ -1946,8 +2186,31 @@ void IlluminateRawLightmap( int rawLightmapNum ) /* setup */ memset( lightLuxels, 0, llSize ); + if(deluxemap) + memset( lightDeluxels, 0, ldSize ); totalLighted = 0; + /* determine filter radius */ + filterRadius = lm->filterRadius > trace.light->filterRadius + ? lm->filterRadius + : trace.light->filterRadius; + if( filterRadius < 0.0f ) + filterRadius = 0.0f; + + /* set luxel filter radius */ + luxelFilterRadius = superSample * filterRadius / lm->sampleSize; + if( luxelFilterRadius == 0 && (filterRadius > 0.0f || filter) ) + luxelFilterRadius = 1; + + /* allocate sampling flags storage */ + if((lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0) + { + size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( unsigned char ); + if(lm->superFlags == NULL) + lm->superFlags = safe_malloc( size ); + memset( (void *) lm->superFlags, 0, size ); + } + /* initial pass, one sample per luxel */ for( y = 0; y < lm->sh; y++ ) { @@ -1960,34 +2223,49 @@ void IlluminateRawLightmap( int rawLightmapNum ) /* get particulars */ lightLuxel = LIGHT_LUXEL( x, y ); - deluxel = SUPER_DELUXEL( x, y ); + lightDeluxel = LIGHT_DELUXEL( x, y ); origin = SUPER_ORIGIN( x, y ); normal = SUPER_NORMAL( x, y ); - - /* set contribution count */ - lightLuxel[ 3 ] = 1.0f; - - /* setup trace */ - trace.cluster = *cluster; - VectorCopy( origin, trace.origin ); - VectorCopy( normal, trace.normal ); - - /* get light for this sample */ - LightContributionToSample( &trace ); - VectorCopy( trace.color, lightLuxel ); - - /* add to count */ - if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] ) + flag = SUPER_FLAG( x, y ); + +#if 0 + ////////// 27's temp hack for testing edge clipping //// + if( origin[0]==0 && origin[1]==0 && origin[2]==0 ) + { + lightLuxel[ 1 ] = 255; + lightLuxel[ 3 ] = 1.0f; totalLighted++; - - /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */ - if( deluxemap ) + } + else +#endif { - /* color to grayscale (photoshop rgb weighting) */ - brightness = trace.color[ 0 ] * 0.3f + trace.color[ 1 ] * 0.59f + trace.color[ 2 ] * 0.11f; - brightness *= (1.0 / 255.0); - VectorScale( trace.direction, brightness, trace.direction ); - VectorAdd( deluxel, trace.direction, deluxel ); + /* set contribution count */ + lightLuxel[ 3 ] = 1.0f; + + /* setup trace */ + trace.cluster = *cluster; + VectorCopy( origin, trace.origin ); + VectorCopy( normal, trace.normal ); + + /* get light for this sample */ + LightContributionToSample( &trace ); + VectorCopy( trace.color, lightLuxel ); + + /* add the contribution to the deluxemap */ + if( deluxemap ) + { + VectorCopy( trace.directionContribution, lightDeluxel ); + } + + /* check for evilness */ + if(trace.forceSubsampling > 1.0f && (lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0) + { + totalLighted++; + *flag |= FLAG_FORCE_SUBSAMPLING; /* force */ + } + /* add to count */ + else if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] ) + totalLighted++; } } } @@ -1996,21 +2274,9 @@ void IlluminateRawLightmap( int rawLightmapNum ) if( totalLighted == 0 ) continue; - /* determine filter radius */ - filterRadius = lm->filterRadius > trace.light->filterRadius - ? lm->filterRadius - : trace.light->filterRadius; - if( filterRadius < 0.0f ) - filterRadius = 0.0f; - - /* set luxel filter radius */ - luxelFilterRadius = superSample * filterRadius / lm->sampleSize; - if( luxelFilterRadius == 0 && (filterRadius > 0.0f || filter) ) - luxelFilterRadius = 1; - /* secondary pass, adaptive supersampling (fixme: use a contrast function to determine if subsampling is necessary) */ /* 2003-09-27: changed it so filtering disamples supersampling, as it would waste time */ - if( lightSamples > 1 && luxelFilterRadius == 0 ) + if( (lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0 ) { /* walk luxels */ for( y = 0; y < (lm->sh - 1); y++ ) @@ -2036,6 +2302,14 @@ void IlluminateRawLightmap( int rawLightmapNum ) mapped++; /* get luxel */ + flag = SUPER_FLAG( sx, sy ); + if(*flag & FLAG_FORCE_SUBSAMPLING) + { + /* force a lighted/mapped discrepancy so we subsample */ + ++lighted; + ++mapped; + ++mapped; + } lightLuxel = LIGHT_LUXEL( sx, sy ); VectorAdd( total, lightLuxel, total ); if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) > 0.0f ) @@ -2059,7 +2333,11 @@ void IlluminateRawLightmap( int rawLightmapNum ) cluster = SUPER_CLUSTER( sx, sy ); if( *cluster < 0 ) continue; + flag = SUPER_FLAG( sx, sy ); + if(*flag & FLAG_ALREADY_SUBSAMPLED) // already subsampled + continue; lightLuxel = LIGHT_LUXEL( sx, sy ); + lightDeluxel = LIGHT_DELUXEL( sx, sy ); origin = SUPER_ORIGIN( sx, sy ); /* only subsample shadowed luxels */ @@ -2067,7 +2345,12 @@ void IlluminateRawLightmap( int rawLightmapNum ) //% continue; /* subsample it */ - SubsampleRawLuxel_r( lm, &trace, origin, sx, sy, 0.25f, lightLuxel ); + if(lightRandomSamples) + RandomSubsampleRawLuxel( lm, &trace, origin, sx, sy, 0.5f * lightSamplesSearchBoxSize, lightLuxel, deluxemap ? lightDeluxel : NULL ); + else + SubsampleRawLuxel_r( lm, &trace, origin, sx, sy, 0.25f * lightSamplesSearchBoxSize, lightLuxel, deluxemap ? lightDeluxel : NULL ); + + *flag |= FLAG_ALREADY_SUBSAMPLED; /* debug code to colorize subsampled areas to yellow */ //% luxel = SUPER_LUXEL( lightmapNum, sx, sy ); @@ -2109,7 +2392,7 @@ void IlluminateRawLightmap( int rawLightmapNum ) lm->superLuxels[ lightmapNum ] = safe_malloc( size ); memset( lm->superLuxels[ lightmapNum ], 0, size ); } - + /* set style */ if( lightmapNum > 0 ) { @@ -2133,6 +2416,7 @@ void IlluminateRawLightmap( int rawLightmapNum ) { /* setup */ VectorClear( averageColor ); + VectorClear( averageDir ); samples = 0.0f; /* cheaper distance-based filtering */ @@ -2151,6 +2435,7 @@ void IlluminateRawLightmap( int rawLightmapNum ) if( *cluster < 0 ) continue; lightLuxel = LIGHT_LUXEL( sx, sy ); + lightDeluxel = LIGHT_DELUXEL( sx, sy ); /* create weight */ weight = (abs( sx - x ) == luxelFilterRadius ? 0.5f : 1.0f); @@ -2159,6 +2444,11 @@ void IlluminateRawLightmap( int rawLightmapNum ) /* scale luxel by filter weight */ VectorScale( lightLuxel, weight, color ); VectorAdd( averageColor, color, averageColor ); + if(deluxemap) + { + VectorScale( lightDeluxel, weight, direction ); + VectorAdd( averageDir, direction, averageDir ); + } samples += weight; } } @@ -2186,6 +2476,15 @@ void IlluminateRawLightmap( int rawLightmapNum ) luxel[ 1 ] += averageColor[ 1 ] / samples; luxel[ 2 ] += averageColor[ 2 ] / samples; } + + if(deluxemap) + { + /* scale into luxel */ + deluxel = SUPER_DELUXEL( x, y ); + deluxel[ 0 ] += averageDir[ 0 ] / samples; + deluxel[ 1 ] += averageDir[ 1 ] / samples; + deluxel[ 2 ] += averageDir[ 2 ] / samples; + } } /* single sample */ @@ -2193,7 +2492,9 @@ void IlluminateRawLightmap( int rawLightmapNum ) { /* get particulars */ lightLuxel = LIGHT_LUXEL( x, y ); + lightDeluxel = LIGHT_DELUXEL( x, y ); luxel = SUPER_LUXEL( lightmapNum, x, y ); + deluxel = SUPER_DELUXEL( x, y ); /* handle negative light */ if( trace.light->flags & LIGHT_NEGATIVE ) @@ -2209,6 +2510,11 @@ void IlluminateRawLightmap( int rawLightmapNum ) /* handle normal light */ else VectorAdd( luxel, lightLuxel, luxel ); + + if(deluxemap) + { + VectorAdd( deluxel, lightDeluxel, deluxel ); + } } } } @@ -2217,11 +2523,47 @@ void IlluminateRawLightmap( int rawLightmapNum ) /* free temporary luxels */ if( lightLuxels != stackLightLuxels ) free( lightLuxels ); + + if(deluxemap) + free( lightDeluxels ); } /* free light list */ FreeTraceLights( &trace ); + /* floodlight pass */ + if( floodlighty ) + FloodlightIlluminateLightmap(lm); + + if (debugnormals) + { + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* early out */ + if( lm->superLuxels[ lightmapNum ] == NULL ) + continue; + + for( y = 0; y < lm->sh; y++ ) + { + for( x = 0; x < lm->sw; x++ ) + { + /* get cluster */ + cluster = SUPER_CLUSTER( x, y ); + //% if( *cluster < 0 ) + //% continue; + + /* get particulars */ + luxel = SUPER_LUXEL( lightmapNum, x, y ); + normal = SUPER_NORMAL ( x, y ); + + luxel[0]=(normal[0]*127)+127; + luxel[1]=(normal[1]*127)+127; + luxel[2]=(normal[2]*127)+127; + } + } + } + } + /* ----------------------------------------------------------------- dirt pass ----------------------------------------------------------------- */ @@ -2242,7 +2584,7 @@ void IlluminateRawLightmap( int rawLightmapNum ) { /* get cluster */ cluster = SUPER_CLUSTER( x, y ); - //% if( *cluster < 0 ) + //% if( *cluster < 0 ) // TODO why not do this check? These pixels should be zero anyway //% continue; /* get particulars */ @@ -2288,6 +2630,7 @@ void IlluminateRawLightmap( int rawLightmapNum ) if( *cluster < 0 || (lm->splotchFix && (luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ])) ) filterColor = qtrue; + if( deluxemap && lightmapNum == 0 && (*cluster < 0 || filter) ) filterDir = qtrue; @@ -2355,6 +2698,44 @@ void IlluminateRawLightmap( int rawLightmapNum ) } } } + + +#if 0 + // audit pass + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* early out */ + if( lm->superLuxels[ lightmapNum ] == NULL ) + continue; + for( y = 0; y < lm->sh; y++ ) + for( x = 0; x < lm->sw; x++ ) + { + /* get cluster */ + cluster = SUPER_CLUSTER( x, y ); + luxel = SUPER_LUXEL( lightmapNum, x, y ); + deluxel = SUPER_DELUXEL( x, y ); + if(!luxel || !deluxel || !cluster) + { + Sys_FPrintf(SYS_VRB, "WARNING: I got NULL'd.\n"); + continue; + } + else if(*cluster < 0) + { + // unmapped pixel + // should have neither deluxemap nor lightmap + if(deluxel[3]) + Sys_FPrintf(SYS_VRB, "WARNING: I have written deluxe to an unmapped luxel. Sorry.\n"); + } + else + { + // mapped pixel + // should have both deluxemap and lightmap + if(deluxel[3]) + Sys_FPrintf(SYS_VRB, "WARNING: I forgot to write deluxe to a mapped luxel. Sorry.\n"); + } + } + } +#endif } @@ -2377,6 +2758,8 @@ void IlluminateVertexes( int num ) rawLightmap_t *lm; bspDrawVert_t *verts; trace_t trace; + float floodLightAmount; + vec3_t floodColor; /* get surface, info, and raw lightmap */ @@ -2454,11 +2837,20 @@ void IlluminateVertexes( int num ) VectorCopy( verts[ i ].normal, trace.normal ); /* r7 dirt */ - if( dirty ) + if( dirty && !bouncing ) dirt = DirtForSample( &trace ); else dirt = 1.0f; + /* jal: floodlight */ + floodLightAmount = 0.0f; + VectorClear( floodColor ); + if( floodlighty && !bouncing ) + { + floodLightAmount = floodlightIntensity * FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality ); + VectorScale( floodlightRGB, floodLightAmount, floodColor ); + } + /* trace */ LightingAtSample( &trace, ds->vertexStyles, colors ); @@ -2467,6 +2859,9 @@ void IlluminateVertexes( int num ) { /* r7 dirt */ VectorScale( colors[ lightmapNum ], dirt, colors[ lightmapNum ] ); + + /* jal: floodlight */ + VectorAdd( colors[ lightmapNum ], floodColor, colors[ lightmapNum ] ); /* store */ radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i ); @@ -2482,16 +2877,16 @@ void IlluminateVertexes( int num ) radVertLuxel[ 2 ] <= ambientColor[ 2 ] ) { /* nudge the sample point around a bit */ - for( x = 0; x < 4; x++ ) + for( x = 0; x < 5; x++ ) { /* two's complement 0, 1, -1, 2, -2, etc */ x1 = ((x >> 1) ^ (x & 1 ? -1 : 0)) + (x & 1); - for( y = 0; y < 4; y++ ) + for( y = 0; y < 5; y++ ) { y1 = ((y >> 1) ^ (y & 1 ? -1 : 0)) + (y & 1); - for( z = 0; z < 4; z++ ) + for( z = 0; z < 5; z++ ) { z1 = ((z >> 1) ^ (z & 1 ? -1 : 0)) + (z & 1); @@ -2504,6 +2899,21 @@ void IlluminateVertexes( int num ) trace.cluster = ClusterForPointExtFilter( origin, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] ); if( trace.cluster < 0 ) continue; + + /* r7 dirt */ + if( dirty && !bouncing ) + dirt = DirtForSample( &trace ); + else + dirt = 1.0f; + + /* jal: floodlight */ + floodLightAmount = 0.0f; + VectorClear( floodColor ); + if( floodlighty && !bouncing ) + { + floodLightAmount = floodlightIntensity * FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality ); + VectorScale( floodlightRGB, floodLightAmount, floodColor ); + } /* trace */ LightingAtSample( &trace, ds->vertexStyles, colors ); @@ -2513,6 +2923,9 @@ void IlluminateVertexes( int num ) { /* r7 dirt */ VectorScale( colors[ lightmapNum ], dirt, colors[ lightmapNum ] ); + + /* jal: floodlight */ + VectorAdd( colors[ lightmapNum ], floodColor, colors[ lightmapNum ] ); /* store */ radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i ); @@ -3112,7 +3525,7 @@ void SetupEnvelopes( qboolean forGrid, qboolean fastFlag ) int i, x, y, z, x1, y1, z1; light_t *light, *light2, **owner; bspLeaf_t *leaf; - vec3_t origin, dir, mins, maxs, nullVector = { 0, 0, 0 }; + vec3_t origin, dir, mins, maxs; float radius, intensity; light_t *buckets[ 256 ]; @@ -3225,6 +3638,7 @@ void SetupEnvelopes( qboolean forGrid, qboolean fastFlag ) /* check for fast mode */ if( !(light->flags & LIGHT_FAST) && !(light->flags & LIGHT_FAST_TEMP) ) light->envelope = MAX_WORLD_COORD * 8.0f; + intensity = light->photons; /* hopefully not used */ } else { @@ -3587,7 +4001,434 @@ void CreateTraceLightsForSurface( int num, trace_t *trace ) CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace ); } +///////////////////////////////////////////////////////////// + +#define FLOODLIGHT_CONE_ANGLE 88 /* degrees */ +#define FLOODLIGHT_NUM_ANGLE_STEPS 16 +#define FLOODLIGHT_NUM_ELEVATION_STEPS 4 +#define FLOODLIGHT_NUM_VECTORS (FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS) + +static vec3_t floodVectors[ FLOODLIGHT_NUM_VECTORS ]; +static int numFloodVectors = 0; + +void SetupFloodLight( void ) +{ + int i, j; + float angle, elevation, angleStep, elevationStep; + const char *value; + double v1,v2,v3,v4,v5,v6; + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" ); + + /* calculate angular steps */ + angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS ); + elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS ); + + /* iterate angle */ + angle = 0.0f; + for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep ) + { + /* iterate elevation */ + for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep ) + { + floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle ); + floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle ); + floodVectors[ numFloodVectors ][ 2 ] = cos( elevation ); + numFloodVectors++; + } + } + + /* emit some statistics */ + Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors ); + + /* floodlight */ + value = ValueForKey( &entities[ 0 ], "_floodlight" ); + + if( value[ 0 ] != '\0' ) + { + v1=v2=v3=0; + v4=floodlightDistance; + v5=floodlightIntensity; + v6=floodlightDirectionScale; + + sscanf( value, "%lf %lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5); + + floodlightRGB[0]=v1; + floodlightRGB[1]=v2; + floodlightRGB[2]=v3; + + if (VectorLength(floodlightRGB)==0) + { + VectorSet(floodlightRGB,240,240,255); + } + + if (v4<1) v4=1024; + if (v5<1) v5=128; + if (v6<0) v6=1; + + floodlightDistance=v4; + floodlightIntensity=v5; + floodlightDirectionScale=v6; + + floodlighty = qtrue; + Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" ); + } + else + { + VectorSet(floodlightRGB,240,240,255); + //floodlighty = qtrue; + //Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" ); + } + VectorNormalize(floodlightRGB,floodlightRGB); +} + +/* +FloodLightForSample() +calculates floodlight value for a given sample +once again, kudos to the dirtmapping coder +*/ + +float FloodLightForSample( trace_t *trace , float floodLightDistance, qboolean floodLightLowQuality) +{ + int i; + float d; + float contribution; + int sub = 0; + float gatherLight, outLight; + vec3_t normal, worldUp, myUp, myRt, direction, displacement; + float dd; + int vecs = 0; + + gatherLight=0; + /* dummy check */ + //if( !dirty ) + // return 1.0f; + if( trace == NULL || trace->cluster < 0 ) + return 0.0f; + + + /* setup */ + dd = floodLightDistance; + VectorCopy( trace->normal, normal ); + + /* check if the normal is aligned to the world-up */ + if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && ( normal[ 2 ] == 1.0f || normal[ 2 ] == -1.0f ) ) + { + if( normal[ 2 ] == 1.0f ) + { + VectorSet( myRt, 1.0f, 0.0f, 0.0f ); + VectorSet( myUp, 0.0f, 1.0f, 0.0f ); + } + else if( normal[ 2 ] == -1.0f ) + { + VectorSet( myRt, -1.0f, 0.0f, 0.0f ); + VectorSet( myUp, 0.0f, 1.0f, 0.0f ); + } + } + else + { + VectorSet( worldUp, 0.0f, 0.0f, 1.0f ); + CrossProduct( normal, worldUp, myRt ); + VectorNormalize( myRt, myRt ); + CrossProduct( myRt, normal, myUp ); + VectorNormalize( myUp, myUp ); + } + + /* vortex: optimise floodLightLowQuality a bit */ + if ( floodLightLowQuality == qtrue ) + { + /* iterate through ordered vectors */ + for( i = 0; i < numFloodVectors; i++ ) + if (rand()%10 != 0 ) continue; + } + else + { + /* iterate through ordered vectors */ + for( i = 0; i < numFloodVectors; i++ ) + { + vecs++; + + /* transform vector into tangent space */ + direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ]; + direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ]; + direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ]; + + /* set endpoint */ + VectorMA( trace->origin, dd, direction, trace->end ); + //VectorMA( trace->origin, 1, direction, trace->origin ); + + SetupTrace( trace ); + /* trace */ + TraceLine( trace ); + contribution=1; + if ( trace->compileFlags & C_SKY || trace->compileFlags & C_TRANSLUCENT ) + { + contribution=1.0f; + } + else if ( trace->opaque ) + { + VectorSubtract( trace->hit, trace->origin, displacement ); + d=VectorLength( displacement ); + + // d=trace->distance; + //if (d>256) gatherDirt+=1; + contribution=d/dd; + if (contribution>1) contribution=1.0f; + + //gatherDirt += 1.0f - ooDepth * VectorLength( displacement ); + } + + gatherLight+=contribution; + } + } + + /* early out */ + if( gatherLight <= 0.0f ) + return 0.0f; + + sub=vecs; + if (sub<1) sub=1; + gatherLight/=(sub); + outLight=gatherLight; + if( outLight > 1.0f ) + outLight = 1.0f; + + /* return to sender */ + return outLight; +} + +/* +FloodLightRawLightmap +lighttracer style ambient occlusion light hack. +Kudos to the dirtmapping author for most of this source. +VorteX: modified to floodlight up custom surfaces (q3map_floodLight) +VorteX: fixed problems with deluxemapping +*/ + +// floodlight pass on a lightmap +void FloodLightRawLightmapPass( rawLightmap_t *lm , vec3_t lmFloodLightRGB, float lmFloodLightIntensity, float lmFloodLightDistance, qboolean lmFloodLightLowQuality, float floodlightDirectionScale) +{ + int i, x, y, *cluster; + float *origin, *normal, *floodlight, floodLightAmount; + surfaceInfo_t *info; + trace_t trace; + // int sx, sy; + // float samples, average, *floodlight2; + + memset(&trace,0,sizeof(trace_t)); + + /* setup trace */ + trace.testOcclusion = qtrue; + trace.forceSunlight = qfalse; + trace.twoSided = qtrue; + trace.recvShadows = lm->recvShadows; + trace.numSurfaces = lm->numLightSurfaces; + trace.surfaces = &lightSurfaces[ lm->firstLightSurface ]; + trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS; + trace.testAll = qfalse; + trace.distance = 1024; + + /* twosided lighting (may or may not be a good idea for lightmapped stuff) */ + //trace.twoSided = qfalse; + for( i = 0; i < trace.numSurfaces; i++ ) + { + /* get surface */ + info = &surfaceInfos[ trace.surfaces[ i ] ]; + + /* check twosidedness */ + if( info->si->twoSided ) + { + trace.twoSided = qtrue; + break; + } + } + + /* gather floodlight */ + for( y = 0; y < lm->sh; y++ ) + { + for( x = 0; x < lm->sw; x++ ) + { + /* get luxel */ + cluster = SUPER_CLUSTER( x, y ); + origin = SUPER_ORIGIN( x, y ); + normal = SUPER_NORMAL( x, y ); + floodlight = SUPER_FLOODLIGHT( x, y ); + + /* set default dirt */ + *floodlight = 0.0f; + + /* only look at mapped luxels */ + if( *cluster < 0 ) + continue; + + /* copy to trace */ + trace.cluster = *cluster; + VectorCopy( origin, trace.origin ); + VectorCopy( normal, trace.normal ); + + /* get floodlight */ + floodLightAmount = FloodLightForSample( &trace , lmFloodLightDistance, lmFloodLightLowQuality)*lmFloodLightIntensity; + + /* add floodlight */ + floodlight[0] += lmFloodLightRGB[0]*floodLightAmount; + floodlight[1] += lmFloodLightRGB[1]*floodLightAmount; + floodlight[2] += lmFloodLightRGB[2]*floodLightAmount; + floodlight[3] += floodlightDirectionScale; + } + } + + /* testing no filtering */ + return; + +#if 0 + + /* filter "dirt" */ + for( y = 0; y < lm->sh; y++ ) + { + for( x = 0; x < lm->sw; x++ ) + { + /* get luxel */ + cluster = SUPER_CLUSTER( x, y ); + floodlight = SUPER_FLOODLIGHT(x, y ); + + /* filter dirt by adjacency to unmapped luxels */ + average = *floodlight; + samples = 1.0f; + for( sy = (y - 1); sy <= (y + 1); sy++ ) + { + if( sy < 0 || sy >= lm->sh ) + continue; + + for( sx = (x - 1); sx <= (x + 1); sx++ ) + { + if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) ) + continue; + + /* get neighboring luxel */ + cluster = SUPER_CLUSTER( sx, sy ); + floodlight2 = SUPER_FLOODLIGHT( sx, sy ); + if( *cluster < 0 || *floodlight2 <= 0.0f ) + continue; + + /* add it */ + average += *floodlight2; + samples += 1.0f; + } + + /* bail */ + if( samples <= 0.0f ) + break; + } + + /* bail */ + if( samples <= 0.0f ) + continue; + + /* scale dirt */ + *floodlight = average / samples; + } + } +#endif +} + +void FloodLightRawLightmap( int rawLightmapNum ) +{ + rawLightmap_t *lm; + + /* bail if this number exceeds the number of raw lightmaps */ + if( rawLightmapNum >= numRawLightmaps ) + return; + /* get lightmap */ + lm = &rawLightmaps[ rawLightmapNum ]; + + /* global pass */ + if (floodlighty && floodlightIntensity) + FloodLightRawLightmapPass(lm, floodlightRGB, floodlightIntensity, floodlightDistance, floodlight_lowquality, floodlightDirectionScale); + + /* custom pass */ + if (lm->floodlightIntensity) + { + FloodLightRawLightmapPass(lm, lm->floodlightRGB, lm->floodlightIntensity, lm->floodlightDistance, qfalse, lm->floodlightDirectionScale); + numSurfacesFloodlighten += 1; + } +} + +void FloodlightRawLightmaps() +{ + Sys_Printf( "--- FloodlightRawLightmap ---\n" ); + numSurfacesFloodlighten = 0; + RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap ); + Sys_Printf( "%9d custom lightmaps floodlighted\n", numSurfacesFloodlighten ); +} + +/* +FloodLightIlluminate() +illuminate floodlight into lightmap luxels +*/ + +void FloodlightIlluminateLightmap( rawLightmap_t *lm ) +{ + float *luxel, *floodlight, *deluxel, *normal; + int *cluster; + float brightness; + int x, y, lightmapNum; + + /* walk lightmaps */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* early out */ + if( lm->superLuxels[ lightmapNum ] == NULL ) + continue; + + /* apply floodlight to each luxel */ + for( y = 0; y < lm->sh; y++ ) + { + for( x = 0; x < lm->sw; x++ ) + { + /* get floodlight */ + floodlight = SUPER_FLOODLIGHT( x, y ); + if (!floodlight[0] && !floodlight[1] && !floodlight[2]) + continue; + + /* get cluster */ + cluster = SUPER_CLUSTER( x, y ); + + /* only process mapped luxels */ + if( *cluster < 0 ) + continue; + + /* get particulars */ + luxel = SUPER_LUXEL( lightmapNum, x, y ); + deluxel = SUPER_DELUXEL( x, y ); + + /* add to lightmap */ + luxel[0]+=floodlight[0]; + luxel[1]+=floodlight[1]; + luxel[2]+=floodlight[2]; + + if (luxel[3]==0) luxel[3]=1; + + /* add to deluxemap */ + if (deluxemap && floodlight[3] > 0) + { + vec3_t lightvector; + + normal = SUPER_NORMAL( x, y ); + brightness = RGBTOGRAY( floodlight ) * ( 1.0f/255.0f ) * floodlight[3]; + + // use AT LEAST this amount of contribution from ambient for the deluxemap, fixes points that receive ZERO light + if(brightness < 0.00390625f) + brightness = 0.00390625f; + + VectorScale( normal, brightness, lightvector ); + VectorAdd( deluxel, lightvector, deluxel ); + } + } + } + } +} diff --git a/tools/quake3/q3map2/lightmaps.c b/tools/quake3/q3map2/lightmaps.c index 62977ddf..13f5c533 100644 --- a/tools/quake3/q3map2/lightmaps.c +++ b/tools/quake3/q3map2/lightmaps.c @@ -30,7 +30,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ int numSortShaders; -mapDrawSurface_t *surfsOnShader[ MAX_MAP_SHADERS ]; +mapDrawSurface_t **surfsOnShader; +int allocatedSurfsOnShader; int allocated[ LIGHTMAP_WIDTH ]; @@ -96,94 +97,6 @@ AllocateLightmapForPatch */ //#define LIGHTMAP_PATCHSHIFT -void AllocateLightmapForPatch( mapDrawSurface_t *ds ) -{ - int i, j, k; - drawVert_t *verts; - int w, h; - int x, y; - float s, t; - mesh_t mesh, *subdividedMesh, *tempMesh, *newmesh; - int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_HEIGHT], ssize; - - verts = ds->verts; - - mesh.width = ds->patchWidth; - mesh.height = ds->patchHeight; - mesh.verts = verts; - newmesh = SubdivideMesh( mesh, 8, 999 ); - - PutMeshOnCurve( *newmesh ); - tempMesh = RemoveLinearMeshColumnsRows( newmesh ); - FreeMesh(newmesh); - - /* get sample size */ - ssize = ds->sampleSize; - - -#ifdef LIGHTMAP_PATCHSHIFT - subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH-1, widthtable, heighttable ); -#else - subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH, widthtable, heighttable ); -#endif - - w = subdividedMesh->width; - h = subdividedMesh->height; - -#ifdef LIGHTMAP_PATCHSHIFT - w++; - h++; -#endif - - FreeMesh(subdividedMesh); - - // allocate the lightmap - c_exactLightmap += w * h; - - if ( !AllocLMBlock( w, h, &x, &y ) ) { - PrepareNewLightmap(); - if ( !AllocLMBlock( w, h, &x, &y ) ) - { - Error("Entity %i, brush %i: Lightmap allocation failed", - ds->mapBrush->entitynum, ds->mapBrush->brushnum ); - } - } - -#ifdef LIGHTMAP_PATCHSHIFT - w--; - h--; -#endif - - // set the lightmap texture coordinates in the drawVerts - ds->lightmapNum = numLightmaps - 1; - ds->lightmapWidth = w; - ds->lightmapHeight = h; - ds->lightmapX = x; - ds->lightmapY = y; - - for ( i = 0 ; i < ds->patchWidth ; i++ ) { - for ( k = 0 ; k < w ; k++ ) { - if ( originalWidths[k] >= i ) { - break; - } - } - if (k >= w) - k = w-1; - s = x + k; - for ( j = 0 ; j < ds->patchHeight ; j++ ) { - for ( k = 0 ; k < h ; k++ ) { - if ( originalHeights[k] >= j ) { - break; - } - } - if (k >= h) - k = h-1; - t = y + k; - verts[i + j * ds->patchWidth].lightmap[0] = ( s + 0.5 ) / LIGHTMAP_WIDTH; - verts[i + j * ds->patchWidth].lightmap[1] = ( t + 0.5 ) / LIGHTMAP_HEIGHT; - } - } -} /* @@ -194,176 +107,6 @@ AllocateLightmapForSurface //#define LIGHTMAP_BLOCK 16 -void AllocateLightmapForSurface( mapDrawSurface_t *ds ) -{ - vec3_t mins, maxs, size, exactSize, delta; - int i; - drawVert_t *verts; - int w, h; - int x, y, ssize; - int axis; - vec3_t vecs[ 2 ]; - float s, t; - vec3_t origin; - vec4_t plane; - float d; - - - /* debug code */ - #if 0 - if( ds->type == SURF_META && ds->planar == qfalse ) - Sys_Printf( "NPMS: %3d vertexes, %s\n", ds->numVerts, ds->shaderInfo->shader ); - else if( ds->type == SURF_META && ds->planar == qtrue ) - Sys_Printf( "PMS: %3d vertexes, %s\n", ds->numVerts, ds->shaderInfo->shader ); - #endif - - /* ydnar: handle planar patches */ - if( noPatchFix == qtrue || (ds->type == SURF_PATCH && ds->planeNum < 0) ) - { - AllocateLightmapForPatch( ds ); - return; - } - - /* get sample size */ - ssize = ds->sampleSize; - - /* bound the surface */ - ClearBounds( mins, maxs ); - verts = ds->verts; - for ( i = 0 ; i < ds->numVerts ; i++ ) - AddPointToBounds( verts[i].xyz, mins, maxs ); - - /* round to the lightmap resolution */ - for( i = 0; i < 3; i++ ) - { - exactSize[i] = maxs[i] - mins[i]; - mins[i] = ssize * floor( mins[i] / ssize ); - maxs[i] = ssize * ceil( maxs[i] / ssize ); - size[i] = (maxs[i] - mins[i]) / ssize + 1; - } - - /* ydnar: lightmap projection axis is already stored */ - memset( vecs, 0, sizeof( vecs ) ); - - /* classify the plane (x y or z major) (ydnar: biased to z axis projection) */ - if( ds->lightmapAxis[ 2 ] >= ds->lightmapAxis[ 0 ] && ds->lightmapAxis[ 2 ] >= ds->lightmapAxis[ 1 ] ) - { - w = size[ 0 ]; - h = size[ 1 ]; - axis = 2; - vecs[ 0 ][ 0 ] = 1.0 / ssize; - vecs[ 1 ][ 1 ] = 1.0 / ssize; - } - else if( ds->lightmapAxis[ 0 ] >= ds->lightmapAxis[ 1 ] && ds->lightmapAxis[ 0 ] >= ds->lightmapAxis[ 2 ] ) - { - w = size[ 1 ]; - h = size[ 2 ]; - axis = 0; - vecs[ 0 ][ 1 ] = 1.0 / ssize; - vecs[ 1 ][ 2 ] = 1.0 / ssize; - } - else - { - w = size[ 0 ]; - h = size[ 2 ]; - axis = 1; - vecs[ 0 ][ 0 ] = 1.0 / ssize; - vecs[ 1 ][ 2 ] = 1.0 / ssize; - } - - /* odd check, given projection is now precalculated */ - if( ds->lightmapAxis[ axis ] == 0 ) - Error( "Chose a 0 valued axis" ); - - /* clamp to lightmap texture resolution */ - if( w > LIGHTMAP_WIDTH ) - { - VectorScale ( vecs[0], (float) LIGHTMAP_WIDTH / w, vecs[0] ); - w = LIGHTMAP_WIDTH; - } - if( h > LIGHTMAP_HEIGHT ) - { - VectorScale ( vecs[1], (float) LIGHTMAP_HEIGHT / h, vecs[1] ); - h = LIGHTMAP_HEIGHT; - } - - - /* ydnar */ - if( ds->planar == qfalse ) - c_nonplanarLightmap += w * h; - c_exactLightmap += w * h; - - - if( !AllocLMBlock( w, h, &x, &y ) ) - { - PrepareNewLightmap(); - if ( !AllocLMBlock( w, h, &x, &y ) ) - { - Error( "Entity %i, brush %i: Lightmap allocation failed", - ds->mapBrush->entitynum, ds->mapBrush->brushnum ); - } - } - - /* set the lightmap texture coordinates in the drawVerts */ - ds->lightmapNum = numLightmaps - 1; - ds->lightmapWidth = w; - ds->lightmapHeight = h; - ds->lightmapX = x; - ds->lightmapY = y; - for ( i = 0 ; i < ds->numVerts ; i++ ) - { - VectorSubtract( verts[i].xyz, mins, delta ); - s = DotProduct( delta, vecs[0] ) + x + 0.5; - t = DotProduct( delta, vecs[1] ) + y + 0.5; - verts[i].lightmap[0] = s / LIGHTMAP_WIDTH; - verts[i].lightmap[1] = t / LIGHTMAP_HEIGHT; - } - - /* calculate the world coordinates of the lightmap samples */ - - /* construct a plane from the first vert and clear bounding box */ - - /* project mins onto plane to get origin */ - VectorCopy( ds->lightmapVecs[ 2 ], plane ); - plane[ 3 ] = DotProduct( ds->verts[ 0 ].xyz, plane ); - d = DotProduct( mins, plane ) - plane[ 3 ]; - d /= plane[ axis ]; - - //% d = DotProduct( mins, plane->normal ) - plane->dist; - //% d /= plane->normal[ axis ]; - VectorCopy( mins, origin ); - origin[ axis ] -= d; - - /* project stepped lightmap blocks and subtract to get planevecs */ - for( i = 0; i < 2; i++ ) - { - vec3_t normalized; - float len; - - len = VectorNormalize( vecs[i], normalized ); - VectorScale( normalized, (1.0/len), vecs[i] ); - d = DotProduct( vecs[i], plane ); - d /= plane[ axis ]; - //%d = DotProduct( vecs[i], plane->normal ); - //%d /= plane->normal[ axis ]; - vecs[i][axis] -= d; - } - - /* store lightmap origin and vectors (fixme: make this work right) */ - VectorCopy( origin, ds->lightmapOrigin ); - //% VectorCopy( plane->normal, ds->lightmapVecs[ 2 ] ); - - /* ydnar: lightmap vectors 0 and 1 are used for lod bounds, so don't overwrite */ - if( ds->type == SURF_PATCH ) - c_planarPatch++; - - /* store lightmap vectors */ - VectorCopy( vecs[ 0 ], ds->lightmapVecs[ 0 ] ); - VectorCopy( vecs[ 1 ], ds->lightmapVecs[ 1 ] ); - - /* ydnar: print some stats */ - //Sys_FPrintf( SYS_VRB, "Lightmap block %3d (%3d, %3d) (%3d x %3d) emitted\n", (numLightmaps - 1), x, y, w, h ); -} /* @@ -371,126 +114,6 @@ void AllocateLightmapForSurface( mapDrawSurface_t *ds ) AllocateLightmaps =================== */ -void AllocateLightmaps( entity_t *e ) -{ - int i, j; - mapDrawSurface_t *ds; - shaderInfo_t *si; - - - /* note it */ - Sys_FPrintf( SYS_VRB,"--- AllocateLightmaps ---\n" ); - - - /* sort all surfaces by shader so common shaders will usually be in the same lightmap */ - /* ydnar: this is done in two passes, because of an odd bug with lightmapped terrain */ - numSortShaders = 0; - for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ ) - { - /* get surface and early out if possible */ - ds = &mapDrawSurfs[ i ]; - si = ds->shaderInfo; - if( si->surfaceFlags & SURF_VERTEXLIT ) - continue; - if( ds->numVerts <= 0 ) - continue; - - /* ydnar: handle brush faces and patches first */ - if( ds->type != SURF_FACE && ds->type != SURF_PATCH ) - continue; - - /* ydnar: this is unecessary because it should already be set */ - //% VectorCopy( ds->plane.normal, ds->lightmapVecs[ 2 ] ); - - /* search for this shader */ - for( j = 0 ; j < numSortShaders; j++ ) - { - if( ds->shaderInfo == surfsOnShader[ j ]->shaderInfo ) - { - ds->nextOnShader = surfsOnShader[ j ]; - surfsOnShader[ j ] = ds; - break; - } - } - - /* new shader */ - if( j == numSortShaders ) - { - if( numSortShaders >= MAX_MAP_SHADERS ) - Error( "MAX_MAP_SHADERS" ); - surfsOnShader[ j ] = ds; - ds->nextOnShader = NULL; - numSortShaders++; - } - } - - /* second pass, to allocate lightmapped terrain last */ - for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ ) - { - /* get surface and early out if possible */ - ds = &mapDrawSurfs[ i ]; - si = ds->shaderInfo; - if( si->surfaceFlags & SURF_VERTEXLIT ) - continue; - if( ds->numVerts <= 0 ) - continue; - - /* ydnar: this only handles metasurfaces and terrain */ - if( ds->type != SURF_TERRAIN && ds->type != SURF_META ) - continue; - - /* ydnar: a lightmap projection should be pre-stored for anything but excessively curved patches */ - if( VectorLength( ds->lightmapAxis ) <= 0 ) - continue; - - /* search for this shader */ - for( j = 0; j < numSortShaders; j++ ) - { - if( ds->shaderInfo == surfsOnShader[ j ]->shaderInfo ) - { - ds->nextOnShader = surfsOnShader[ j ]; - surfsOnShader[ j ] = ds; - break; - } - } - - /* new shader */ - if( j == numSortShaders ) - { - if( numSortShaders >= MAX_MAP_SHADERS ) - Error( "MAX_MAP_SHADERS" ); - surfsOnShader[ j ] = ds; - ds->nextOnShader = NULL; - numSortShaders++; - } - } - - /* tot up shader count */ - Sys_FPrintf( SYS_VRB, "%9d unique shaders\n", numSortShaders ); - - /* for each shader, allocate lightmaps for each surface */ - for( i = 0; i < numSortShaders; i++ ) - { - si = surfsOnShader[ i ]->shaderInfo; - for( ds = surfsOnShader[ i ]; ds; ds = ds->nextOnShader ) - { - /* ydnar: promoting pointlight above nolightmap */ - if( si->surfaceFlags & SURF_POINTLIGHT ) - ds->lightmapNum = -3; - else if( si->surfaceFlags & SURF_NOLIGHTMAP ) - ds->lightmapNum = -1; - else - AllocateLightmapForSurface( ds ); - } - } - - /* emit some statistics */ - Sys_FPrintf( SYS_VRB, "%9d exact lightmap texels\n", c_exactLightmap ); - Sys_FPrintf( SYS_VRB, "%9d block lightmap texels\n", numLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT ); - Sys_FPrintf( SYS_VRB, "%9d non-planar or terrain lightmap texels\n", c_nonplanarLightmap ); - Sys_FPrintf( SYS_VRB, "%9d planar patch lightmaps\n", c_planarPatch ); - Sys_FPrintf( SYS_VRB, "%9d lightmap textures, size: %d Kbytes\n", numLightmaps, (numLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3) / 1024 ); -} diff --git a/tools/quake3/q3map2/lightmaps_ydnar.c b/tools/quake3/q3map2/lightmaps_ydnar.c index 8ae0d75a..080f26ec 100644 --- a/tools/quake3/q3map2/lightmaps_ydnar.c +++ b/tools/quake3/q3map2/lightmaps_ydnar.c @@ -291,8 +291,8 @@ static int CompareLightSurface( const void *a, const void *b ) /* get shaders */ - asi = surfaceInfos[ *((int*) a) ].si; - bsi = surfaceInfos[ *((int*) b) ].si; + asi = surfaceInfos[ *((const int*) a) ].si; + bsi = surfaceInfos[ *((const int*) b) ].si; /* dummy check */ if( asi == NULL ) @@ -414,6 +414,12 @@ void FinishRawLightmap( rawLightmap_t *lm ) lm->superNormals = safe_malloc( size ); memset( lm->superNormals, 0, size ); + /* allocate floodlight map storage */ + size = lm->sw * lm->sh * SUPER_FLOODLIGHT_SIZE * sizeof( float ); + if( lm->superFloodLight == NULL ) + lm->superFloodLight = safe_malloc( size ); + memset( lm->superFloodLight, 0, size ); + /* allocate cluster map storage */ size = lm->sw * lm->sh * sizeof( int ); if( lm->superClusters == NULL ) @@ -672,12 +678,25 @@ qboolean AddSurfaceToRawLightmap( int num, rawLightmap_t *lm ) size[ i ] = (maxs[ i ] - mins[ i ]) / sampleSize + 1.0f; /* hack (god this sucks) */ - if( size[ i ] > lm->customWidth || size[ i ] > lm->customHeight ) + if( size[ i ] > lm->customWidth || size[ i ] > lm->customHeight || (lmLimitSize && size[i] > lmLimitSize)) { i = -1; sampleSize += 1.0f; } } + + if(sampleSize != lm->sampleSize && lmLimitSize == 0) + { + Sys_FPrintf(SYS_VRB,"WARNING: surface at (%6.0f %6.0f %6.0f) (%6.0f %6.0f %6.0f) too large for desired samplesize/lightmapsize/lightmapscale combination, increased samplesize from %d to %d\n", + info->mins[0], + info->mins[1], + info->mins[2], + info->maxs[0], + info->maxs[1], + info->maxs[2], + lm->sampleSize, + (int) sampleSize); + } /* set actual sample size */ lm->actualSampleSize = sampleSize; @@ -842,13 +861,13 @@ static int CompareSurfaceInfo( const void *a, const void *b ) /* get surface info */ - aInfo = &surfaceInfos[ *((int*) a) ]; - bInfo = &surfaceInfos[ *((int*) b) ]; + aInfo = &surfaceInfos[ *((const int*) a) ]; + bInfo = &surfaceInfos[ *((const int*) b) ]; /* model first */ - if( aInfo->model < bInfo->model ) + if( aInfo->modelindex < bInfo->modelindex ) return 1; - else if( aInfo->model > bInfo->model ) + else if( aInfo->modelindex > bInfo->modelindex ) return -1; /* then lightmap status */ @@ -856,6 +875,13 @@ static int CompareSurfaceInfo( const void *a, const void *b ) return 1; else if( aInfo->hasLightmap > bInfo->hasLightmap ) return -1; + + /* 27: then shader! */ + if (aInfo->si < bInfo->si) + return 1; + else if (aInfo->si > bInfo->si) + return -1; + /* then lightmap sample size */ if( aInfo->sampleSize < bInfo->sampleSize ) @@ -978,7 +1004,7 @@ void SetupSurfaceLightmaps( void ) VectorClear( entityOrigin ); /* basic setup */ - info->model = model; + info->modelindex = i; info->lm = NULL; info->plane = NULL; info->firstSurfaceCluster = numSurfaceClusters; @@ -1092,12 +1118,20 @@ void SetupSurfaceLightmaps( void ) lm->splotchFix = info->si->splotchFix; lm->firstLightSurface = numLightSurfaces; lm->numLightSurfaces = 0; - lm->sampleSize = info->sampleSize; - lm->actualSampleSize = info->sampleSize; + /* vortex: multiply lightmap sample size by -samplescale */ + if (sampleScale > 0) + lm->sampleSize = info->sampleSize*sampleScale; + else + lm->sampleSize = info->sampleSize; + lm->actualSampleSize = lm->sampleSize; lm->entityNum = info->entityNum; lm->recvShadows = info->recvShadows; lm->brightness = info->si->lmBrightness; lm->filterRadius = info->si->lmFilterRadius; + VectorCopy(info->si->floodlightRGB, lm->floodlightRGB); + lm->floodlightDistance = info->si->floodlightDistance; + lm->floodlightIntensity = info->si->floodlightIntensity; + lm->floodlightDirectionScale = info->si->floodlightDirectionScale; VectorCopy( info->axis, lm->axis ); lm->plane = info->plane; VectorCopy( info->mins, lm->mins ); @@ -1884,9 +1918,10 @@ FindOutLightmaps() for a given surface lightmap, find output lightmap pages and positions for it */ +#define LIGHTMAP_RESERVE_COUNT 1 static void FindOutLightmaps( rawLightmap_t *lm ) { - int i, j, lightmapNum, xMax, yMax, x, y, sx, sy, ox, oy, offset, temp; + int i, j, k, lightmapNum, xMax, yMax, x, y, sx, sy, ox, oy, offset; outLightmap_t *olm; surfaceInfo_t *info; float *luxel, *deluxel; @@ -1981,7 +2016,11 @@ static void FindOutLightmaps( rawLightmap_t *lm ) y = 0; /* walk the list of lightmap pages */ - for( i = 0; i < numOutLightmaps; i++ ) + if(lightmapSearchBlockSize <= 0 || numOutLightmaps < LIGHTMAP_RESERVE_COUNT) + i = 0; + else + i = ((numOutLightmaps - LIGHTMAP_RESERVE_COUNT) / lightmapSearchBlockSize) * lightmapSearchBlockSize; + for( ; i < numOutLightmaps; i++ ) { /* get the output lightmap */ olm = &outLightmaps[ i ]; @@ -2035,22 +2074,22 @@ static void FindOutLightmaps( rawLightmap_t *lm ) /* no match? */ if( ok == qfalse ) { - /* allocate two new output lightmaps */ - numOutLightmaps += 2; + /* allocate LIGHTMAP_RESERVE_COUNT new output lightmaps */ + numOutLightmaps += LIGHTMAP_RESERVE_COUNT; olm = safe_malloc( numOutLightmaps * sizeof( outLightmap_t ) ); - if( outLightmaps != NULL && numOutLightmaps > 2 ) + if( outLightmaps != NULL && numOutLightmaps > LIGHTMAP_RESERVE_COUNT ) { - memcpy( olm, outLightmaps, (numOutLightmaps - 2) * sizeof( outLightmap_t ) ); + memcpy( olm, outLightmaps, (numOutLightmaps - LIGHTMAP_RESERVE_COUNT) * sizeof( outLightmap_t ) ); free( outLightmaps ); } outLightmaps = olm; /* initialize both out lightmaps */ - SetupOutLightmap( lm, &outLightmaps[ numOutLightmaps - 2 ] ); - SetupOutLightmap( lm, &outLightmaps[ numOutLightmaps - 1 ] ); + for(k = numOutLightmaps - LIGHTMAP_RESERVE_COUNT; k < numOutLightmaps; ++k) + SetupOutLightmap( lm, &outLightmaps[ k ] ); /* set out lightmap */ - i = numOutLightmaps - 2; + i = numOutLightmaps - LIGHTMAP_RESERVE_COUNT; olm = &outLightmaps[ i ]; /* set stamp xy origin to the first surface lightmap */ @@ -2154,21 +2193,12 @@ static void FindOutLightmaps( rawLightmap_t *lm ) if( deluxemap ) { /* normalize average light direction */ - if( VectorNormalize( deluxel, direction ) ) - { - /* encode [-1,1] in [0,255] */ - pixel = olm->bspDirBytes + (((oy * olm->customWidth) + ox) * 3); - for( i = 0; i < 3; i++ ) - { - temp = (direction[ i ] + 1.0f) * 127.5f; - if( temp < 0 ) - pixel[ i ] = 0; - else if( temp > 255 ) - pixel[ i ] = 255; - else - pixel[ i ] = temp; - } - } + pixel = olm->bspDirBytes + (((oy * olm->customWidth) + ox) * 3); + VectorScale( deluxel, 1000.0f, direction ); + VectorNormalize( direction, direction ); + VectorScale( direction, 127.5f, direction ); + for( i = 0; i < 3; i++ ) + pixel[ i ] = (byte)( 127.5f + direction[ i ] ); } } } @@ -2190,8 +2220,8 @@ static int CompareRawLightmap( const void *a, const void *b ) /* get lightmaps */ - alm = &rawLightmaps[ *((int*) a) ]; - blm = &rawLightmaps[ *((int*) b) ]; + alm = &rawLightmaps[ *((const int*) a) ]; + blm = &rawLightmaps[ *((const int*) b) ]; /* get min number of surfaces */ min = (alm->numLightSurfaces < blm->numLightSurfaces ? alm->numLightSurfaces : blm->numLightSurfaces); @@ -2225,7 +2255,112 @@ static int CompareRawLightmap( const void *a, const void *b ) return 0; } +void FillOutLightmap(outLightmap_t *olm) +{ + int x, y; + int ofs; + vec3_t dir_sum, light_sum; + int cnt, filled; + byte *lightBitsNew = NULL; + byte *lightBytesNew = NULL; + byte *dirBytesNew = NULL; + + lightBitsNew = safe_malloc((olm->customWidth * olm->customHeight + 8) / 8); + lightBytesNew = safe_malloc(olm->customWidth * olm->customHeight * 3); + if(deluxemap) + dirBytesNew = safe_malloc(olm->customWidth * olm->customHeight * 3); + + /* + memset(olm->lightBits, 0, (olm->customWidth * olm->customHeight + 8) / 8); + olm->lightBits[0] |= 1; + olm->lightBits[(10 * olm->customWidth + 30) >> 3] |= 1 << ((10 * olm->customWidth + 30) & 7); + memset(olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3); + olm->bspLightBytes[0] = 255; + olm->bspLightBytes[(10 * olm->customWidth + 30) * 3 + 2] = 255; + */ + + memcpy(lightBitsNew, olm->lightBits, (olm->customWidth * olm->customHeight + 8) / 8); + memcpy(lightBytesNew, olm->bspLightBytes, olm->customWidth * olm->customHeight * 3); + if(deluxemap) + memcpy(dirBytesNew, olm->bspDirBytes, olm->customWidth * olm->customHeight * 3); + + for(;;) + { + filled = 0; + for(y = 0; y < olm->customHeight; ++y) + { + for(x = 0; x < olm->customWidth; ++x) + { + ofs = y * olm->customWidth + x; + if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */ + continue; + cnt = 0; + VectorClear(dir_sum); + VectorClear(light_sum); + + /* try all four neighbors */ + ofs = ((y + olm->customHeight - 1) % olm->customHeight) * olm->customWidth + x; + if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */ + { + ++cnt; + VectorAdd(light_sum, olm->bspLightBytes + ofs * 3, light_sum); + if(deluxemap) + VectorAdd(dir_sum, olm->bspDirBytes + ofs * 3, dir_sum); + } + + ofs = ((y + 1) % olm->customHeight) * olm->customWidth + x; + if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */ + { + ++cnt; + VectorAdd(light_sum, olm->bspLightBytes + ofs * 3, light_sum); + if(deluxemap) + VectorAdd(dir_sum, olm->bspDirBytes + ofs * 3, dir_sum); + } + + ofs = y * olm->customWidth + (x + olm->customWidth - 1) % olm->customWidth; + if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */ + { + ++cnt; + VectorAdd(light_sum, olm->bspLightBytes + ofs * 3, light_sum); + if(deluxemap) + VectorAdd(dir_sum, olm->bspDirBytes + ofs * 3, dir_sum); + } + + ofs = y * olm->customWidth + (x + 1) % olm->customWidth; + if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */ + { + ++cnt; + VectorAdd(light_sum, olm->bspLightBytes + ofs * 3, light_sum); + if(deluxemap) + VectorAdd(dir_sum, olm->bspDirBytes + ofs * 3, dir_sum); + } + + if(cnt) + { + ++filled; + ofs = y * olm->customWidth + x; + lightBitsNew[ofs >> 3] |= (1 << (ofs & 7)); + VectorScale(light_sum, 1.0/cnt, lightBytesNew + ofs * 3); + if(deluxemap) + VectorScale(dir_sum, 1.0/cnt, dirBytesNew + ofs * 3); + } + } + } + + if(!filled) + break; + + memcpy(olm->lightBits, lightBitsNew, (olm->customWidth * olm->customHeight + 8) / 8); + memcpy(olm->bspLightBytes, lightBytesNew, olm->customWidth * olm->customHeight * 3); + if(deluxemap) + memcpy(olm->bspDirBytes, dirBytesNew, olm->customWidth * olm->customHeight * 3); + } + free(lightBitsNew); + free(lightBytesNew); + if(deluxemap) + free(dirBytesNew); +} /* StoreSurfaceLightmaps() @@ -2251,16 +2386,23 @@ void StoreSurfaceLightmaps( void ) char dirname[ 1024 ], filename[ 1024 ]; shaderInfo_t *csi; char lightmapName[ 128 ]; - char *rgbGenValues[ 256 ]; - char *alphaGenValues[ 256 ]; + const char *rgbGenValues[ 256 ]; + const char *alphaGenValues[ 256 ]; /* note it */ Sys_Printf( "--- StoreSurfaceLightmaps ---\n"); /* setup */ - strcpy( dirname, source ); - StripExtension( dirname ); + if(lmCustomDir) + { + strcpy( dirname, lmCustomDir ); + } + else + { + strcpy( dirname, source ); + StripExtension( dirname ); + } memset( rgbGenValues, 0, sizeof( rgbGenValues ) ); memset( alphaGenValues, 0, sizeof( alphaGenValues ) ); @@ -2269,7 +2411,7 @@ void StoreSurfaceLightmaps( void ) ----------------------------------------------------------------- */ /* note it */ - Sys_FPrintf( SYS_VRB, "Subsampling..." ); + Sys_Printf( "Subsampling..." ); /* walk the list of raw lightmaps */ numUsed = 0; @@ -2605,6 +2747,135 @@ void StoreSurfaceLightmaps( void ) } } + /* ----------------------------------------------------------------- + convert modelspace deluxemaps to tangentspace + ----------------------------------------------------------------- */ + /* note it */ + if( !bouncing ) + { + if( deluxemap && deluxemode == 1) + { + vec3_t worldUp, myNormal, myTangent, myBinormal; + float dist; + + Sys_Printf( "converting..." ); + + for( i = 0; i < numRawLightmaps; i++ ) + { + /* get lightmap */ + lm = &rawLightmaps[ i ]; + + /* walk lightmap samples */ + for( y = 0; y < lm->sh; y++ ) + { + for( x = 0; x < lm->sw; x++ ) + { + /* get normal and deluxel */ + normal = SUPER_NORMAL(x, y); + cluster = SUPER_CLUSTER(x, y); + bspDeluxel = BSP_DELUXEL( x, y ); + deluxel = SUPER_DELUXEL( x, y ); + + /* get normal */ + VectorSet( myNormal, normal[0], normal[1], normal[2] ); + + /* get tangent vectors */ + if( myNormal[ 0 ] == 0.0f && myNormal[ 1 ] == 0.0f ) + { + if( myNormal[ 2 ] == 1.0f ) + { + VectorSet( myTangent, 1.0f, 0.0f, 0.0f ); + VectorSet( myBinormal, 0.0f, 1.0f, 0.0f ); + } + else if( myNormal[ 2 ] == -1.0f ) + { + VectorSet( myTangent, -1.0f, 0.0f, 0.0f ); + VectorSet( myBinormal, 0.0f, 1.0f, 0.0f ); + } + } + else + { + VectorSet( worldUp, 0.0f, 0.0f, 1.0f ); + CrossProduct( myNormal, worldUp, myTangent ); + VectorNormalize( myTangent, myTangent ); + CrossProduct( myTangent, myNormal, myBinormal ); + VectorNormalize( myBinormal, myBinormal ); + } + + /* project onto plane */ + dist = -DotProduct(myTangent, myNormal); + VectorMA(myTangent, dist, myNormal, myTangent); + dist = -DotProduct(myBinormal, myNormal); + VectorMA(myBinormal, dist, myNormal, myBinormal); + + /* renormalize */ + VectorNormalize( myTangent, myTangent ); + VectorNormalize( myBinormal, myBinormal ); + + /* convert modelspace deluxel to tangentspace */ + dirSample[0] = bspDeluxel[0]; + dirSample[1] = bspDeluxel[1]; + dirSample[2] = bspDeluxel[2]; + VectorNormalize(dirSample, dirSample); + + /* fix tangents to world matrix */ + if (myNormal[0] > 0 || myNormal[1] < 0 || myNormal[2] < 0) + VectorNegate(myTangent, myTangent); + + /* build tangentspace vectors */ + bspDeluxel[0] = DotProduct(dirSample, myTangent); + bspDeluxel[1] = DotProduct(dirSample, myBinormal); + bspDeluxel[2] = DotProduct(dirSample, myNormal); + } + } + } + } + } + + /* ----------------------------------------------------------------- + blend lightmaps + ----------------------------------------------------------------- */ + +#ifdef sdfsdfwq312323 + /* note it */ + Sys_Printf( "blending..." ); + + for( i = 0; i < numRawLightmaps; i++ ) + { + vec3_t myColor; + float myBrightness; + + /* get lightmap */ + lm = &rawLightmaps[ i ]; + + /* walk individual lightmaps */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* early outs */ + if( lm->superLuxels[ lightmapNum ] == NULL ) + continue; + + /* walk lightmap samples */ + for( y = 0; y < lm->sh; y++ ) + { + for( x = 0; x < lm->sw; x++ ) + { + /* get luxel */ + bspLuxel = BSP_LUXEL( lightmapNum, x, y ); + + /* get color */ + VectorNormalize(bspLuxel, myColor); + myBrightness = VectorLength(bspLuxel); + myBrightness *= (1 / 127.0f); + myBrightness = myBrightness*myBrightness; + myBrightness *= 127.0f; + VectorScale(myColor, myBrightness, bspLuxel); + } + } + } + } +#endif + /* ----------------------------------------------------------------- collapse non-unique lightmaps ----------------------------------------------------------------- */ @@ -2612,7 +2883,7 @@ void StoreSurfaceLightmaps( void ) if( noCollapse == qfalse && deluxemap == qfalse ) { /* note it */ - Sys_FPrintf( SYS_VRB, "collapsing..." ); + Sys_Printf( "collapsing..." ); /* set all twin refs to null */ for( i = 0; i < numRawLightmaps; i++ ) @@ -2680,7 +2951,7 @@ void StoreSurfaceLightmaps( void ) ----------------------------------------------------------------- */ /* note it */ - Sys_FPrintf( SYS_VRB, "sorting..." ); + Sys_Printf( "sorting..." ); /* allocate a new sorted list */ if( sortLightmaps == NULL ) @@ -2696,7 +2967,7 @@ void StoreSurfaceLightmaps( void ) ----------------------------------------------------------------- */ /* note it */ - Sys_FPrintf( SYS_VRB, "allocating..." ); + Sys_Printf( "allocating..." ); /* kill all existing output lightmaps */ if( outLightmaps != NULL ) @@ -2749,7 +3020,7 @@ void StoreSurfaceLightmaps( void ) ----------------------------------------------------------------- */ /* note it */ - Sys_FPrintf( SYS_VRB, "storing..." ); + Sys_Printf( "storing..." ); /* count the bsp lightmaps and allocate space */ if( bspLightBytes != NULL ) @@ -2771,6 +3042,10 @@ void StoreSurfaceLightmaps( void ) { /* get output lightmap */ olm = &outLightmaps[ i ]; + + /* fill output lightmap */ + if(lightmapFill) + FillOutLightmap(olm); /* is this a valid bsp lightmap? */ if( olm->lightmapNum >= 0 && !externalLightmaps ) @@ -2817,7 +3092,7 @@ void StoreSurfaceLightmaps( void ) } if( numExtLightmaps > 0 ) - Sys_FPrintf( SYS_VRB, "\n" ); + Sys_Printf( "\n" ); /* delete unused external lightmaps */ for( i = numExtLightmaps; i; i++ ) @@ -2836,7 +3111,7 @@ void StoreSurfaceLightmaps( void ) ----------------------------------------------------------------- */ /* note it */ - Sys_FPrintf( SYS_VRB, "projecting..." ); + Sys_Printf( "projecting..." ); /* walk the list of surfaces */ for( i = 0; i < numBSPDrawSurfaces; i++ ) @@ -3004,7 +3279,7 @@ void StoreSurfaceLightmaps( void ) if( rgbGenValues[ style ] == NULL ) { sprintf( key, "_style%drgbgen", style ); - rgbGenValues[ style ] = (char*) ValueForKey( &entities[ 0 ], key ); + rgbGenValues[ style ] = ValueForKey( &entities[ 0 ], key ); if( rgbGenValues[ style ][ 0 ] == '\0' ) rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37"; } @@ -3018,7 +3293,7 @@ void StoreSurfaceLightmaps( void ) if( alphaGenValues[ style ] == NULL ) { sprintf( key, "_style%dalphagen", style ); - alphaGenValues[ style ] = (char*) ValueForKey( &entities[ 0 ], key ); + alphaGenValues[ style ] = ValueForKey( &entities[ 0 ], key ); } if( alphaGenValues[ style ][ 0 ] != '\0' ) sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style ); @@ -3108,7 +3383,7 @@ void StoreSurfaceLightmaps( void ) } /* finish */ - Sys_FPrintf( SYS_VRB, "done.\n" ); + Sys_Printf( "done.\n" ); /* calc num stored */ numStored = numBSPLightBytes / 3; diff --git a/tools/quake3/q3map2/main.c b/tools/quake3/q3map2/main.c index 86d4d498..074a4a43 100644 --- a/tools/quake3/q3map2/main.c +++ b/tools/quake3/q3map2/main.c @@ -1,4 +1,4 @@ -/* ------------------------------------------------------------------------------- +/* -------------------------------------------------------------------------------; Copyright (C) 1999-2007 id Software, Inc. and contributors. For a list of contributors, see the accompanying CONTRIBUTORS file. @@ -36,6 +36,8 @@ several games based on the Quake III Arena engine, in the form of "Q3Map2." /* dependencies */ #include "q3map2.h" + + /* Random() returns a pseudorandom number between 0 and 1 @@ -60,17 +62,752 @@ static void ExitQ3Map( void ) free( mapDrawSurfs ); } -static int MD4BlockChecksum( void * buffer, int length ) { - unsigned char digest[16]; - int checksum; - - md4_get_digest( buffer, length, digest ); - /* I suppose it has to be done that way for legacy reasons? */ - checksum = digest[0] & ( digest[1] << 8 ) & ( digest[2] << 16 ) & ( digest[3] << 24 ); - checksum ^= digest[4] & ( digest[5] << 8 ) & ( digest[6] << 16 ) & ( digest[7] << 24 ); - checksum ^= digest[8] & ( digest[9] << 8 ) & ( digest[10] << 16 ) & ( digest[11] << 24 ); - checksum ^= digest[12] & ( digest[13] << 8 ) & ( digest[14] << 16 ) & ( digest[15] << 24 ); - return checksum; + + +/* minimap stuff */ + +typedef struct minimap_s +{ + bspModel_t *model; + int width; + int height; + int samples; + float *sample_offsets; + float sharpen_boxmult; + float sharpen_centermult; + float boost; + float *data1f; + float *sharpendata1f; + vec3_t mins, size; +} +minimap_t; +static minimap_t minimap; + +qboolean BrushIntersectionWithLine(bspBrush_t *brush, vec3_t start, vec3_t dir, float *t_in, float *t_out) +{ + int i; + qboolean in = qfalse, out = qfalse; + bspBrushSide_t *sides = &bspBrushSides[brush->firstSide]; + + for(i = 0; i < brush->numSides; ++i) + { + bspPlane_t *p = &bspPlanes[sides[i].planeNum]; + float sn = DotProduct(start, p->normal); + float dn = DotProduct(dir, p->normal); + if(dn == 0) + { + if(sn > p->dist) + return qfalse; // outside! + } + else + { + float t = (p->dist - sn) / dn; + if(dn < 0) + { + if(!in || t > *t_in) + { + *t_in = t; + in = qtrue; + // as t_in can only increase, and t_out can only decrease, early out + if(out && *t_in >= *t_out) + return qfalse; + } + } + else + { + if(!out || t < *t_out) + { + *t_out = t; + out = qtrue; + // as t_in can only increase, and t_out can only decrease, early out + if(in && *t_in >= *t_out) + return qfalse; + } + } + } + } + return in && out; +} + +static float MiniMapSample(float x, float y) +{ + vec3_t org, dir; + int i, bi; + float t0, t1; + float samp; + bspBrush_t *b; + bspBrushSide_t *s; + int cnt; + + org[0] = x; + org[1] = y; + org[2] = 0; + dir[0] = 0; + dir[1] = 0; + dir[2] = 1; + + cnt = 0; + samp = 0; + for(i = 0; i < minimap.model->numBSPBrushes; ++i) + { + bi = minimap.model->firstBSPBrush + i; + if(opaqueBrushes[bi >> 3] & (1 << (bi & 7))) + { + b = &bspBrushes[bi]; + + // sort out mins/maxs of the brush + s = &bspBrushSides[b->firstSide]; + if(x < -bspPlanes[s[0].planeNum].dist) + continue; + if(x > +bspPlanes[s[1].planeNum].dist) + continue; + if(y < -bspPlanes[s[2].planeNum].dist) + continue; + if(y > +bspPlanes[s[3].planeNum].dist) + continue; + + if(BrushIntersectionWithLine(b, org, dir, &t0, &t1)) + { + samp += t1 - t0; + ++cnt; + } + } + } + + return samp; +} + +void RandomVector2f(float v[2]) +{ + do + { + v[0] = 2 * Random() - 1; + v[1] = 2 * Random() - 1; + } + while(v[0] * v[0] + v[1] * v[1] > 1); +} + +static void MiniMapRandomlySupersampled(int y) +{ + int x, i; + float *p = &minimap.data1f[y * minimap.width]; + float ymin = minimap.mins[1] + minimap.size[1] * (y / (float) minimap.height); + float dx = minimap.size[0] / (float) minimap.width; + float dy = minimap.size[1] / (float) minimap.height; + float uv[2]; + float thisval; + + for(x = 0; x < minimap.width; ++x) + { + float xmin = minimap.mins[0] + minimap.size[0] * (x / (float) minimap.width); + float val = 0; + + for(i = 0; i < minimap.samples; ++i) + { + RandomVector2f(uv); + thisval = MiniMapSample( + xmin + (uv[0] + 0.5) * dx, /* exaggerated random pattern for better results */ + ymin + (uv[1] + 0.5) * dy /* exaggerated random pattern for better results */ + ); + val += thisval; + } + val /= minimap.samples * minimap.size[2]; + *p++ = val; + } +} + +static void MiniMapSupersampled(int y) +{ + int x, i; + float *p = &minimap.data1f[y * minimap.width]; + float ymin = minimap.mins[1] + minimap.size[1] * (y / (float) minimap.height); + float dx = minimap.size[0] / (float) minimap.width; + float dy = minimap.size[1] / (float) minimap.height; + + for(x = 0; x < minimap.width; ++x) + { + float xmin = minimap.mins[0] + minimap.size[0] * (x / (float) minimap.width); + float val = 0; + + for(i = 0; i < minimap.samples; ++i) + { + float thisval = MiniMapSample( + xmin + minimap.sample_offsets[2*i+0] * dx, + ymin + minimap.sample_offsets[2*i+1] * dy + ); + val += thisval; + } + val /= minimap.samples * minimap.size[2]; + *p++ = val; + } +} + +static void MiniMapNoSupersampling(int y) +{ + int x; + float *p = &minimap.data1f[y * minimap.width]; + float ymin = minimap.mins[1] + minimap.size[1] * ((y + 0.5) / (float) minimap.height); + + for(x = 0; x < minimap.width; ++x) + { + float xmin = minimap.mins[0] + minimap.size[0] * ((x + 0.5) / (float) minimap.width); + *p++ = MiniMapSample(xmin, ymin) / minimap.size[2]; + } +} + +static void MiniMapSharpen(int y) +{ + int x; + qboolean up = (y > 0); + qboolean down = (y < minimap.height - 1); + float *p = &minimap.data1f[y * minimap.width]; + float *q = &minimap.sharpendata1f[y * minimap.width]; + + for(x = 0; x < minimap.width; ++x) + { + qboolean left = (x > 0); + qboolean right = (x < minimap.width - 1); + float val = p[0] * minimap.sharpen_centermult; + + if(left && up) + val += p[-1 -minimap.width] * minimap.sharpen_boxmult; + if(left && down) + val += p[-1 +minimap.width] * minimap.sharpen_boxmult; + if(right && up) + val += p[+1 -minimap.width] * minimap.sharpen_boxmult; + if(right && down) + val += p[+1 +minimap.width] * minimap.sharpen_boxmult; + + if(left) + val += p[-1] * minimap.sharpen_boxmult; + if(right) + val += p[+1] * minimap.sharpen_boxmult; + if(up) + val += p[-minimap.width] * minimap.sharpen_boxmult; + if(down) + val += p[+minimap.width] * minimap.sharpen_boxmult; + + ++p; + *q++ = val; + } +} + +static void MiniMapContrastBoost(int y) +{ + int x; + float *q = &minimap.data1f[y * minimap.width]; + for(x = 0; x < minimap.width; ++x) + { + *q = *q * minimap.boost / ((minimap.boost - 1) * *q + 1); + ++q; + } +} + +void MiniMapMakeMinsMaxs(vec3_t mins_in, vec3_t maxs_in, float border, qboolean keepaspect) +{ + vec3_t mins, maxs, extend; + VectorCopy(mins_in, mins); + VectorCopy(maxs_in, maxs); + + // line compatible to nexuiz mapinfo + Sys_Printf("size %f %f %f %f %f %f\n", mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2]); + + if(keepaspect) + { + VectorSubtract(maxs, mins, extend); + if(extend[1] > extend[0]) + { + mins[0] -= (extend[1] - extend[0]) * 0.5; + maxs[0] += (extend[1] - extend[0]) * 0.5; + } + else + { + mins[1] -= (extend[0] - extend[1]) * 0.5; + maxs[1] += (extend[0] - extend[1]) * 0.5; + } + } + + /* border: amount of black area around the image */ + /* input: border, 1-2*border, border but we need border/(1-2*border) */ + + VectorSubtract(maxs, mins, extend); + VectorScale(extend, border / (1 - 2 * border), extend); + + VectorSubtract(mins, extend, mins); + VectorAdd(maxs, extend, maxs); + + VectorCopy(mins, minimap.mins); + VectorSubtract(maxs, mins, minimap.size); + + // line compatible to nexuiz mapinfo + Sys_Printf("size_texcoords %f %f %f %f %f %f\n", mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2]); +} + +/* +MiniMapSetupBrushes() +determines solid non-sky brushes in the world +*/ + +void MiniMapSetupBrushes( void ) +{ + int i, b, compileFlags; + bspBrush_t *brush; + bspShader_t *shader; + shaderInfo_t *si; + + + /* note it */ + Sys_FPrintf( SYS_VRB, "--- MiniMapSetupBrushes ---\n" ); + + /* allocate */ + if( opaqueBrushes == NULL ) + opaqueBrushes = safe_malloc( numBSPBrushes / 8 + 1 ); + + /* clear */ + memset( opaqueBrushes, 0, numBSPBrushes / 8 + 1 ); + numOpaqueBrushes = 0; + + /* walk the list of worldspawn brushes */ + for( i = 0; i < minimap.model->numBSPBrushes; i++ ) + { + /* get brush */ + b = minimap.model->firstBSPBrush + i; + brush = &bspBrushes[ b ]; + +#if 0 + /* check all sides */ + compileFlags = 0; + for( j = 0; j < brush->numSides; j++ ) + { + /* do bsp shader calculations */ + side = &bspBrushSides[ brush->firstSide + j ]; + shader = &bspShaders[ side->shaderNum ]; + + /* get shader info */ + si = ShaderInfoForShader( shader->shader ); + if( si == NULL ) + continue; + + /* or together compile flags */ + compileFlags |= si->compileFlags; + } +#else + shader = &bspShaders[ brush->shaderNum ]; + si = ShaderInfoForShader( shader->shader ); + if( si == NULL ) + compileFlags = 0; + else + compileFlags = si->compileFlags; +#endif + + /* determine if this brush is solid */ + if( (compileFlags & (C_SOLID | C_SKY)) == C_SOLID ) + { + opaqueBrushes[ b >> 3 ] |= (1 << (b & 7)); + numOpaqueBrushes++; + maxOpaqueBrush = i; + } + } + + /* emit some statistics */ + Sys_FPrintf( SYS_VRB, "%9d solid brushes\n", numOpaqueBrushes ); +} + +qboolean MiniMapEvaluateSampleOffsets(int *bestj, int *bestk, float *bestval) +{ + float val, dx, dy; + int j, k; + + *bestj = *bestk = -1; + *bestval = 3; /* max possible val is 2 */ + + for(j = 0; j < minimap.samples; ++j) + for(k = j + 1; k < minimap.samples; ++k) + { + dx = minimap.sample_offsets[2*j+0] - minimap.sample_offsets[2*k+0]; + dy = minimap.sample_offsets[2*j+1] - minimap.sample_offsets[2*k+1]; + if(dx > +0.5) dx -= 1; + if(dx < -0.5) dx += 1; + if(dy > +0.5) dy -= 1; + if(dy < -0.5) dy += 1; + val = dx * dx + dy * dy; + if(val < *bestval) + { + *bestj = j; + *bestk = k; + *bestval = val; + } + } + + return *bestval < 3; +} + +void MiniMapMakeSampleOffsets() +{ + int i, j, k, jj, kk; + float val, valj, valk, sx, sy, rx, ry; + + Sys_Printf( "Generating good sample offsets (this may take a while)...\n" ); + + /* start with entirely random samples */ + for(i = 0; i < minimap.samples; ++i) + { + minimap.sample_offsets[2*i+0] = Random(); + minimap.sample_offsets[2*i+1] = Random(); + } + + for(i = 0; i < 1000; ++i) + { + if(MiniMapEvaluateSampleOffsets(&j, &k, &val)) + { + sx = minimap.sample_offsets[2*j+0]; + sy = minimap.sample_offsets[2*j+1]; + minimap.sample_offsets[2*j+0] = rx = Random(); + minimap.sample_offsets[2*j+1] = ry = Random(); + if(!MiniMapEvaluateSampleOffsets(&jj, &kk, &valj)) + valj = -1; + minimap.sample_offsets[2*j+0] = sx; + minimap.sample_offsets[2*j+1] = sy; + + sx = minimap.sample_offsets[2*k+0]; + sy = minimap.sample_offsets[2*k+1]; + minimap.sample_offsets[2*k+0] = rx; + minimap.sample_offsets[2*k+1] = ry; + if(!MiniMapEvaluateSampleOffsets(&jj, &kk, &valk)) + valk = -1; + minimap.sample_offsets[2*k+0] = sx; + minimap.sample_offsets[2*k+1] = sy; + + if(valj > valk) + { + if(valj > val) + { + /* valj is the greatest */ + minimap.sample_offsets[2*j+0] = rx; + minimap.sample_offsets[2*j+1] = ry; + i = -1; + } + else + { + /* valj is the greater and it is useless - forget it */ + } + } + else + { + if(valk > val) + { + /* valk is the greatest */ + minimap.sample_offsets[2*k+0] = rx; + minimap.sample_offsets[2*k+1] = ry; + i = -1; + } + else + { + /* valk is the greater and it is useless - forget it */ + } + } + } + else + break; + } +} + +void MergeRelativePath(char *out, const char *absolute, const char *relative) +{ + const char *endpos = absolute + strlen(absolute); + while(endpos != absolute && (endpos[-1] == '/' || endpos[-1] == '\\')) + --endpos; + while(relative[0] == '.' && relative[1] == '.' && (relative[2] == '/' || relative[2] == '\\')) + { + relative += 3; + while(endpos != absolute) + { + --endpos; + if(*endpos == '/' || *endpos == '\\') + break; + } + while(endpos != absolute && (endpos[-1] == '/' || endpos[-1] == '\\')) + --endpos; + } + memcpy(out, absolute, endpos - absolute); + out[endpos - absolute] = '/'; + strcpy(out + (endpos - absolute + 1), relative); +} + +int MiniMapBSPMain( int argc, char **argv ) +{ + char minimapFilename[1024]; + char basename[1024]; + char path[1024]; + char relativeMinimapFilename[1024]; + float minimapSharpen; + float border; + byte *data4b, *p; + float *q; + int x, y; + int i; + miniMapMode_t mode; + vec3_t mins, maxs; + qboolean keepaspect; + + /* arg checking */ + if( argc < 2 ) + { + Sys_Printf( "Usage: q3map [-v] -minimap [-size n] [-sharpen f] [-samples n | -random n] [-o filename.tga] [-minmax Xmin Ymin Zmin Xmax Ymax Zmax] \n" ); + return 0; + } + + /* load the BSP first */ + strcpy( source, ExpandArg( argv[ argc - 1 ] ) ); + StripExtension( source ); + DefaultExtension( source, ".bsp" ); + Sys_Printf( "Loading %s\n", source ); + BeginMapShaderFile( source ); + LoadShaderInfo(); + LoadBSPFile( source ); + + minimap.model = &bspModels[0]; + VectorCopy(minimap.model->mins, mins); + VectorCopy(minimap.model->maxs, maxs); + + *minimapFilename = 0; + minimapSharpen = game->miniMapSharpen; + minimap.width = minimap.height = game->miniMapSize; + border = game->miniMapBorder; + keepaspect = game->miniMapKeepAspect; + mode = game->miniMapMode; + + minimap.samples = 1; + minimap.sample_offsets = NULL; + minimap.boost = 1.0; + + /* process arguments */ + for( i = 1; i < (argc - 1); i++ ) + { + if( !strcmp( argv[ i ], "-size" ) ) + { + minimap.width = minimap.height = atoi(argv[i + 1]); + i++; + Sys_Printf( "Image size set to %i\n", minimap.width ); + } + else if( !strcmp( argv[ i ], "-sharpen" ) ) + { + minimapSharpen = atof(argv[i + 1]); + i++; + Sys_Printf( "Sharpening coefficient set to %f\n", minimapSharpen ); + } + else if( !strcmp( argv[ i ], "-samples" ) ) + { + minimap.samples = atoi(argv[i + 1]); + i++; + Sys_Printf( "Samples set to %i\n", minimap.samples ); + if(minimap.sample_offsets) + free(minimap.sample_offsets); + minimap.sample_offsets = malloc(2 * sizeof(*minimap.sample_offsets) * minimap.samples); + MiniMapMakeSampleOffsets(); + } + else if( !strcmp( argv[ i ], "-random" ) ) + { + minimap.samples = atoi(argv[i + 1]); + i++; + Sys_Printf( "Random samples set to %i\n", minimap.samples ); + if(minimap.sample_offsets) + free(minimap.sample_offsets); + minimap.sample_offsets = NULL; + } + else if( !strcmp( argv[ i ], "-border" ) ) + { + border = atof(argv[i + 1]); + i++; + Sys_Printf( "Border set to %f\n", border ); + } + else if( !strcmp( argv[ i ], "-keepaspect" ) ) + { + keepaspect = qtrue; + Sys_Printf( "Keeping aspect ratio by letterboxing\n", border ); + } + else if( !strcmp( argv[ i ], "-nokeepaspect" ) ) + { + keepaspect = qfalse; + Sys_Printf( "Not keeping aspect ratio\n", border ); + } + else if( !strcmp( argv[ i ], "-o" ) ) + { + strcpy(minimapFilename, argv[i + 1]); + i++; + Sys_Printf( "Output file name set to %s\n", minimapFilename ); + } + else if( !strcmp( argv[ i ], "-minmax" ) && i < (argc - 7) ) + { + mins[0] = atof(argv[i + 1]); + mins[1] = atof(argv[i + 2]); + mins[2] = atof(argv[i + 3]); + maxs[0] = atof(argv[i + 4]); + maxs[1] = atof(argv[i + 5]); + maxs[2] = atof(argv[i + 6]); + i += 6; + Sys_Printf( "Map mins/maxs overridden\n" ); + } + else if( !strcmp( argv[ i ], "-gray" ) ) + { + mode = MINIMAP_MODE_GRAY; + Sys_Printf( "Writing as white-on-black image\n" ); + } + else if( !strcmp( argv[ i ], "-black" ) ) + { + mode = MINIMAP_MODE_BLACK; + Sys_Printf( "Writing as black alpha image\n" ); + } + else if( !strcmp( argv[ i ], "-white" ) ) + { + mode = MINIMAP_MODE_WHITE; + Sys_Printf( "Writing as white alpha image\n" ); + } + else if( !strcmp( argv[ i ], "-boost" ) ) + { + minimap.boost = atof(argv[i + 1]); + i++; + Sys_Printf( "Contrast boost set to %f\n", minimap.boost ); + } + } + + MiniMapMakeMinsMaxs(mins, maxs, border, keepaspect); + + if(!*minimapFilename) + { + ExtractFileBase(source, basename); + ExtractFilePath(source, path); + sprintf(relativeMinimapFilename, game->miniMapNameFormat, basename); + MergeRelativePath(minimapFilename, path, relativeMinimapFilename); + Sys_Printf("Output file name automatically set to %s\n", minimapFilename); + } + ExtractFilePath(minimapFilename, path); + Q_mkdir(path); + + if(minimapSharpen >= 0) + { + minimap.sharpen_centermult = 8 * minimapSharpen + 1; + minimap.sharpen_boxmult = -minimapSharpen; + } + + minimap.data1f = safe_malloc(minimap.width * minimap.height * sizeof(*minimap.data1f)); + data4b = safe_malloc(minimap.width * minimap.height * 4); + if(minimapSharpen >= 0) + minimap.sharpendata1f = safe_malloc(minimap.width * minimap.height * sizeof(*minimap.data1f)); + + MiniMapSetupBrushes(); + + if(minimap.samples <= 1) + { + Sys_Printf( "\n--- MiniMapNoSupersampling (%d) ---\n", minimap.height ); + RunThreadsOnIndividual(minimap.height, qtrue, MiniMapNoSupersampling); + } + else + { + if(minimap.sample_offsets) + { + Sys_Printf( "\n--- MiniMapSupersampled (%d) ---\n", minimap.height ); + RunThreadsOnIndividual(minimap.height, qtrue, MiniMapSupersampled); + } + else + { + Sys_Printf( "\n--- MiniMapRandomlySupersampled (%d) ---\n", minimap.height ); + RunThreadsOnIndividual(minimap.height, qtrue, MiniMapRandomlySupersampled); + } + } + + if(minimap.boost != 1.0) + { + Sys_Printf( "\n--- MiniMapContrastBoost (%d) ---\n", minimap.height ); + RunThreadsOnIndividual(minimap.height, qtrue, MiniMapContrastBoost); + } + + if(minimap.sharpendata1f) + { + Sys_Printf( "\n--- MiniMapSharpen (%d) ---\n", minimap.height ); + RunThreadsOnIndividual(minimap.height, qtrue, MiniMapSharpen); + q = minimap.sharpendata1f; + } + else + { + q = minimap.data1f; + } + + Sys_Printf( "\nConverting..."); + + switch(mode) + { + case MINIMAP_MODE_GRAY: + p = data4b; + for(y = 0; y < minimap.height; ++y) + for(x = 0; x < minimap.width; ++x) + { + byte b; + float v = *q++; + if(v < 0) v = 0; + if(v > 255.0/256.0) v = 255.0/256.0; + b = v * 256; + *p++ = b; + } + Sys_Printf( " writing to %s...", minimapFilename ); + WriteTGAGray(minimapFilename, data4b, minimap.width, minimap.height); + break; + case MINIMAP_MODE_BLACK: + p = data4b; + for(y = 0; y < minimap.height; ++y) + for(x = 0; x < minimap.width; ++x) + { + byte b; + float v = *q++; + if(v < 0) v = 0; + if(v > 255.0/256.0) v = 255.0/256.0; + b = v * 256; + *p++ = 0; + *p++ = 0; + *p++ = 0; + *p++ = b; + } + Sys_Printf( " writing to %s...", minimapFilename ); + WriteTGA(minimapFilename, data4b, minimap.width, minimap.height); + break; + case MINIMAP_MODE_WHITE: + p = data4b; + for(y = 0; y < minimap.height; ++y) + for(x = 0; x < minimap.width; ++x) + { + byte b; + float v = *q++; + if(v < 0) v = 0; + if(v > 255.0/256.0) v = 255.0/256.0; + b = v * 256; + *p++ = 255; + *p++ = 255; + *p++ = 255; + *p++ = b; + } + Sys_Printf( " writing to %s...", minimapFilename ); + WriteTGA(minimapFilename, data4b, minimap.width, minimap.height); + break; + } + + Sys_Printf( " done.\n" ); + + /* return to sender */ + return 0; +} + + + + + +/* +MD4BlockChecksum() +calculates an md4 checksum for a block of data +*/ + +static int MD4BlockChecksum( void *buffer, int length ) +{ + return Com_BlockChecksum(buffer, length); } /* @@ -252,8 +989,8 @@ int AnalyzeBSP( int argc, char **argv ) lump = (byte*) header + offset; lumpInt = LittleLong( (int) *((int*) lump) ); lumpFloat = LittleFloat( (float) *((float*) lump) ); - memcpy( lumpString, (char*) lump, (length < 1024 ? length : 1024) ); - lumpString[ 1024 ] = '\0'; + memcpy( lumpString, (char*) lump, (length < sizeof(lumpString) ? length : sizeof(lumpString)-1) ); + lumpString[ sizeof(lumpString)-1 ] = '\0'; /* print basic lump info */ Sys_Printf( "Lump: %d\n", i ); @@ -368,6 +1105,74 @@ int BSPInfo( int count, char **fileNames ) } +static void ExtrapolateTexcoords(const float *axyz, const float *ast, const float *bxyz, const float *bst, const float *cxyz, const float *cst, const float *axyz_new, float *ast_out, const float *bxyz_new, float *bst_out, const float *cxyz_new, float *cst_out) +{ + vec4_t scoeffs, tcoeffs; + float md; + m4x4_t solvematrix; + + vec3_t norm; + vec3_t dab, dac; + VectorSubtract(bxyz, axyz, dab); + VectorSubtract(cxyz, axyz, dac); + CrossProduct(dab, dac, norm); + + // assume: + // s = f(x, y, z) + // s(v + norm) = s(v) when n ortho xyz + + // s(v) = DotProduct(v, scoeffs) + scoeffs[3] + + // solve: + // scoeffs * (axyz, 1) == ast[0] + // scoeffs * (bxyz, 1) == bst[0] + // scoeffs * (cxyz, 1) == cst[0] + // scoeffs * (norm, 0) == 0 + // scoeffs * [axyz, 1 | bxyz, 1 | cxyz, 1 | norm, 0] = [ast[0], bst[0], cst[0], 0] + solvematrix[0] = axyz[0]; + solvematrix[4] = axyz[1]; + solvematrix[8] = axyz[2]; + solvematrix[12] = 1; + solvematrix[1] = bxyz[0]; + solvematrix[5] = bxyz[1]; + solvematrix[9] = bxyz[2]; + solvematrix[13] = 1; + solvematrix[2] = cxyz[0]; + solvematrix[6] = cxyz[1]; + solvematrix[10] = cxyz[2]; + solvematrix[14] = 1; + solvematrix[3] = norm[0]; + solvematrix[7] = norm[1]; + solvematrix[11] = norm[2]; + solvematrix[15] = 0; + + md = m4_det(solvematrix); + if(md*md < 1e-10) + { + Sys_Printf("Cannot invert some matrix, some texcoords aren't extrapolated!"); + return; + } + + m4x4_invert(solvematrix); + + scoeffs[0] = ast[0]; + scoeffs[1] = bst[0]; + scoeffs[2] = cst[0]; + scoeffs[3] = 0; + m4x4_transform_vec4(solvematrix, scoeffs); + tcoeffs[0] = ast[1]; + tcoeffs[1] = bst[1]; + tcoeffs[2] = cst[1]; + tcoeffs[3] = 0; + m4x4_transform_vec4(solvematrix, tcoeffs); + + ast_out[0] = scoeffs[0] * axyz_new[0] + scoeffs[1] * axyz_new[1] + scoeffs[2] * axyz_new[2] + scoeffs[3]; + ast_out[1] = tcoeffs[0] * axyz_new[0] + tcoeffs[1] * axyz_new[1] + tcoeffs[2] * axyz_new[2] + tcoeffs[3]; + bst_out[0] = scoeffs[0] * bxyz_new[0] + scoeffs[1] * bxyz_new[1] + scoeffs[2] * bxyz_new[2] + scoeffs[3]; + bst_out[1] = tcoeffs[0] * bxyz_new[0] + tcoeffs[1] * bxyz_new[1] + tcoeffs[2] * bxyz_new[2] + tcoeffs[3]; + cst_out[0] = scoeffs[0] * cxyz_new[0] + scoeffs[1] * cxyz_new[1] + scoeffs[2] * cxyz_new[2] + scoeffs[3]; + cst_out[1] = tcoeffs[0] * cxyz_new[0] + tcoeffs[1] * cxyz_new[1] + tcoeffs[2] * cxyz_new[2] + tcoeffs[3]; +} /* ScaleBSPMain() @@ -376,24 +1181,53 @@ amaze and confuse your enemies with wierd scaled maps! int ScaleBSPMain( int argc, char **argv ) { - int i; - float f, scale; + int i, j; + float f, a; + vec3_t scale; vec3_t vec; char str[ 1024 ]; + int uniform, axis; + qboolean texscale; + float *old_xyzst = NULL; + float spawn_ref = 0; /* arg checking */ - if( argc < 2 ) + if( argc < 3 ) { - Sys_Printf( "Usage: q3map -scale [-v] \n" ); + Sys_Printf( "Usage: q3map [-v] -scale [-tex] [-spawn_ref ] \n" ); return 0; } + texscale = qfalse; + for(i = 1; i < argc-2; ++i) + { + if(!strcmp(argv[i], "-tex")) + { + texscale = qtrue; + } + else if(!strcmp(argv[i], "-spawn_ref")) + { + spawn_ref = atof(argv[i+1]); + ++i; + } + else + break; + } + /* get scale */ - scale = atof( argv[ argc - 2 ] ); - if( scale == 0.0f ) + // if(argc-2 >= i) // always true + scale[2] = scale[1] = scale[0] = atof( argv[ argc - 2 ] ); + if(argc-3 >= i) + scale[1] = scale[0] = atof( argv[ argc - 3 ] ); + if(argc-4 >= i) + scale[0] = atof( argv[ argc - 4 ] ); + + uniform = ((scale[0] == scale[1]) && (scale[1] == scale[2])); + + if( scale[0] == 0.0f || scale[1] == 0.0f || scale[2] == 0.0f ) { - Sys_Printf( "Usage: q3map -scale [-v] \n" ); + Sys_Printf( "Usage: q3map [-v] -scale [-tex] [-spawn_ref ] \n" ); Sys_Printf( "Non-zero scale value required.\n" ); return 0; } @@ -417,59 +1251,172 @@ int ScaleBSPMain( int argc, char **argv ) { /* scale origin */ GetVectorForKey( &entities[ i ], "origin", vec ); - if( (vec[ 0 ] + vec[ 1 ] + vec[ 2 ]) ) + if( (vec[ 0 ] || vec[ 1 ] || vec[ 2 ]) ) { - VectorScale( vec, scale, vec ); + if(!strncmp(ValueForKey(&entities[i], "classname"), "info_player_", 12)) + vec[2] += spawn_ref; + vec[0] *= scale[0]; + vec[1] *= scale[1]; + vec[2] *= scale[2]; + if(!strncmp(ValueForKey(&entities[i], "classname"), "info_player_", 12)) + vec[2] -= spawn_ref; sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] ); SetKeyValue( &entities[ i ], "origin", str ); } + + a = FloatForKey( &entities[ i ], "angle" ); + if(a == -1 || a == -2) // z scale + axis = 2; + else if(fabs(sin(DEG2RAD(a))) < 0.707) + axis = 0; + else + axis = 1; /* scale door lip */ f = FloatForKey( &entities[ i ], "lip" ); if( f ) { - f *= scale; + f *= scale[axis]; sprintf( str, "%f", f ); SetKeyValue( &entities[ i ], "lip", str ); } + + /* scale plat height */ + f = FloatForKey( &entities[ i ], "height" ); + if( f ) + { + f *= scale[2]; + sprintf( str, "%f", f ); + SetKeyValue( &entities[ i ], "height", str ); + } + + // TODO maybe allow a definition file for entities to specify which values are scaled how? } /* scale models */ for( i = 0; i < numBSPModels; i++ ) { - VectorScale( bspModels[ i ].mins, scale, bspModels[ i ].mins ); - VectorScale( bspModels[ i ].maxs, scale, bspModels[ i ].maxs ); + bspModels[ i ].mins[0] *= scale[0]; + bspModels[ i ].mins[1] *= scale[1]; + bspModels[ i ].mins[2] *= scale[2]; + bspModels[ i ].maxs[0] *= scale[0]; + bspModels[ i ].maxs[1] *= scale[1]; + bspModels[ i ].maxs[2] *= scale[2]; } /* scale nodes */ for( i = 0; i < numBSPNodes; i++ ) { - VectorScale( bspNodes[ i ].mins, scale, bspNodes[ i ].mins ); - VectorScale( bspNodes[ i ].maxs, scale, bspNodes[ i ].maxs ); + bspNodes[ i ].mins[0] *= scale[0]; + bspNodes[ i ].mins[1] *= scale[1]; + bspNodes[ i ].mins[2] *= scale[2]; + bspNodes[ i ].maxs[0] *= scale[0]; + bspNodes[ i ].maxs[1] *= scale[1]; + bspNodes[ i ].maxs[2] *= scale[2]; } /* scale leafs */ for( i = 0; i < numBSPLeafs; i++ ) { - VectorScale( bspLeafs[ i ].mins, scale, bspLeafs[ i ].mins ); - VectorScale( bspLeafs[ i ].maxs, scale, bspLeafs[ i ].maxs ); + bspLeafs[ i ].mins[0] *= scale[0]; + bspLeafs[ i ].mins[1] *= scale[1]; + bspLeafs[ i ].mins[2] *= scale[2]; + bspLeafs[ i ].maxs[0] *= scale[0]; + bspLeafs[ i ].maxs[1] *= scale[1]; + bspLeafs[ i ].maxs[2] *= scale[2]; } + if(texscale) + { + Sys_Printf("Using texture unlocking (and probably breaking texture alignment a lot)\n"); + old_xyzst = safe_malloc(sizeof(*old_xyzst) * numBSPDrawVerts * 5); + for(i = 0; i < numBSPDrawVerts; i++) + { + old_xyzst[5*i+0] = bspDrawVerts[i].xyz[0]; + old_xyzst[5*i+1] = bspDrawVerts[i].xyz[1]; + old_xyzst[5*i+2] = bspDrawVerts[i].xyz[2]; + old_xyzst[5*i+3] = bspDrawVerts[i].st[0]; + old_xyzst[5*i+4] = bspDrawVerts[i].st[1]; + } + } + /* scale drawverts */ for( i = 0; i < numBSPDrawVerts; i++ ) - VectorScale( bspDrawVerts[ i ].xyz, scale, bspDrawVerts[ i ].xyz ); + { + bspDrawVerts[i].xyz[0] *= scale[0]; + bspDrawVerts[i].xyz[1] *= scale[1]; + bspDrawVerts[i].xyz[2] *= scale[2]; + bspDrawVerts[i].normal[0] /= scale[0]; + bspDrawVerts[i].normal[1] /= scale[1]; + bspDrawVerts[i].normal[2] /= scale[2]; + VectorNormalize(bspDrawVerts[i].normal, bspDrawVerts[i].normal); + } + + if(texscale) + { + for(i = 0; i < numBSPDrawSurfaces; i++) + { + switch(bspDrawSurfaces[i].surfaceType) + { + case SURFACE_FACE: + case SURFACE_META: + if(bspDrawSurfaces[i].numIndexes % 3) + Error("Not a triangulation!"); + for(j = bspDrawSurfaces[i].firstIndex; j < bspDrawSurfaces[i].firstIndex + bspDrawSurfaces[i].numIndexes; j += 3) + { + int ia = bspDrawIndexes[j] + bspDrawSurfaces[i].firstVert, ib = bspDrawIndexes[j+1] + bspDrawSurfaces[i].firstVert, ic = bspDrawIndexes[j+2] + bspDrawSurfaces[i].firstVert; + bspDrawVert_t *a = &bspDrawVerts[ia], *b = &bspDrawVerts[ib], *c = &bspDrawVerts[ic]; + float *oa = &old_xyzst[ia*5], *ob = &old_xyzst[ib*5], *oc = &old_xyzst[ic*5]; + // extrapolate: + // a->xyz -> oa + // b->xyz -> ob + // c->xyz -> oc + ExtrapolateTexcoords( + &oa[0], &oa[3], + &ob[0], &ob[3], + &oc[0], &oc[3], + a->xyz, a->st, + b->xyz, b->st, + c->xyz, c->st); + } + break; + } + } + } /* scale planes */ - for( i = 0; i < numBSPPlanes; i++ ) - bspPlanes[ i ].dist *= scale; + if(uniform) + { + for( i = 0; i < numBSPPlanes; i++ ) + { + bspPlanes[ i ].dist *= scale[0]; + } + } + else + { + for( i = 0; i < numBSPPlanes; i++ ) + { + bspPlanes[ i ].normal[0] /= scale[0]; + bspPlanes[ i ].normal[1] /= scale[1]; + bspPlanes[ i ].normal[2] /= scale[2]; + f = 1/VectorLength(bspPlanes[i].normal); + VectorScale(bspPlanes[i].normal, f, bspPlanes[i].normal); + bspPlanes[ i ].dist *= f; + } + } /* scale gridsize */ GetVectorForKey( &entities[ 0 ], "gridsize", vec ); if( (vec[ 0 ] + vec[ 1 ] + vec[ 2 ]) == 0.0f ) VectorCopy( gridSize, vec ); - VectorScale( vec, scale, vec ); + vec[0] *= scale[0]; + vec[1] *= scale[1]; + vec[2] *= scale[2]; sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] ); SetKeyValue( &entities[ 0 ], "gridsize", str ); + + /* inject command line parameters */ + InjectCommandLine(argv, 0, argc - 1); /* write the bsp */ UnparseEntities(); @@ -483,6 +1430,101 @@ int ScaleBSPMain( int argc, char **argv ) } +/* +PseudoCompileBSP() +a stripped down ProcessModels +*/ +void PseudoCompileBSP(qboolean need_tree) +{ + int models; + char modelValue[10]; + entity_t *entity; + face_t *faces; + tree_t *tree; + node_t *node; + brush_t *brush; + side_t *side; + int i; + + SetDrawSurfacesBuffer(); + mapDrawSurfs = safe_malloc( sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS ); + memset( mapDrawSurfs, 0, sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS ); + numMapDrawSurfs = 0; + + BeginBSPFile(); + models = 1; + for( mapEntityNum = 0; mapEntityNum < numEntities; mapEntityNum++ ) + { + /* get entity */ + entity = &entities[ mapEntityNum ]; + if( entity->brushes == NULL && entity->patches == NULL ) + continue; + + if(mapEntityNum != 0) + { + sprintf( modelValue, "*%d", models++); + SetKeyValue(entity, "model", modelValue); + } + + /* process the model */ + Sys_FPrintf( SYS_VRB, "############### model %i ###############\n", numBSPModels ); + BeginModel(); + + entity->firstDrawSurf = numMapDrawSurfs; + + ClearMetaTriangles(); + PatchMapDrawSurfs(entity); + + if(mapEntityNum == 0 && need_tree) + { + faces = MakeStructuralBSPFaceList(entities[0].brushes); + tree = FaceBSP(faces); + node = tree->headnode; + } + else + { + node = AllocNode(); + node->planenum = PLANENUM_LEAF; + tree = AllocTree(); + tree->headnode = node; + } + + /* a minimized ClipSidesIntoTree */ + for( brush = entity->brushes; brush; brush = brush->next ) + { + /* walk the brush sides */ + for( i = 0; i < brush->numsides; i++ ) + { + /* get side */ + side = &brush->sides[ i ]; + if( side->winding == NULL ) + continue; + /* shader? */ + if( side->shaderInfo == NULL ) + continue; + /* save this winding as a visible surface */ + DrawSurfaceForSide(entity, brush, side, side->winding); + } + } + + if(meta) + { + ClassifyEntitySurfaces(entity); + MakeEntityDecals(entity); + MakeEntityMetaTriangles(entity); + SmoothMetaTriangles(); + MergeMetaTriangles(); + } + FilterDrawsurfsIntoTree(entity, tree); + + FilterStructuralBrushesIntoTree(entity, tree); + FilterDetailBrushesIntoTree(entity, tree); + + EmitBrushes(entity->brushes, &entity->firstBrush, &entity->numBrushes ); + EndModel(entity, node); + } + EndBSPFile(qfalse); +} /* ConvertBSPMain() @@ -494,16 +1536,21 @@ int ConvertBSPMain( int argc, char **argv ) int i; int (*convertFunc)( char * ); game_t *convertGame; + char ext[1024]; + qboolean map_allowed, force_bsp, force_map; /* set default */ convertFunc = ConvertBSPToASE; convertGame = NULL; + map_allowed = qfalse; + force_bsp = qfalse; + force_map = qfalse; /* arg checking */ if( argc < 1 ) { - Sys_Printf( "Usage: q3map -scale [-v] \n" ); + Sys_Printf( "Usage: q3map -convert -format [-shadesasbitmap|-lightmapsastexcoord|-deluxemapsastexcoord] [-readbsp|-readmap [-meta|-patchmeta]] \n" ); return 0; } @@ -515,34 +1562,94 @@ int ConvertBSPMain( int argc, char **argv ) { i++; if( !Q_stricmp( argv[ i ], "ase" ) ) + { convertFunc = ConvertBSPToASE; + map_allowed = qfalse; + } + else if( !Q_stricmp( argv[ i ], "obj" ) ) + { + convertFunc = ConvertBSPToOBJ; + map_allowed = qfalse; + } + else if( !Q_stricmp( argv[ i ], "map_bp" ) ) + { + convertFunc = ConvertBSPToMap_BP; + map_allowed = qtrue; + } else if( !Q_stricmp( argv[ i ], "map" ) ) + { convertFunc = ConvertBSPToMap; + map_allowed = qtrue; + } else { convertGame = GetGame( argv[ i ] ); + map_allowed = qfalse; if( convertGame == NULL ) Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] ); } } + else if( !strcmp( argv[ i ], "-ne" ) ) + { + normalEpsilon = atof( argv[ i + 1 ] ); + i++; + Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon ); + } + else if( !strcmp( argv[ i ], "-de" ) ) + { + distanceEpsilon = atof( argv[ i + 1 ] ); + i++; + Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon ); + } + else if( !strcmp( argv[ i ], "-shadersasbitmap" ) ) + shadersAsBitmap = qtrue; + else if( !strcmp( argv[ i ], "-lightmapsastexcoord" ) ) + lightmapsAsTexcoord = qtrue; + else if( !strcmp( argv[ i ], "-deluxemapsastexcoord" ) ) + { + lightmapsAsTexcoord = qtrue; + deluxemap = qtrue; + } + else if( !strcmp( argv[ i ], "-readbsp" ) ) + force_bsp = qtrue; + else if( !strcmp( argv[ i ], "-readmap" ) ) + force_map = qtrue; + else if( !strcmp( argv[ i ], "-meta" ) ) + meta = qtrue; + else if( !strcmp( argv[ i ], "-patchmeta" ) ) + { + meta = qtrue; + patchMeta = qtrue; + } } - - /* clean up map name */ - strcpy( source, ExpandArg( argv[ i ] ) ); - StripExtension( source ); - DefaultExtension( source, ".bsp" ); - + LoadShaderInfo(); - Sys_Printf( "Loading %s\n", source ); - - /* ydnar: load surface file */ - //% LoadSurfaceExtraFile( source ); - - LoadBSPFile( source ); - - /* parse bsp entities */ - ParseEntities(); + /* clean up map name */ + strcpy(source, ExpandArg(argv[i])); + ExtractFileExtension(source, ext); + + if(!map_allowed && !force_map) + force_bsp = qtrue; + + if(force_map || (!force_bsp && !Q_stricmp(ext, "map") && map_allowed)) + { + if(!map_allowed) + Sys_Printf("WARNING: the requested conversion should not be done from .map files. Compile a .bsp first.\n"); + StripExtension(source); + DefaultExtension(source, ".map"); + Sys_Printf("Loading %s\n", source); + LoadMapFile(source, qfalse, convertGame == NULL); + PseudoCompileBSP(convertGame != NULL); + } + else + { + StripExtension(source); + DefaultExtension(source, ".bsp"); + Sys_Printf("Loading %s\n", source); + LoadBSPFile(source); + ParseEntities(); + } /* bsp format convert? */ if( convertGame != NULL ) @@ -588,7 +1695,7 @@ int main( int argc, char **argv ) /* set exit call */ atexit( ExitQ3Map ); - + /* read general options first */ for( i = 1; i < argc; i++ ) { @@ -604,8 +1711,11 @@ int main( int argc, char **argv ) /* verbose */ else if( !strcmp( argv[ i ], "-v" ) ) { - verbose = qtrue; - argv[ i ] = NULL; + if(!verbose) + { + verbose = qtrue; + argv[ i ] = NULL; + } } /* force */ @@ -635,7 +1745,7 @@ int main( int argc, char **argv ) argv[ i ] = NULL; } } - + /* init model library */ PicoInit(); PicoSetMallocFunc( safe_malloc ); @@ -659,11 +1769,15 @@ int main( int argc, char **argv ) Sys_Printf( "Q3Map - v1.0r (c) 1999 Id Software Inc.\n" ); Sys_Printf( "Q3Map (ydnar) - v" Q3MAP_VERSION "\n" ); - Sys_Printf( "GtkRadiant - v" RADIANT_VERSION " " __DATE__ " " __TIME__ "\n" ); + Sys_Printf( "NetRadiant - v" RADIANT_VERSION " " __DATE__ " " __TIME__ "\n" ); Sys_Printf( "%s\n", Q3MAP_MOTD ); /* ydnar: new path initialization */ InitPaths( &argc, argv ); + + /* set game options */ + if (!patchSubdivisions) + patchSubdivisions = game->patchSubdivisions; /* check if we have enough options left to attempt something */ if( argc < 2 ) @@ -713,6 +1827,10 @@ int main( int argc, char **argv ) else if( !strcmp( argv[ 1 ], "-convert" ) ) r = ConvertBSPMain( argc - 1, argv + 1 ); + /* div0: minimap */ + else if( !strcmp( argv[ 1 ], "-minimap" ) ) + r = MiniMapBSPMain(argc - 1, argv + 1); + /* ydnar: otherwise create a bsp */ else r = BSPMain( argc, argv ); diff --git a/tools/quake3/q3map2/map.c b/tools/quake3/q3map2/map.c index 4ec5a381..95bb3d1f 100644 --- a/tools/quake3/q3map2/map.c +++ b/tools/quake3/q3map2/map.c @@ -44,7 +44,7 @@ several games based on the Quake III Arena engine, in the form of "Q3Map2." #define USE_HASHING #define PLANE_HASHES 8192 -plane_t *planehash[ PLANE_HASHES ]; +int planehash[ PLANE_HASHES ]; int c_boxbevels; int c_edgebevels; @@ -97,7 +97,7 @@ void AddPlaneToHash( plane_t *p ) hash = (PLANE_HASHES - 1) & (int) fabs( p->dist ); p->hash_chain = planehash[hash]; - planehash[hash] = p; + planehash[hash] = p - mapplanes + 1; } /* @@ -116,8 +116,7 @@ int CreateNewFloatPlane (vec3_t normal, vec_t dist) } // create a new plane - if (nummapplanes+2 > MAX_MAP_PLANES) - Error ("MAX_MAP_PLANES"); + AUTOEXPAND_BY_REALLOC(mapplanes, nummapplanes+1, allocatedmapplanes, 1024); p = &mapplanes[nummapplanes]; VectorCopy (normal, p->normal); @@ -248,7 +247,7 @@ SnapPlane() snaps a plane to normal/distance epsilons */ -void SnapPlane( vec3_t normal, vec_t *dist ) +void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center ) { // SnapPlane disabled by LordHavoc because it often messes up collision // brushes made from triangles of embedded models, and it has little effect @@ -322,22 +321,25 @@ void SnapPlaneImproved(vec3_t normal, vec_t *dist, int numPoints, const vec3_t * } + /* FindFloatPlane() ydnar: changed to allow a number of test points to be supplied that must be within an epsilon distance of the plane */ -int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ) +int FindFloatPlane( vec3_t innormal, vec_t dist, int numPoints, vec3_t *points ) // NOTE: this has a side effect on the normal. Good or bad? #ifdef USE_HASHING { int i, j, hash, h; + int pidx; plane_t *p; vec_t d; - - + vec3_t normal; + + VectorCopy(innormal, normal); #if Q3MAP2_EXPERIMENTAL_SNAP_PLANE_FIX SnapPlaneImproved(normal, &dist, numPoints, (const vec3_t *) points); #else @@ -350,8 +352,10 @@ int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ) for( i = -1; i <= 1; i++ ) { h = (hash + i) & (PLANE_HASHES - 1); - for( p = planehash[ h ]; p != NULL; p = p->hash_chain ) + for( pidx = planehash[ h ] - 1; pidx != -1; pidx = mapplanes[pidx].hash_chain - 1 ) { + p = &mapplanes[pidx]; + /* do standard plane compare */ if( !PlaneEqual( p, normal, dist ) ) continue; @@ -367,7 +371,7 @@ int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ) // very small when world coordinates extend to 2^16. Making the // dot product here in 64 bit land will not really help the situation // because the error will already be carried in dist. - d = DotProduct( points[ j ], normal ) - dist; + d = DotProduct( points[ j ], p->normal ) - p->dist; d = fabs(d); if (d != 0.0 && d >= distanceEpsilon) break; // Point is too far from plane. @@ -388,15 +392,32 @@ int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ) { int i; plane_t *p; + vec3_t normal; + VectorCopy(innormal, normal); #if Q3MAP2_EXPERIMENTAL_SNAP_PLANE_FIX SnapPlaneImproved(normal, &dist, numPoints, (const vec3_t *) points); #else - SnapPlane( normal, &dist ); + SnapPlane( normal, &dist ); #endif for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ ) { - if( PlaneEqual( p, normal, dist ) ) + if( !PlaneEqual( p, normal, dist ) ) + continue; + + /* ydnar: uncomment the following line for old-style plane finding */ + //% return i; + + /* ydnar: test supplied points against this plane */ + for( j = 0; j < numPoints; j++ ) + { + d = DotProduct( points[ j ], p->normal ) - p->dist; + if( fabs( d ) > distanceEpsilon ) + break; + } + + /* found a matching plane */ + if( j >= numPoints ) return i; // TODO: Note that the non-USE_HASHING code does not compute epsilons // for the provided points. It should do that. I think this code @@ -487,6 +508,9 @@ void SetBrushContents( brush_t *b ) continue; if( s->contentFlags != contentFlags || s->compileFlags != compileFlags ) mixed = qtrue; + + contentFlags |= s->contentFlags; + compileFlags |= s->compileFlags; } /* ydnar: getting rid of this stupid warning */ @@ -739,7 +763,23 @@ produces a final brush based on the buildBrush->sides array and links it to the current entity */ -brush_t *FinishBrush( void ) +static void MergeOrigin(entity_t *ent, vec3_t origin) +{ + vec3_t adjustment; + char string[128]; + + /* we have not parsed the brush completely yet... */ + GetVectorForKey( ent, "origin", ent->origin ); + + VectorMA(origin, -1, ent->originbrush_origin, adjustment); + VectorAdd(adjustment, ent->origin, ent->origin); + VectorCopy(origin, ent->originbrush_origin); + + sprintf(string, "%f %f %f", ent->origin[0], ent->origin[1], ent->origin[2]); + SetKeyValue(ent, "origin", string); +} + +brush_t *FinishBrush( qboolean noCollapseGroups ) { brush_t *b; @@ -752,9 +792,11 @@ brush_t *FinishBrush( void ) after the entire entity is parsed, the planenums and texinfos will be adjusted for the origin brush */ if( buildBrush->compileFlags & C_ORIGIN ) { - char string[ 32 ]; vec3_t origin; + Sys_Printf( "Entity %i, Brush %i: origin brush detected\n", + mapEnt->mapEntityNum, entitySourceBrushes ); + if( numEntities == 1 ) { Sys_Printf( "Entity %i, Brush %i: origin brushes not allowed in world\n", @@ -765,10 +807,7 @@ brush_t *FinishBrush( void ) VectorAdd (buildBrush->mins, buildBrush->maxs, origin); VectorScale (origin, 0.5, origin); - sprintf( string, "%i %i %i", (int) origin[ 0 ], (int) origin[ 1 ], (int) origin[ 2 ] ); - SetKeyValue( &entities[ numEntities - 1 ], "origin", string); - - VectorCopy( origin, entities[ numEntities - 1 ].origin); + MergeOrigin(&entities[ numEntities - 1 ], origin); /* don't keep this brush */ return NULL; @@ -785,7 +824,8 @@ brush_t *FinishBrush( void ) } /* add bevel planes */ - AddBrushBevels(); + if(!noCollapseGroups) + AddBrushBevels(); /* keep it */ b = CopyBrush( buildBrush ); @@ -957,7 +997,7 @@ static void ParseRawBrush( qboolean onlyLights ) int planenum; shaderInfo_t *si; vec_t shift[ 2 ]; - vec_t rotate; + vec_t rotate = 0; vec_t scale[ 2 ]; char name[ MAX_QPATH ]; char shader[ MAX_QPATH ]; @@ -1154,7 +1194,7 @@ ParseBrush() parses a brush out of a map file and sets it up */ -static void ParseBrush( qboolean onlyLights ) +static void ParseBrush( qboolean onlyLights, qboolean noCollapseGroups ) { brush_t *b; @@ -1201,7 +1241,7 @@ static void ParseBrush( qboolean onlyLights ) } /* finish the brush */ - b = FinishBrush(); + b = FinishBrush(noCollapseGroups); } @@ -1213,11 +1253,16 @@ adds them to the world's brush list (used by func_group) */ +void AdjustBrushesForOrigin( entity_t *ent ); void MoveBrushesToWorld( entity_t *ent ) { brush_t *b, *next; parseMesh_t *pm; + /* we need to undo the common/origin adjustment, and instead shift them by the entity key origin */ + VectorScale(ent->origin, -1, ent->originbrush_origin); + AdjustBrushesForOrigin(ent); + VectorClear(ent->originbrush_origin); /* move brushes */ for( b = ent->brushes; b != NULL; b = next ) @@ -1280,7 +1325,6 @@ void AdjustBrushesForOrigin( entity_t *ent ) brush_t *b; parseMesh_t *p; - /* walk brush list */ for( b = ent->brushes; b != NULL; b = b->next ) { @@ -1291,7 +1335,7 @@ void AdjustBrushesForOrigin( entity_t *ent ) s = &b->sides[ i ]; /* offset side plane */ - newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->origin ); + newdist = mapplanes[ s->planenum ].dist - DotProduct( mapplanes[ s->planenum ].normal, ent->originbrush_origin ); /* find a new plane */ s->planenum = FindFloatPlane( mapplanes[ s->planenum ].normal, newdist, 0, NULL ); @@ -1305,7 +1349,7 @@ void AdjustBrushesForOrigin( entity_t *ent ) for( p = ent->patches; p != NULL; p = p->next ) { for( i = 0; i < (p->mesh.width * p->mesh.height); i++ ) - VectorSubtract( p->mesh.verts[ i ].xyz, ent->origin, p->mesh.verts[ i ].xyz ); + VectorSubtract( p->mesh.verts[ i ].xyz, ent->originbrush_origin, p->mesh.verts[ i ].xyz ); } } @@ -1534,11 +1578,12 @@ ParseMapEntity() parses a single entity out of a map file */ -static qboolean ParseMapEntity( qboolean onlyLights ) +static qboolean ParseMapEntity( qboolean onlyLights, qboolean noCollapseGroups ) { epair_t *ep; const char *classname, *value; - float lightmapScale; + float lightmapScale, shadeAngle; + int lightmapSampleSize; char shader[ MAX_QPATH ]; shaderInfo_t *celShader = NULL; brush_t *brush; @@ -1612,7 +1657,7 @@ static qboolean ParseMapEntity( qboolean onlyLights ) g_bBrushPrimit = BPRIMIT_NEWBRUSHES; /* parse brush primitive */ - ParseBrush( onlyLights ); + ParseBrush( onlyLights, noCollapseGroups ); } else { @@ -1622,7 +1667,7 @@ static qboolean ParseMapEntity( qboolean onlyLights ) /* parse old brush format */ UnGetToken(); - ParseBrush( onlyLights ); + ParseBrush( onlyLights, noCollapseGroups ); } entitySourceBrushes++; } @@ -1675,19 +1720,24 @@ static qboolean ParseMapEntity( qboolean onlyLights ) /* get explicit shadow flags */ GetEntityShadowFlags( mapEnt, NULL, &castShadows, &recvShadows ); + /* vortex: added _ls key (short name of lightmapscale) */ /* ydnar: get lightmap scaling value for this entity */ + lightmapScale = 0.0f; if( strcmp( "", ValueForKey( mapEnt, "lightmapscale" ) ) || - strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) ) + strcmp( "", ValueForKey( mapEnt, "_lightmapscale" ) ) || + strcmp( "", ValueForKey( mapEnt, "_ls" ) ) ) { /* get lightmap scale from entity */ lightmapScale = FloatForKey( mapEnt, "lightmapscale" ); if( lightmapScale <= 0.0f ) lightmapScale = FloatForKey( mapEnt, "_lightmapscale" ); + if( lightmapScale <= 0.0f ) + lightmapScale = FloatForKey( mapEnt, "_ls" ); + if( lightmapScale < 0.0f ) + lightmapScale = 0.0f; if( lightmapScale > 0.0f ) Sys_Printf( "Entity %d (%s) has lightmap scale of %.4f\n", mapEnt->mapEntityNum, classname, lightmapScale ); } - else - lightmapScale = 0.0f; /* ydnar: get cel shader :) for this entity */ value = ValueForKey( mapEnt, "_celshader" ); @@ -1695,12 +1745,50 @@ static qboolean ParseMapEntity( qboolean onlyLights ) value = ValueForKey( &entities[ 0 ], "_celshader" ); if( value[ 0 ] != '\0' ) { - sprintf( shader, "textures/%s", value ); - celShader = ShaderInfoForShader( shader ); - Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader ); + if(strcmp(value, "none")) + { + sprintf( shader, "textures/%s", value ); + celShader = ShaderInfoForShader( shader ); + Sys_Printf( "Entity %d (%s) has cel shader %s\n", mapEnt->mapEntityNum, classname, celShader->shader ); + } + else + { + celShader = NULL; + } } else - celShader = NULL; + celShader = (*globalCelShader ? ShaderInfoForShader(globalCelShader) : NULL); + + /* jal : entity based _shadeangle */ + shadeAngle = 0.0f; + if ( strcmp( "", ValueForKey( mapEnt, "_shadeangle" ) ) ) + shadeAngle = FloatForKey( mapEnt, "_shadeangle" ); + /* vortex' aliases */ + else if ( strcmp( "", ValueForKey( mapEnt, "_smoothnormals" ) ) ) + shadeAngle = FloatForKey( mapEnt, "_smoothnormals" ); + else if ( strcmp( "", ValueForKey( mapEnt, "_sn" ) ) ) + shadeAngle = FloatForKey( mapEnt, "_sn" ); + else if ( strcmp( "", ValueForKey( mapEnt, "_smooth" ) ) ) + shadeAngle = FloatForKey( mapEnt, "_smooth" ); + + if( shadeAngle < 0.0f ) + shadeAngle = 0.0f; + + if( shadeAngle > 0.0f ) + Sys_Printf( "Entity %d (%s) has shading angle of %.4f\n", mapEnt->mapEntityNum, classname, shadeAngle ); + + /* jal : entity based _samplesize */ + lightmapSampleSize = 0; + if ( strcmp( "", ValueForKey( mapEnt, "_lightmapsamplesize" ) ) ) + lightmapSampleSize = IntForKey( mapEnt, "_lightmapsamplesize" ); + else if ( strcmp( "", ValueForKey( mapEnt, "_samplesize" ) ) ) + lightmapSampleSize = IntForKey( mapEnt, "_samplesize" ); + + if( lightmapSampleSize < 0 ) + lightmapSampleSize = 0; + + if( lightmapSampleSize > 0 ) + Sys_Printf( "Entity %d (%s) has lightmap sample size of %d\n", mapEnt->mapEntityNum, classname, lightmapSampleSize ); /* attach stuff to everything in the entity */ for( brush = mapEnt->brushes; brush != NULL; brush = brush->next ) @@ -1708,8 +1796,10 @@ static qboolean ParseMapEntity( qboolean onlyLights ) brush->entityNum = mapEnt->mapEntityNum; brush->castShadows = castShadows; brush->recvShadows = recvShadows; + brush->lightmapSampleSize = lightmapSampleSize; brush->lightmapScale = lightmapScale; brush->celShader = celShader; + brush->shadeAngleDegrees = shadeAngle; } for( patch = mapEnt->patches; patch != NULL; patch = patch->next ) @@ -1717,6 +1807,7 @@ static qboolean ParseMapEntity( qboolean onlyLights ) patch->entityNum = mapEnt->mapEntityNum; patch->castShadows = castShadows; patch->recvShadows = recvShadows; + patch->lightmapSampleSize = lightmapSampleSize; patch->lightmapScale = lightmapScale; patch->celShader = celShader; } @@ -1729,18 +1820,18 @@ static qboolean ParseMapEntity( qboolean onlyLights ) /* get entity origin and adjust brushes */ GetVectorForKey( mapEnt, "origin", mapEnt->origin ); - if( mapEnt->origin[ 0 ] || mapEnt->origin[ 1 ] || mapEnt->origin[ 2 ] ) + if( mapEnt->originbrush_origin[ 0 ] || mapEnt->originbrush_origin[ 1 ] || mapEnt->originbrush_origin[ 2 ] ) AdjustBrushesForOrigin( mapEnt ); /* group_info entities are just for editor grouping (fixme: leak!) */ - if( !Q_stricmp( "group_info", classname ) ) + if( !noCollapseGroups && !Q_stricmp( "group_info", classname ) ) { numEntities--; return qtrue; } /* group entities are just for editor convenience, toss all brushes into worldspawn */ - if( funcGroup ) + if( !noCollapseGroups && funcGroup ) { MoveBrushesToWorld( mapEnt ); numEntities--; @@ -1758,11 +1849,11 @@ LoadMapFile() loads a map file into a list of entities */ -void LoadMapFile( char *filename, qboolean onlyLights ) +void LoadMapFile( char *filename, qboolean onlyLights, qboolean noCollapseGroups ) { FILE *file; brush_t *b; - int oldNumEntities, numMapBrushes; + int oldNumEntities = 0, numMapBrushes; /* note it */ @@ -1791,7 +1882,7 @@ void LoadMapFile( char *filename, qboolean onlyLights ) buildBrush = AllocBrush( MAX_BUILD_SIDES ); /* parse the map file */ - while( ParseMapEntity( onlyLights ) ); + while( ParseMapEntity( onlyLights, noCollapseGroups ) ); /* light loading */ if( onlyLights ) diff --git a/tools/quake3/q3map2/model.c b/tools/quake3/q3map2/model.c index ef0a0489..a56134c8 100644 --- a/tools/quake3/q3map2/model.c +++ b/tools/quake3/q3map2/model.c @@ -78,9 +78,9 @@ PicoLoadFileFunc() callback for picomodel.lib */ -void PicoLoadFileFunc( char *name, byte **buffer, int *bufSize ) +void PicoLoadFileFunc( const char *name, byte **buffer, int *bufSize ) { - *bufSize = vfsLoadFile( (const char*) name, (void**) buffer, 0 ); + *bufSize = vfsLoadFile( name, (void**) buffer, 0 ); } @@ -90,7 +90,7 @@ FindModel() - ydnar finds an existing picoModel and returns a pointer to the picoModel_t struct or NULL if not found */ -picoModel_t *FindModel( char *name, int frame ) +picoModel_t *FindModel( const char *name, int frame ) { int i; @@ -123,7 +123,7 @@ LoadModel() - ydnar loads a picoModel and returns a pointer to the picoModel_t struct or NULL if not found */ -picoModel_t *LoadModel( char *name, int frame ) +picoModel_t *LoadModel( const char *name, int frame ) { int i; picoModel_t *model, **pm; @@ -158,7 +158,7 @@ picoModel_t *LoadModel( char *name, int frame ) Error( "MAX_MODELS (%d) exceeded, there are too many model files referenced by the map.", MAX_MODELS ); /* attempt to parse model */ - *pm = PicoLoadModel( (char*) name, frame ); + *pm = PicoLoadModel( name, frame ); /* if loading failed, make a bogus model to silence the rest of the warnings */ if( *pm == NULL ) @@ -206,7 +206,7 @@ InsertModel() - ydnar adds a picomodel into the bsp */ -void InsertModel( char *name, int frame, m4x4_t transform, remap_t *remap, shaderInfo_t *celShader, int eNum, int castShadows, int recvShadows, int spawnFlags, float lightmapScale ) +void InsertModel( const char *name, int skin, int frame, m4x4_t transform, remap_t *remap, shaderInfo_t *celShader, int eNum, int castShadows, int recvShadows, int spawnFlags, float lightmapScale, int lightmapSampleSize, float shadeAngle ) { int i, j, k, s, numSurfaces; m4x4_t identity, nTransform; @@ -222,12 +222,76 @@ void InsertModel( char *name, int frame, m4x4_t transform, remap_t *remap, shade byte *color; picoIndex_t *indexes; remap_t *rm, *glob; + skinfile_t *sf, *sf2; + double normalEpsilon_save; + double distanceEpsilon_save; + char skinfilename[ MAX_QPATH ]; + char *skinfilecontent; + int skinfilesize; + char *skinfileptr, *skinfilenextptr; /* get model */ model = LoadModel( name, frame ); if( model == NULL ) return; + + /* load skin file */ + snprintf(skinfilename, sizeof(skinfilename), "%s_%d.skin", name, skin); + skinfilename[sizeof(skinfilename)-1] = 0; + skinfilesize = vfsLoadFile(skinfilename, (void**) &skinfilecontent, 0); + if(skinfilesize < 0 && skin != 0) + { + /* fallback to skin 0 if invalid */ + snprintf(skinfilename, sizeof(skinfilename), "%s_0.skin", name); + skinfilename[sizeof(skinfilename)-1] = 0; + skinfilesize = vfsLoadFile(skinfilename, (void**) &skinfilecontent, 0); + if(skinfilesize >= 0) + Sys_Printf( "Skin %d of %s does not exist, using 0 instead\n", skin, name ); + } + sf = NULL; + if(skinfilesize >= 0) + { + Sys_Printf( "Using skin %d of %s\n", skin, name ); + int pos; + for(skinfileptr = skinfilecontent; *skinfileptr; skinfileptr = skinfilenextptr) + { + // for fscanf + char format[64]; + + skinfilenextptr = strchr(skinfileptr, '\r'); + if(skinfilenextptr) + { + *skinfilenextptr++ = 0; + } + else + { + skinfilenextptr = strchr(skinfileptr, '\n'); + if(skinfilenextptr) + *skinfilenextptr++ = 0; + else + skinfilenextptr = skinfileptr + strlen(skinfileptr); + } + + /* create new item */ + sf2 = sf; + sf = safe_malloc( sizeof( *sf ) ); + sf->next = sf2; + + sprintf(format, "replace %%%ds %%%ds", (int)sizeof(sf->name)-1, (int)sizeof(sf->to)-1); + if(sscanf(skinfileptr, format, sf->name, sf->to) == 2) + continue; + sprintf(format, " %%%d[^, ] ,%%%ds", (int)sizeof(sf->name)-1, (int)sizeof(sf->to)-1); + if((pos = sscanf(skinfileptr, format, sf->name, sf->to)) == 2) + continue; + + /* invalid input line -> discard sf struct */ + Sys_Printf( "Discarding skin directive in %s: %s\n", skinfilename, skinfileptr ); + free(sf); + sf = sf2; + } + free(skinfilecontent); + } /* handle null matrix */ if( transform == NULL ) @@ -250,6 +314,10 @@ void InsertModel( char *name, int frame, m4x4_t transform, remap_t *remap, shade /* fix bogus lightmap scale */ if( lightmapScale <= 0.0f ) lightmapScale = 1.0f; + + /* fix bogus shade angle */ + if( shadeAngle <= 0.0f ) + shadeAngle = 0.0f; /* each surface on the model will become a new map drawsurface */ numSurfaces = PicoGetModelNumSurfaces( model ); @@ -265,9 +333,6 @@ void InsertModel( char *name, int frame, m4x4_t transform, remap_t *remap, shade if( PicoGetSurfaceType( surface ) != PICO_TRIANGLES ) continue; - /* fix the surface's normals */ - PicoFixSurfaceNormals( surface ); - /* allocate a surface (ydnar: gs mods) */ ds = AllocDrawSurface( SURFACE_TRIANGLES ); ds->entityNum = eNum; @@ -280,7 +345,27 @@ void InsertModel( char *name, int frame, m4x4_t transform, remap_t *remap, shade picoShaderName = ""; else picoShaderName = PicoGetShaderName( shader ); - + + /* handle .skin file */ + if(sf) + { + picoShaderName = NULL; + for(sf2 = sf; sf2 != NULL; sf2 = sf2->next) + { + if( !Q_stricmp( surface->name, sf2->name ) ) + { + Sys_FPrintf( SYS_VRB, "Skin file: mapping %s to %s\n", surface->name, sf2->to ); + picoShaderName = sf2->to; + break; + } + } + if(!picoShaderName) + { + Sys_FPrintf( SYS_VRB, "Skin file: not mapping %s\n", surface->name ); + continue; + } + } + /* handle shader remapping */ glob = NULL; for( rm = remap; rm != NULL; rm = rm->next ) @@ -318,13 +403,26 @@ void InsertModel( char *name, int frame, m4x4_t transform, remap_t *remap, shade /* set shader */ ds->shaderInfo = si; - - /* set lightmap scale */ - ds->lightmapScale = lightmapScale; - + /* force to meta? */ if( (si != NULL && si->forceMeta) || (spawnFlags & 4) ) /* 3rd bit */ ds->type = SURFACE_FORCED_META; + + /* fix the surface's normals (jal: conditioned by shader info) */ + if( !(spawnFlags & 64) && ( shadeAngle == 0.0f || ds->type != SURFACE_FORCED_META ) ) + PicoFixSurfaceNormals( surface ); + + /* set sample size */ + if( lightmapSampleSize > 0.0f ) + ds->sampleSize = lightmapSampleSize; + + /* set lightmap scale */ + if( lightmapScale > 0.0f ) + ds->lightmapScale = lightmapScale; + + /* set shading angle */ + if( shadeAngle > 0.0f ) + ds->shadeAngleDegrees = shadeAngle; /* set particulars */ ds->numVerts = PicoGetSurfaceNumVertexes( surface ); @@ -380,10 +478,20 @@ void InsertModel( char *name, int frame, m4x4_t transform, remap_t *remap, shade { dv->lightmap[ j ][ 0 ] = 0.0f; dv->lightmap[ j ][ 1 ] = 0.0f; - dv->color[ j ][ 0 ] = color[ 0 ]; - dv->color[ j ][ 1 ] = color[ 1 ]; - dv->color[ j ][ 2 ] = color[ 2 ]; - dv->color[ j ][ 3 ] = color[ 3 ]; + if(spawnFlags & 32) // spawnflag 32: model color -> alpha hack + { + dv->color[ j ][ 0 ] = 255.0f; + dv->color[ j ][ 1 ] = 255.0f; + dv->color[ j ][ 2 ] = 255.0f; + dv->color[ j ][ 3 ] = RGBTOGRAY( color ); + } + else + { + dv->color[ j ][ 0 ] = color[ 0 ]; + dv->color[ j ][ 1 ] = color[ 1 ]; + dv->color[ j ][ 2 ] = color[ 2 ]; + dv->color[ j ][ 3 ] = color[ 3 ]; + } } } @@ -398,30 +506,19 @@ void InsertModel( char *name, int frame, m4x4_t transform, remap_t *remap, shade /* ydnar: giant hack land: generate clipping brushes for model triangles */ if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */ { - vec3_t points[ 3 ], backs[ 3 ]; + vec3_t points[ 4 ], backs[ 3 ]; vec4_t plane, reverse, pa, pb, pc; - vec3_t nadir; /* temp hack */ - if( !si->clipModel && - ((si->compileFlags & C_TRANSLUCENT) || !(si->compileFlags & C_SOLID)) ) - continue; - - /* overflow check */ - if( (nummapplanes + 64) >= (MAX_MAP_PLANES >> 1) ) + if( !si->clipModel && !(si->compileFlags & C_SOLID) ) continue; /* walk triangle list */ for( i = 0; i < ds->numIndexes; i += 3 ) { /* overflow hack */ - if( (nummapplanes + 64) >= (MAX_MAP_PLANES >> 1) ) - { - Sys_Printf( "WARNING: MAX_MAP_PLANES (%d) hit generating clip brushes for model %s.\n", - MAX_MAP_PLANES, name ); - break; - } + AUTOEXPAND_BY_REALLOC(mapplanes, (nummapplanes+64) << 1, allocatedmapplanes, 1024); /* make points and back points */ for( j = 0; j < 3; j++ ) @@ -431,107 +528,135 @@ void InsertModel( char *name, int frame, m4x4_t transform, remap_t *remap, shade /* copy xyz */ VectorCopy( dv->xyz, points[ j ] ); -#if ! Q3MAP2_EXPERIMENTAL_MODEL_CLIPPING_FIX - // The code below is totally unneeded regardless of Q3MAP2_EXPERIMENTAL_MODEL_CLIPPING_FIX. - // backs is reinitialized further below. However, the extra code does not hurt anything. - VectorCopy( dv->xyz, backs[ j ] ); - - /* find nearest axial to normal and push back points opposite */ - /* note: this doesn't work as well as simply using the plane of the triangle, below */ - for( k = 0; k < 3; k++ ) - { - if( fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 1) % 3 ] ) && - fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 2) % 3 ] ) ) - { - backs[ j ][ k ] += dv->normal[ k ] < 0.0f ? 64.0f : -64.0f; - break; - } - } -#endif } + + VectorCopy( points[0], points[3] ); // for cyclic usage /* make plane for triangle */ + // div0: add some extra spawnflags: + // 0: snap normals to axial planes for extrusion + // 8: extrude with the original normals + // 16: extrude only with up/down normals (ideal for terrain) + // 24: extrude by distance zero (may need engine changes) if( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) ) { + vec3_t bestNormal; + float backPlaneDistance = 2; + + if(spawnFlags & 8) // use a DOWN normal + { + if(spawnFlags & 16) + { + // 24: normal as is, and zero width (broken) + VectorCopy(plane, bestNormal); + } + else + { + // 8: normal as is + VectorCopy(plane, bestNormal); + } + } + else + { + if(spawnFlags & 16) + { + // 16: UP/DOWN normal + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1)); + } + else + { + // 0: axial normal + if(fabs(plane[0]) > fabs(plane[1])) // x>y + if(fabs(plane[1]) > fabs(plane[2])) // x>y, y>z + VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0); + else // x>y, z>=y + if(fabs(plane[0]) > fabs(plane[2])) // x>z, z>=y + VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0); + else // z>=x, x>y + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1)); + else // y>=x + if(fabs(plane[1]) > fabs(plane[2])) // y>z, y>=x + VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0); + else // z>=y, y>=x + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1)); + } + } + + /* build a brush */ + buildBrush = AllocBrush( 48 ); + buildBrush->entityNum = mapEntityNum; + buildBrush->original = buildBrush; + buildBrush->contentShader = si; + buildBrush->compileFlags = si->compileFlags; + buildBrush->contentFlags = si->contentFlags; + normalEpsilon_save = normalEpsilon; + distanceEpsilon_save = distanceEpsilon; + if(si->compileFlags & C_STRUCTURAL) // allow forced structural brushes here + { + buildBrush->detail = qfalse; + + // only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model) + if(normalEpsilon > 0) + normalEpsilon = 0; + if(distanceEpsilon > 0) + distanceEpsilon = 0; + } + else + buildBrush->detail = qtrue; + /* regenerate back points */ for( j = 0; j < 3; j++ ) { /* get vertex */ dv = &ds->verts[ ds->indexes[ i + j ] ]; - - /* copy xyz */ - VectorCopy( dv->xyz, backs[ j ] ); - - /* find nearest axial to plane normal and push back points opposite */ - for( k = 0; k < 3; k++ ) - { -#if Q3MAP2_EXPERIMENTAL_MODEL_CLIPPING_FIX - if( fabs( plane[ k ] ) >= fabs( plane[ (k + 1) % 3 ] ) && - fabs( plane[ k ] ) >= fabs( plane[ (k + 2) % 3 ] ) ) -#else - // This code is broken for 45 degree angles where there - // is no clear winner. - if( fabs( plane[ k ] ) > fabs( plane[ (k + 1) % 3 ] ) && - fabs( plane[ k ] ) > fabs( plane[ (k + 2) % 3 ] ) ) -#endif - { - backs[ j ][ k ] += plane[ k ] < 0.0f ? 64.0f : -64.0f; - break; - } - } + + // shift by some units + VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]); // 64 prevents roundoff errors a bit } - + /* make back plane */ VectorScale( plane, -1.0f, reverse ); - reverse[ 3 ] = -(plane[ 3 ] - 1); - - /* make back pyramid point */ - VectorCopy( points[ 0 ], nadir ); - VectorAdd( nadir, points[ 1 ], nadir ); - VectorAdd( nadir, points[ 2 ], nadir ); - VectorScale( nadir, 0.3333333333333f, nadir ); - VectorMA( nadir, -2.0f, plane, nadir ); - - /* make 3 more planes */ - //% if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], nadir ) && - //% PlaneFromPoints( pb, points[ 1 ], points[ 0 ], nadir ) && - //% PlaneFromPoints( pc, points[ 0 ], points[ 2 ], nadir ) ) + reverse[ 3 ] = -plane[ 3 ]; + if((spawnFlags & 24) != 24) + reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance; + // that's at least sqrt(1/3) backPlaneDistance, unless in DOWN mode; in DOWN mode, we are screwed anyway if we encounter a plane that's perpendicular to the xy plane) + if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], backs[ 1 ] ) && - PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) && - PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) ) + PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) && + PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) ) { - /* build a brush */ - buildBrush = AllocBrush( 48 ); - - buildBrush->entityNum = mapEntityNum; - buildBrush->original = buildBrush; - buildBrush->contentShader = si; - buildBrush->compileFlags = si->compileFlags; - buildBrush->contentFlags = si->contentFlags; - buildBrush->detail = qtrue; - /* set up brush sides */ buildBrush->numsides = 5; - for( j = 0; j < buildBrush->numsides; j++ ) - buildBrush->sides[ j ].shaderInfo = si; + buildBrush->sides[ 0 ].shaderInfo = si; + for( j = 1; j < buildBrush->numsides; j++ ) + buildBrush->sides[ j ].shaderInfo = NULL; // don't emit these faces as draw surfaces, should make smaller BSPs; hope this works + buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points ); - buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 1, &points[ 2 ] ); - buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 1, &points[ 1 ] ); - buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 1, &points[ 0 ] ); - buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, points ); - - /* add to entity */ - if( CreateBrushWindings( buildBrush ) ) - { - AddBrushBevels(); - //% EmitBrushes( buildBrush, NULL, NULL ); - buildBrush->next = entities[ mapEntityNum ].brushes; - entities[ mapEntityNum ].brushes = buildBrush; - entities[ mapEntityNum ].numBrushes++; - } - else - free( buildBrush ); + buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 2, &points[ 1 ] ); // pa contains points[1] and points[2] + buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 2, &points[ 0 ] ); // pb contains points[0] and points[1] + buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 2, &points[ 2 ] ); // pc contains points[2] and points[0] (copied to points[3] + buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, backs ); + } + else + { + free(buildBrush); + continue; } + + normalEpsilon = normalEpsilon_save; + distanceEpsilon = distanceEpsilon_save; + + /* add to entity */ + if( CreateBrushWindings( buildBrush ) ) + { + AddBrushBevels(); + //% EmitBrushes( buildBrush, NULL, NULL ); + buildBrush->next = entities[ mapEntityNum ].brushes; + entities[ mapEntityNum ].brushes = buildBrush; + entities[ mapEntityNum ].numBrushes++; + } + else + free( buildBrush ); } } } @@ -547,13 +672,15 @@ adds misc_model surfaces to the bsp void AddTriangleModels( entity_t *e ) { - int num, frame, castShadows, recvShadows, spawnFlags; + int num, frame, skin, castShadows, recvShadows, spawnFlags; entity_t *e2; const char *targetName; const char *target, *model, *value; char shader[ MAX_QPATH ]; shaderInfo_t *celShader; float temp, baseLightmapScale, lightmapScale; + float shadeAngle; + int lightmapSampleSize; vec3_t origin, scale, angles; m4x4_t transform; epair_t *ep; @@ -577,9 +704,23 @@ void AddTriangleModels( entity_t *e ) } /* get lightmap scale */ - baseLightmapScale = FloatForKey( e, "_lightmapscale" ); - if( baseLightmapScale <= 0.0f ) - baseLightmapScale = 0.0f; + /* vortex: added _ls key (short name of lightmapscale) */ + baseLightmapScale = 0.0f; + if( strcmp( "", ValueForKey( e, "lightmapscale" ) ) || + strcmp( "", ValueForKey( e, "_lightmapscale" ) ) || + strcmp( "", ValueForKey( e, "_ls" ) ) ) + { + baseLightmapScale = FloatForKey( e, "lightmapscale" ); + if( baseLightmapScale <= 0.0f ) + baseLightmapScale = FloatForKey( e, "_lightmapscale" ); + if( baseLightmapScale <= 0.0f ) + baseLightmapScale = FloatForKey( e, "_ls" ); + if( baseLightmapScale < 0.0f ) + baseLightmapScale = 0.0f; + if( baseLightmapScale > 0.0f ) + Sys_Printf( "World Entity has lightmap scale of %.4f\n", baseLightmapScale ); + } + /* walk the entity list */ for( num = 1; num < numEntities; num++ ) @@ -696,15 +837,61 @@ void AddTriangleModels( entity_t *e ) celShader = ShaderInfoForShader( shader ); } else - celShader = NULL; - + celShader = *globalCelShader ? ShaderInfoForShader(globalCelShader) : NULL; + + /* jal : entity based _samplesize */ + lightmapSampleSize = 0; + if ( strcmp( "", ValueForKey( e2, "_lightmapsamplesize" ) ) ) + lightmapSampleSize = IntForKey( e2, "_lightmapsamplesize" ); + else if ( strcmp( "", ValueForKey( e2, "_samplesize" ) ) ) + lightmapSampleSize = IntForKey( e2, "_samplesize" ); + + if( lightmapSampleSize < 0 ) + lightmapSampleSize = 0; + + if( lightmapSampleSize > 0.0f ) + Sys_Printf( "misc_model has lightmap sample size of %.d\n", lightmapSampleSize ); + /* get lightmap scale */ - lightmapScale = FloatForKey( e2, "_lightmapscale" ); - if( lightmapScale <= 0.0f ) - lightmapScale = baseLightmapScale; - + /* vortex: added _ls key (short name of lightmapscale) */ + lightmapScale = 0.0f; + if( strcmp( "", ValueForKey( e2, "lightmapscale" ) ) || + strcmp( "", ValueForKey( e2, "_lightmapscale" ) ) || + strcmp( "", ValueForKey( e2, "_ls" ) ) ) + { + lightmapScale = FloatForKey( e2, "lightmapscale" ); + if( lightmapScale <= 0.0f ) + lightmapScale = FloatForKey( e2, "_lightmapscale" ); + if( lightmapScale <= 0.0f ) + lightmapScale = FloatForKey( e2, "_ls" ); + if( lightmapScale < 0.0f ) + lightmapScale = 0.0f; + if( lightmapScale > 0.0f ) + Sys_Printf( "misc_model has lightmap scale of %.4f\n", lightmapScale ); + } + + /* jal : entity based _shadeangle */ + shadeAngle = 0.0f; + if ( strcmp( "", ValueForKey( e2, "_shadeangle" ) ) ) + shadeAngle = FloatForKey( e2, "_shadeangle" ); + /* vortex' aliases */ + else if ( strcmp( "", ValueForKey( e2, "_smoothnormals" ) ) ) + shadeAngle = FloatForKey( e2, "_smoothnormals" ); + else if ( strcmp( "", ValueForKey( e2, "_sn" ) ) ) + shadeAngle = FloatForKey( e2, "_sn" ); + else if ( strcmp( "", ValueForKey( e2, "_smooth" ) ) ) + shadeAngle = FloatForKey( e2, "_smooth" ); + + if( shadeAngle < 0.0f ) + shadeAngle = 0.0f; + + if( shadeAngle > 0.0f ) + Sys_Printf( "misc_model has shading angle of %.4f\n", shadeAngle ); + + skin = IntForKey(e2, "skin"); + /* insert the model */ - InsertModel( (char*) model, frame, transform, remap, celShader, mapEntityNum, castShadows, recvShadows, spawnFlags, lightmapScale ); + InsertModel( model, skin, frame, transform, remap, celShader, mapEntityNum, castShadows, recvShadows, spawnFlags, lightmapScale, lightmapSampleSize, shadeAngle ); /* free shader remappings */ while( remap != NULL ) diff --git a/tools/quake3/q3map2/patch.c b/tools/quake3/q3map2/patch.c index 58b8ea20..9cd707e2 100644 --- a/tools/quake3/q3map2/patch.c +++ b/tools/quake3/q3map2/patch.c @@ -227,7 +227,6 @@ void ParsePatch( qboolean onlyLights ) float longestCurve; int maxIterations; - MatchToken( "{" ); /* get texture */ diff --git a/tools/quake3/q3map2/path_init.c b/tools/quake3/q3map2/path_init.c index 927ba76a..83383e22 100644 --- a/tools/quake3/q3map2/path_init.c +++ b/tools/quake3/q3map2/path_init.c @@ -49,7 +49,7 @@ int numBasePaths; char *basePaths[ MAX_BASE_PATHS ]; int numGamePaths; char *gamePaths[ MAX_GAME_PATHS ]; - +char *homeBasePath = NULL; /* @@ -109,6 +109,7 @@ void LokiInitPaths( char *argv0 ) strcpy( installPath, "../" ); #else char temp[ MAX_OS_PATH ]; + char last0[ 2 ]; char *home; char *path; char *last; @@ -122,7 +123,7 @@ void LokiInitPaths( char *argv0 ) /* do some path divining */ strcpy( temp, argv0 ); - if( strrchr( temp, '/' ) ) + if( strrchr( argv0, '/' ) ) argv0 = strrchr( argv0, '/' ) + 1; else { @@ -130,6 +131,7 @@ void LokiInitPaths( char *argv0 ) path = getenv( "PATH" ); /* minor setup */ + last = last0; last[ 0 ] = path[ 0 ]; last[ 1 ] = '\0'; found = qfalse; @@ -280,7 +282,7 @@ void AddHomeBasePath( char *path ) return; /* make a hole */ - for( i = 0; i < (MAX_BASE_PATHS - 1); i++ ) + for( i = (MAX_BASE_PATHS - 2); i >= 0; i-- ) basePaths[ i + 1 ] = basePaths[ i ]; /* concatenate home dir and path */ @@ -374,6 +376,21 @@ void InitPaths( int *argc, char **argv ) argv[ i ] = NULL; } + /* -fs_forbiddenpath */ + else if( strcmp( argv[ i ], "-fs_forbiddenpath" ) == 0 ) + { + if( ++i >= *argc ) + Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] ); + argv[ i - 1 ] = NULL; + if(g_numForbiddenDirs < VFS_MAXDIRS) + { + strncpy(g_strForbiddenDirs[g_numForbiddenDirs], argv[i], PATH_MAX); + g_strForbiddenDirs[g_numForbiddenDirs][PATH_MAX] = 0; + ++g_numForbiddenDirs; + } + argv[ i ] = NULL; + } + /* -fs_basepath */ else if( strcmp( argv[ i ], "-fs_basepath" ) == 0 ) { @@ -393,6 +410,16 @@ void InitPaths( int *argc, char **argv ) AddGamePath( argv[ i ] ); argv[ i ] = NULL; } + + /* -fs_nohomebase */ + else if( strcmp( argv[ i ], "-fs_homebase" ) == 0 ) + { + if( ++i >= *argc ) + Error( "Out of arguments: No path specified after %s.", argv[ i - 1 ] ); + argv[ i - 1 ] = NULL; + homeBasePath = argv[i]; + argv[ i ] = NULL; + } } /* remove processed arguments */ @@ -448,7 +475,10 @@ void InitPaths( int *argc, char **argv ) } /* this only affects unix */ - AddHomeBasePath( game->homeBasePath ); + if(homeBasePath) + AddHomeBasePath( homeBasePath ); + else + AddHomeBasePath( game->homeBasePath ); /* initialize vfs paths */ if( numBasePaths > MAX_BASE_PATHS ) diff --git a/tools/quake3/q3map2/portals.c b/tools/quake3/q3map2/portals.c index 02209d54..2efc1db4 100644 --- a/tools/quake3/q3map2/portals.c +++ b/tools/quake3/q3map2/portals.c @@ -668,9 +668,15 @@ qboolean FloodEntities( tree_t *tree ) /* get origin */ GetVectorForKey( e, "origin", origin ); + + /* as a special case, allow origin-less entities */ if( VectorCompare( origin, vec3_origin ) ) continue; + /* also allow bmodel entities outside, as they could be on a moving path that will go into the map */ + if( e->brushes != NULL || e->patches != NULL ) + continue; + /* handle skybox entities */ value = ValueForKey( e, "classname" ); if( !Q_stricmp( value, "_skybox" ) ) @@ -719,7 +725,11 @@ qboolean FloodEntities( tree_t *tree ) r = PlaceOccupant( headnode, origin, e, skybox ); if( r ) inside = qtrue; - if( (!r || tree->outside_node.occupied) && !tripped ) + if( !r ) + { + Sys_Printf( "Entity %i, Brush %i: Entity in solid\n", e->mapEntityNum, 0); + } + else if( tree->outside_node.occupied && !tripped ) { xml_Select( "Entity leaked", e->mapEntityNum, 0, qfalse ); tripped = qtrue; diff --git a/tools/quake3/q3map2/prtfile.c b/tools/quake3/q3map2/prtfile.c index 6f36f758..2f10c7c0 100644 --- a/tools/quake3/q3map2/prtfile.c +++ b/tools/quake3/q3map2/prtfile.c @@ -63,6 +63,38 @@ void WriteFloat (FILE *f, vec_t v) fprintf (f,"%f ",v); } +void CountVisportals_r(node_t *node) +{ + int s; + portal_t *p; + winding_t *w; + + // decision node + if (node->planenum != PLANENUM_LEAF) { + CountVisportals_r (node->children[0]); + CountVisportals_r (node->children[1]); + return; + } + + if (node->opaque) { + return; + } + + for (p = node->portals ; p ; p=p->next[s]) + { + w = p->winding; + s = (p->nodes[1] == node); + if (w && p->nodes[0] == node) + { + if (!PortalPassable(p)) + continue; + if(p->nodes[0]->cluster == p->nodes[1]->cluster) + continue; + ++num_visportals; + } + } +} + /* ================= WritePortalFile_r @@ -95,6 +127,9 @@ void WritePortalFile_r (node_t *node) { if (!PortalPassable(p)) continue; + if(p->nodes[0]->cluster == p->nodes[1]->cluster) + continue; + --num_visportals; // write out to the file // sometimes planes get turned around when they are very near @@ -102,6 +137,7 @@ void WritePortalFile_r (node_t *node) // plane the same way vis will, and flip the side orders if needed // FIXME: is this still relevent? WindingPlane (w, normal, &dist); + if ( DotProduct (p->plane.normal, normal) < 0.99 ) { // backwards... fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster); @@ -130,6 +166,40 @@ void WritePortalFile_r (node_t *node) } +void CountSolidFaces_r (node_t *node) +{ + int s; + portal_t *p; + winding_t *w; + + // decision node + if (node->planenum != PLANENUM_LEAF) { + CountSolidFaces_r (node->children[0]); + CountSolidFaces_r (node->children[1]); + return; + } + + if (node->opaque) { + return; + } + + for (p = node->portals ; p ; p=p->next[s]) + { + w = p->winding; + s = (p->nodes[1] == node); + if (w) + { + if (PortalPassable(p)) + continue; + if(p->nodes[0]->cluster == p->nodes[1]->cluster) + continue; + // write out to the file + + ++num_solidfaces; + } + } +} + /* ================= WriteFaceFile_r @@ -160,6 +230,8 @@ void WriteFaceFile_r (node_t *node) { if (PortalPassable(p)) continue; + if(p->nodes[0]->cluster == p->nodes[1]->cluster) + continue; // write out to the file if (p->nodes[0] == node) @@ -197,15 +269,31 @@ void WriteFaceFile_r (node_t *node) NumberLeafs_r ================ */ -void NumberLeafs_r (node_t *node) +void NumberLeafs_r (node_t *node, int c) { +#if 0 portal_t *p; - +#endif if ( node->planenum != PLANENUM_LEAF ) { // decision node node->cluster = -99; - NumberLeafs_r (node->children[0]); - NumberLeafs_r (node->children[1]); + + if(node->has_structural_children) + { +#if 0 + if(c >= 0) + Sys_FPrintf (SYS_ERR,"THIS CANNOT HAPPEN\n"); +#endif + NumberLeafs_r (node->children[0], c); + NumberLeafs_r (node->children[1], c); + } + else + { + if(c < 0) + c = num_visclusters++; + NumberLeafs_r (node->children[0], c); + NumberLeafs_r (node->children[1], c); + } return; } @@ -217,9 +305,12 @@ void NumberLeafs_r (node_t *node) return; } - node->cluster = num_visclusters; - num_visclusters++; + if(c < 0) + c = num_visclusters++; + + node->cluster = c; +#if 0 // count the portals for (p = node->portals ; p ; ) { @@ -238,6 +329,7 @@ void NumberLeafs_r (node_t *node) p = p->next[1]; } } +#endif } @@ -254,7 +346,9 @@ void NumberClusters(tree_t *tree) { Sys_FPrintf (SYS_VRB,"--- NumberClusters ---\n"); // set the cluster field in every leaf and count the total number of portals - NumberLeafs_r (tree->headnode); + NumberLeafs_r (tree->headnode, -1); + CountVisportals_r (tree->headnode); + CountSolidFaces_r (tree->headnode); Sys_FPrintf( SYS_VRB, "%9d visclusters\n", num_visclusters ); Sys_FPrintf( SYS_VRB, "%9d visportals\n", num_visportals ); diff --git a/tools/quake3/q3map2/q3map2.h b/tools/quake3/q3map2/q3map2.h index 78b2f7c1..e912d15b 100644 --- a/tools/quake3/q3map2/q3map2.h +++ b/tools/quake3/q3map2/q3map2.h @@ -35,8 +35,11 @@ several games based on the Quake III Arena engine, in the form of "Q3Map2." /* version */ -#define Q3MAP_VERSION "2.5.17" -#define Q3MAP_MOTD "Last one turns the lights off" +#ifndef Q3MAP_VERSION +#error no Q3MAP_VERSION defined +#endif +#define Q3MAP_MOTD "Your map saw the pretty lights from q3map2's BFG" + @@ -68,7 +71,6 @@ dependencies #include "cmdlib.h" #include "mathlib.h" #include "md5lib.h" -#include "md4lib.h" #include "ddslib.h" #include "picomodel.h" @@ -80,7 +82,8 @@ dependencies #include "inout.h" #include "vfs.h" #include "png.h" - +#include "md4.h" +#include "radiant_jpeglib.h" #include @@ -124,7 +127,6 @@ constants #define Q3MAP2_EXPERIMENTAL_HIGH_PRECISION_MATH_FIXES 1 #define Q3MAP2_EXPERIMENTAL_SNAP_NORMAL_FIX 1 #define Q3MAP2_EXPERIMENTAL_SNAP_PLANE_FIX 1 -#define Q3MAP2_EXPERIMENTAL_MODEL_CLIPPING_FIX 1 /* general */ #define MAX_QPATH 64 @@ -189,7 +191,7 @@ constants /* bsp */ #define MAX_PATCH_SIZE 32 #define MAX_BRUSH_SIDES 1024 -#define MAX_BUILD_SIDES 300 +#define MAX_BUILD_SIDES 1024 #define MAX_EXPANDED_AXIS 128 @@ -200,6 +202,7 @@ constants #define HINT_PRIORITY 1000 /* ydnar: force hint splits first and antiportal/areaportal splits last */ #define ANTIPORTAL_PRIORITY -1000 #define AREAPORTAL_PRIORITY -1000 +#define DETAIL_PRIORITY -3000 #define PSIDE_FRONT 1 #define PSIDE_BACK 2 @@ -218,10 +221,10 @@ constants #define PORTALFILE "PRT1" -#define MAX_PORTALS 32768 +#define MAX_PORTALS 0x20000 /* same as MAX_MAP_PORTALS */ #define MAX_SEPERATORS MAX_POINTS_ON_WINDING #define MAX_POINTS_ON_FIXED_WINDING 24 /* ydnar: increased this from 12 at the expense of more memory */ -#define MAX_PORTALS_ON_LEAF 128 +#define MAX_PORTALS_ON_LEAF 1024 /* light */ @@ -241,6 +244,7 @@ constants #define LIGHT_FAST_TEMP 512 #define LIGHT_FAST_ACTUAL (LIGHT_FAST | LIGHT_FAST_TEMP) #define LIGHT_NEGATIVE 1024 +#define LIGHT_UNNORMALIZED 2048 /* vortex: do not normalize _color */ #define LIGHT_SUN_DEFAULT (LIGHT_ATTEN_ANGLE | LIGHT_GRID | LIGHT_SURFACES) #define LIGHT_AREA_DEFAULT (LIGHT_ATTEN_ANGLE | LIGHT_ATTEN_DISTANCE | LIGHT_GRID | LIGHT_SURFACES) /* q3a and wolf are the same */ @@ -255,6 +259,7 @@ constants #define GRID_EPSILON 0.0f #define DEFAULT_LIGHTMAP_SAMPLE_SIZE 16 +#define DEFAULT_LIGHTMAP_MIN_SAMPLE_SIZE 0 #define DEFAULT_LIGHTMAP_SAMPLE_OFFSET 1.0f #define DEFAULT_SUBDIVIDE_THRESHOLD 1.0f @@ -269,22 +274,28 @@ constants #define BSP_LUXEL_SIZE 3 #define RAD_LUXEL_SIZE 3 #define SUPER_LUXEL_SIZE 4 +#define SUPER_FLAG_SIZE 4 +#define FLAG_FORCE_SUBSAMPLING 1 +#define FLAG_ALREADY_SUBSAMPLED 2 #define SUPER_ORIGIN_SIZE 3 #define SUPER_NORMAL_SIZE 4 #define SUPER_DELUXEL_SIZE 3 #define BSP_DELUXEL_SIZE 3 +#define SUPER_FLOODLIGHT_SIZE 4 #define VERTEX_LUXEL( s, v ) (vertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE)) #define RAD_VERTEX_LUXEL( s, v )(radVertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE)) #define BSP_LUXEL( s, x, y ) (lm->bspLuxels[ s ] + ((((y) * lm->w) + (x)) * BSP_LUXEL_SIZE)) #define RAD_LUXEL( s, x, y ) (lm->radLuxels[ s ] + ((((y) * lm->w) + (x)) * RAD_LUXEL_SIZE)) #define SUPER_LUXEL( s, x, y ) (lm->superLuxels[ s ] + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE)) +#define SUPER_FLAG( x, y ) (lm->superFlags + ((((y) * lm->sw) + (x)) * SUPER_FLAG_SIZE)) #define SUPER_DELUXEL( x, y ) (lm->superDeluxels + ((((y) * lm->sw) + (x)) * SUPER_DELUXEL_SIZE)) #define BSP_DELUXEL( x, y ) (lm->bspDeluxels + ((((y) * lm->w) + (x)) * BSP_DELUXEL_SIZE)) #define SUPER_CLUSTER( x, y ) (lm->superClusters + (((y) * lm->sw) + (x))) #define SUPER_ORIGIN( x, y ) (lm->superOrigins + ((((y) * lm->sw) + (x)) * SUPER_ORIGIN_SIZE)) #define SUPER_NORMAL( x, y ) (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE)) #define SUPER_DIRT( x, y ) (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE) + 3) /* stash dirtyness in normal[ 3 ] */ +#define SUPER_FLOODLIGHT( x, y ) (lm->superFloodLight + ((((y) * lm->sw) + (x)) * SUPER_FLOODLIGHT_SIZE) ) @@ -306,27 +317,19 @@ abstracted bsp file #define MAX_LIGHTMAP_SHADERS 256 /* ok to increase these at the expense of more memory */ -#define MAX_MAP_MODELS 0x400 -#define MAX_MAP_BRUSHES 0x10000 #define MAX_MAP_ENTITIES 0x1000 //% 0x800 /* ydnar */ #define MAX_MAP_ENTSTRING 0x80000 //% 0x40000 /* ydnar */ -#define MAX_MAP_SHADERS 0x800 //% 0x400 /* ydnar */ #define MAX_MAP_AREAS 0x100 /* MAX_MAP_AREA_BYTES in q_shared must match! */ #define MAX_MAP_FOGS 30 //& 0x100 /* RBSP (32 - world fog - goggles) */ -#define MAX_MAP_PLANES 0x100000 //% 0x20000 /* ydnar for md */ -#define MAX_MAP_NODES 0x20000 -#define MAX_MAP_BRUSHSIDES 0x100000 //% 0x20000 /* ydnar */ #define MAX_MAP_LEAFS 0x20000 -#define MAX_MAP_LEAFFACES 0x100000 //% 0x20000 /* ydnar */ -#define MAX_MAP_LEAFBRUSHES 0x40000 #define MAX_MAP_PORTALS 0x20000 #define MAX_MAP_LIGHTING 0x800000 #define MAX_MAP_LIGHTGRID 0x100000 //% 0x800000 /* ydnar: set to points, not bytes */ -#define MAX_MAP_VISIBILITY 0x200000 +#define MAX_MAP_VISCLUSTERS 0x4000 // <= MAX_MAP_LEAFS +#define MAX_MAP_VISIBILITY (VIS_HEADER_SIZE + MAX_MAP_VISCLUSTERS * (((MAX_MAP_VISCLUSTERS + 63) & ~63) >> 3)) #define MAX_MAP_DRAW_SURFS 0x20000 -#define MAX_MAP_DRAW_VERTS 0x100000 #define MAX_MAP_DRAW_INDEXES 0x80000 #define MAX_MAP_ADVERTISEMENTS 30 @@ -525,7 +528,7 @@ general types ------------------------------------------------------------------------------- */ /* ydnar: for smaller structs */ -typedef char qb_t; +typedef unsigned char qb_t; /* ydnar: for q3map_tcMod */ @@ -542,6 +545,13 @@ typedef struct surfaceParm_s } surfaceParm_t; +typedef enum +{ + MINIMAP_MODE_GRAY, + MINIMAP_MODE_BLACK, + MINIMAP_MODE_WHITE +} +miniMapMode_t; typedef struct game_s { @@ -558,7 +568,23 @@ typedef struct game_s qboolean wolfLight; /* when true, lights work like wolf q3map */ int lightmapSize; /* bsp lightmap width/height */ float lightmapGamma; /* default lightmap gamma */ + float lightmapExposure; /* default lightmap exposure */ float lightmapCompensate; /* default lightmap compensate value */ + float gridScale; /* vortex: default lightgrid scale (affects both directional and ambient spectres) */ + float gridAmbientScale; /* vortex: default lightgrid ambient spectre scale */ + qboolean lightAngleHL; /* jal: use half-lambert curve for light angle attenuation */ + qboolean noStyles; /* use lightstyles hack or not */ + qboolean keepLights; /* keep light entities on bsp */ + int patchSubdivisions; /* default patch subdivisions tolerance */ + qboolean patchShadows; /* patch casting enabled */ + qboolean deluxeMap; /* compile deluxemaps */ + int deluxeMode; /* deluxemap mode (0 - modelspace, 1 - tangentspace with renormalization, 2 - tangentspace without renormalization) */ + int miniMapSize; /* minimap size */ + float miniMapSharpen; /* minimap sharpening coefficient */ + float miniMapBorder; /* minimap border amount */ + qboolean miniMapKeepAspect; /* minimap keep aspect ratio by letterboxing */ + miniMapMode_t miniMapMode; /* minimap mode */ + char *miniMapNameFormat; /* minimap name format */ char *bspIdent; /* 4-letter bsp file prefix */ int bspVersion; /* bsp version to use */ qboolean lumpSwap; /* cod-style len/ofs order */ @@ -625,6 +651,14 @@ typedef struct remap_s } remap_t; +typedef struct skinfile_s +{ + struct skinfile_s *next; + char name[ 1024 ]; + char to[ MAX_QPATH ]; +} +skinfile_t; + /* wingdi.h hack, it's the same: 0 */ #undef CM_NONE @@ -639,8 +673,12 @@ typedef enum CM_ALPHA_SCALE, CM_COLOR_DOT_PRODUCT, CM_ALPHA_DOT_PRODUCT, + CM_COLOR_DOT_PRODUCT_SCALE, + CM_ALPHA_DOT_PRODUCT_SCALE, CM_COLOR_DOT_PRODUCT_2, - CM_ALPHA_DOT_PRODUCT_2 + CM_ALPHA_DOT_PRODUCT_2, + CM_COLOR_DOT_PRODUCT_2_SCALE, + CM_ALPHA_DOT_PRODUCT_2_SCALE } colorModType_t; @@ -677,6 +715,7 @@ typedef struct shaderInfo_s char *backShader; /* for surfaces that generate different front and back passes */ char *cloneShader; /* ydnar: for cloning of a surface */ char *remapShader; /* ydnar: remap a shader in final stage */ + char *deprecateShader; /* vortex: shader is deprecated and replaced by this on use */ surfaceModel_t *surfaceModel; /* ydnar: for distribution of models */ foliage_t *foliage; /* ydnar/splash damage: wolf et foliage */ @@ -728,7 +767,8 @@ typedef struct shaderInfo_s qb_t noFog; /* ydnar: supress fogging */ qb_t clipModel; /* ydnar: solid model hack */ qb_t noVertexLight; /* ydnar: leave vertex color alone */ - + qb_t noDirty; /* jal: do not apply the dirty pass to this surface */ + byte styleMarker; /* ydnar: light styles hack */ float vertexScale; /* vertex light scale */ @@ -752,7 +792,13 @@ typedef struct shaderInfo_s vec3_t color; /* normalized color */ vec3_t averageColor; - byte lightStyle; + byte lightStyle; + + /* vortex: per-surface floodlight */ + float floodlightDirectionScale; + vec3_t floodlightRGB; + float floodlightIntensity; + float floodlightDistance; qb_t lmMergable; /* ydnar */ int lmCustomWidth, lmCustomHeight; /* ydnar */ @@ -783,7 +829,7 @@ typedef struct face_s struct face_s *next; int planenum; int priority; - qboolean checked; + //qboolean checked; int compileFlags; winding_t *w; } @@ -795,7 +841,8 @@ typedef struct plane_s vec3_t normal; vec_t dist; int type; - struct plane_s *hash_chain; + int counter; + int hash_chain; } plane_t; @@ -862,7 +909,9 @@ typedef struct brush_s shaderInfo_t *celShader; /* :) */ /* ydnar: gs mods */ + int lightmapSampleSize; /* jal : entity based _lightmapsamplesize */ float lightmapScale; + float shadeAngleDegrees; /* jal : entity based _shadeangle */ vec3_t eMins, eMaxs; indexMap_t *im; @@ -913,6 +962,7 @@ typedef struct parseMesh_s shaderInfo_t *celShader; /* :) */ /* ydnar: gs mods */ + int lightmapSampleSize; /* jal : entity based _lightmapsamplesize */ float lightmapScale; vec3_t eMins, eMaxs; indexMap_t *im; @@ -1010,6 +1060,9 @@ typedef struct mapDrawSurface_s /* ydnar: per-surface (per-entity, actually) lightmap sample size scaling */ float lightmapScale; + + /* jal: per-surface (per-entity, actually) shadeangle */ + float shadeAngleDegrees; /* ydnar: surface classification */ vec3_t mins, maxs; @@ -1028,7 +1081,7 @@ typedef struct mapDrawSurface_s int maxIterations; int patchWidth, patchHeight; vec3_t bounds[ 2 ]; - + /* ydnar/sd: for foliage */ int numFoliageInstances; @@ -1053,6 +1106,7 @@ typedef struct metaTriangle_s shaderInfo_t *si; side_t *side; int entityNum, surfaceNum, planeNum, fogNum, sampleSize, castShadows, recvShadows; + float shadeAngleDegrees; vec4_t plane; vec3_t lightmapAxis; int indexes[ 3 ]; @@ -1076,6 +1130,7 @@ typedef struct int mapEntityNum, firstDrawSurf; int firstBrush, numBrushes; /* only valid during BSP compile */ epair_t *epairs; + vec3_t originbrush_origin; } entity_t; @@ -1109,6 +1164,8 @@ typedef struct node_s entity_t *occupant; /* for leak file testing */ struct portal_s *portals; /* also on nodes during construction */ + + qboolean has_structural_children; } node_t; @@ -1266,6 +1323,7 @@ typedef struct light_s float radiusByDist; /* for spotlights */ float fade; /* ydnar: from wolf, for linear lights */ float angleScale; /* ydnar: stolen from vlight for K */ + float extraDist; /* "extra dimension" distance of the light, to kill hot spots */ float add; /* ydnar: used for area lights */ float envelope; /* ydnar: units until falloff < tolerance */ @@ -1311,12 +1369,15 @@ typedef struct /* input and output */ vec3_t color; /* starts out at full color, may be reduced if transparent surfaces are crossed */ - + vec3_t colorNoShadow; /* result color with no shadow casting */ + vec3_t directionContribution; /* result contribution to the deluxe map */ + /* output */ vec3_t hit; int compileFlags; /* for determining surface compile flags traced through */ qboolean passSolid; qboolean opaque; + vec_t forceSubsampling; /* needs subsampling (alphashadow), value = max color contribution possible from it */ /* working data */ int numTestNodes; @@ -1382,6 +1443,13 @@ typedef struct rawLightmap_s int numLightClusters, *lightClusters; int sampleSize, actualSampleSize, axisNum; + + /* vortex: per-surface floodlight */ + float floodlightDirectionScale; + vec3_t floodlightRGB; + float floodlightIntensity; + float floodlightDistance; + int entityNum; int recvShadows; vec3_t mins, maxs, axis, origin, *vecs; @@ -1401,12 +1469,14 @@ typedef struct rawLightmap_s float *bspLuxels[ MAX_LIGHTMAPS ]; float *radLuxels[ MAX_LIGHTMAPS ]; float *superLuxels[ MAX_LIGHTMAPS ]; + unsigned char *superFlags; float *superOrigins; float *superNormals; int *superClusters; float *superDeluxels; /* average light direction */ float *bspDeluxels; + float *superFloodLight; } rawLightmap_t; @@ -1423,7 +1493,7 @@ rawGridPoint_t; typedef struct surfaceInfo_s { - bspModel_t *model; + int modelindex; shaderInfo_t *si; rawLightmap_t *lm; int parentSurfaceNum, childSurfaceNum; @@ -1436,8 +1506,6 @@ typedef struct surfaceInfo_s } surfaceInfo_t; - - /* ------------------------------------------------------------------------------- prototypes @@ -1462,11 +1530,15 @@ int BSPMain( int argc, char **argv ); /* convert_map.c */ int ConvertBSPToMap( char *bspName ); +int ConvertBSPToMap_BP( char *bspName ); /* convert_ase.c */ int ConvertBSPToASE( char *bspName ); +/* convert_obj.c */ +int ConvertBSPToOBJ( char *bspName ); + /* brush.c */ sideRef_t *AllocSideRef( side_t *side, sideRef_t *next ); @@ -1513,11 +1585,11 @@ void MakeNormalVectors( vec3_t forward, vec3_t right, vec3_t up ); /* map.c */ -void LoadMapFile( char *filename, qboolean onlyLights ); +void LoadMapFile( char *filename, qboolean onlyLights, qboolean noCollapseGroups ); int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ); int PlaneTypeForNormal( vec3_t normal ); void AddBrushBevels( void ); -brush_t *FinishBrush( void ); +brush_t *FinishBrush(qboolean noCollapseGroups); /* portals.c */ @@ -1552,7 +1624,7 @@ void SetLightStyles( void ); int EmitShader( const char *shader, int *contentFlags, int *surfaceFlags ); void BeginBSPFile( void ); -void EndBSPFile( void ); +void EndBSPFile( qboolean do_write ); void EmitBrushes( brush_t *brushes, int *firstBrush, int *numBrushes ); void EmitFogs( void ); @@ -1571,6 +1643,7 @@ void FreeTreePortals_r( node_t *node ); void ParsePatch( qboolean onlyLights ); mesh_t *SubdivideMesh( mesh_t in, float maxError, float minLength ); void PatchMapDrawSurfs( entity_t *e ); +void TriangulatePatchSurface( entity_t *e , mapDrawSurface_t *ds ); /* tjunction.c */ @@ -1593,10 +1666,10 @@ tree_t *FaceBSP( face_t *list ); /* model.c */ void PicoPrintFunc( int level, const char *str ); -void PicoLoadFileFunc( char *name, byte **buffer, int *bufSize ); -picoModel_t *FindModel( char *name, int frame ); -picoModel_t *LoadModel( char *name, int frame ); -void InsertModel( char *name, int frame, m4x4_t transform, remap_t *remap, shaderInfo_t *celShader, int eNum, int castShadows, int recvShadows, int spawnFlags, float lightmapScale ); +void PicoLoadFileFunc( const char *name, byte **buffer, int *bufSize ); +picoModel_t *FindModel( const char *name, int frame ); +picoModel_t *LoadModel( const char *name, int frame ); +void InsertModel( const char *name, int skin, int frame, m4x4_t transform, remap_t *remap, shaderInfo_t *celShader, int eNum, int castShadows, int recvShadows, int spawnFlags, float lightmapScale, int lightmapSampleSize, float shadeAngle ); void AddTriangleModels( entity_t *e ); @@ -1604,6 +1677,7 @@ void AddTriangleModels( entity_t *e ); mapDrawSurface_t *AllocDrawSurface( surfaceType_t type ); void FinishSurface( mapDrawSurface_t *ds ); void StripFaceSurface( mapDrawSurface_t *ds ); +void MaxAreaFaceSurface( mapDrawSurface_t *ds ); qboolean CalcSurfaceTextureRange( mapDrawSurface_t *ds ); qboolean CalcLightmapAxis( vec3_t normal, vec3_t axis ); void ClassifySurfaces( int numSurfs, mapDrawSurface_t *ds ); @@ -1616,7 +1690,7 @@ void ClearSurface( mapDrawSurface_t *ds ); void AddEntitySurfaceModels( entity_t *e ); mapDrawSurface_t *DrawSurfaceForSide( entity_t *e, brush_t *b, side_t *s, winding_t *w ); mapDrawSurface_t *DrawSurfaceForMesh( entity_t *e, parseMesh_t *p, mesh_t *mesh ); -mapDrawSurface_t *DrawSurfaceForFlare( int entNum, vec3_t origin, vec3_t normal, vec3_t color, char *flareShader, int lightStyle ); +mapDrawSurface_t *DrawSurfaceForFlare( int entNum, vec3_t origin, vec3_t normal, vec3_t color, const char *flareShader, int lightStyle ); mapDrawSurface_t *DrawSurfaceForShader( char *shader ); void ClipSidesIntoTree( entity_t *e, tree_t *tree ); void MakeDebugPortalSurfs( tree_t *tree ); @@ -1625,6 +1699,8 @@ void SubdivideFaceSurfaces( entity_t *e, tree_t *tree ); void AddEntitySurfaceModels( entity_t *e ); int AddSurfaceModels( mapDrawSurface_t *ds ); void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ); +void EmitPatchSurface( entity_t *e, mapDrawSurface_t *ds ); +void EmitTriangleSurface( mapDrawSurface_t *ds ); /* surface_fur.c */ @@ -1642,6 +1718,7 @@ void MakeEntityMetaTriangles( entity_t *e ); void FixMetaTJunctions( void ); void SmoothMetaTriangles( void ); void MergeMetaTriangles( void ); +void EmitMetaStats(); // vortex: print meta statistics even in no-verbose mode /* surface_extra.c */ @@ -1655,6 +1732,7 @@ int GetSurfaceExtraEntityNum( int num ); int GetSurfaceExtraCastShadows( int num ); int GetSurfaceExtraRecvShadows( int num ); int GetSurfaceExtraSampleSize( int num ); +int GetSurfaceExtraMinSampleSize( int num ); float GetSurfaceExtraLongestCurve( int num ); void GetSurfaceExtraLightmapAxis( int num, vec3_t lightmapAxis ); @@ -1666,6 +1744,8 @@ void LoadSurfaceExtraFile( const char *path ); void ProcessDecals( void ); void MakeEntityDecals( entity_t *e ); +/* map.c */ +void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv ); /* brush_primit.c */ void ComputeAxisBase( vec3_t normal, vec3_t texX, vec3_t texY); @@ -1719,6 +1799,12 @@ void SetupDirt(); float DirtForSample( trace_t *trace ); void DirtyRawLightmap( int num ); +void SetupFloodLight(); +void FloodlightRawLightmaps(); +void FloodlightIlluminateLightmap( rawLightmap_t *lm ); +float FloodLightForSample( trace_t *trace , float floodLightDistance, qboolean floodLightLowQuality); +void FloodLightRawLightmap( int num ); + void IlluminateRawLightmap( int num ); void IlluminateVertexes( int num ); @@ -1787,6 +1873,7 @@ void SwapBlock( int *block, int size ); int GetLumpElements( bspHeader_t *header, int lump, int size ); void *GetLump( bspHeader_t *header, int lump ); int CopyLump( bspHeader_t *header, int lump, void *dest, int size ); +int CopyLump_Allocate( bspHeader_t *header, int lump, void **dest, int size, int *allocationVariable ); void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length ); void LoadBSPFile( const char *filename ); @@ -1798,12 +1885,15 @@ void ParseEntities( void ); void UnparseEntities( void ); void PrintEntity( const entity_t *ent ); void SetKeyValue( entity_t *ent, const char *key, const char *value ); +qboolean KeyExists( const entity_t *ent, const char *key ); /* VorteX: check if key exists */ const char *ValueForKey( const entity_t *ent, const char *key ); int IntForKey( const entity_t *ent, const char *key ); vec_t FloatForKey( const entity_t *ent, const char *key ); void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ); entity_t *FindTargetEntity( const char *target ); void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows ); +void InjectCommandLine(char **argv, int beginArgs, int endArgs); + /* bspfile_ibsp.c */ @@ -1844,6 +1934,8 @@ Q_EXTERN game_t games[] , #include "game_nexuiz.h"/* most be after game_quake3.h as they share defines! */ , + #include "game_xonotic.h"/* most be after game_quake3.h as they share defines! */ + , #include "game_tremulous.h" /*LinuxManMikeC: must be after game_quake3.h, depends on #define's set in it */ , #include "game_tenebrae.h" @@ -1866,7 +1958,13 @@ Q_EXTERN game_t games[] , #include "game_reaction.h" /* must be after game_quake3.h */ , - { NULL } /* null game */ + #include "game_darkplaces.h" /* vortex: darkplaces q1 engine */ + , + #include "game_dq.h" /* vortex: deluxe quake game ( darkplaces q1 engine) */ + , + #include "game_prophecy.h" /* vortex: prophecy game ( darkplaces q1 engine) */ + , + #include "game__null.h" /* null game (must be last item) */ }; #endif Q_EXTERN game_t *game Q_ASSIGN( &games[ 0 ] ); @@ -1914,6 +2012,9 @@ Q_EXTERN qboolean nofog Q_ASSIGN( qfalse ); Q_EXTERN qboolean noHint Q_ASSIGN( qfalse ); /* ydnar */ Q_EXTERN qboolean renameModelShaders Q_ASSIGN( qfalse ); /* ydnar */ Q_EXTERN qboolean skyFixHack Q_ASSIGN( qfalse ); /* ydnar */ +Q_EXTERN qboolean bspAlternateSplitWeights Q_ASSIGN( qfalse ); /* 27 */ +Q_EXTERN qboolean deepBSP Q_ASSIGN( qfalse ); /* div0 */ +Q_EXTERN qboolean maxAreaFaceSurface Q_ASSIGN( qfalse ); /* divVerent */ Q_EXTERN int patchSubdivisions Q_ASSIGN( 8 ); /* ydnar: -patchmeta subdivisions */ @@ -1930,6 +2031,9 @@ Q_EXTERN qboolean emitFlares Q_ASSIGN( qfalse ); Q_EXTERN qboolean debugSurfaces Q_ASSIGN( qfalse ); Q_EXTERN qboolean debugInset Q_ASSIGN( qfalse ); Q_EXTERN qboolean debugPortals Q_ASSIGN( qfalse ); +Q_EXTERN qboolean lightmapTriangleCheck Q_ASSIGN(qfalse); +Q_EXTERN qboolean lightmapExtraVisClusterNudge Q_ASSIGN(qfalse); +Q_EXTERN qboolean lightmapFill Q_ASSIGN(qfalse); #if Q3MAP2_EXPERIMENTAL_SNAP_NORMAL_FIX // Increasing the normalEpsilon to compensate for new logic in SnapNormal(), where @@ -1972,13 +2076,16 @@ Q_EXTERN char source[ 1024 ]; Q_EXTERN char outbase[ 32 ]; Q_EXTERN int sampleSize; /* lightmap sample size in units */ +Q_EXTERN int minSampleSize; /* minimum sample size to use at all */ +Q_EXTERN int sampleScale; /* vortex: lightmap sample scale (ie quality)*/ Q_EXTERN int mapEntityNum Q_ASSIGN( 0 ); Q_EXTERN int entitySourceBrushes; -Q_EXTERN plane_t mapplanes[ MAX_MAP_PLANES ]; /* mapplanes[ num ^ 1 ] will always be the mirror or mapplanes[ num ] */ -Q_EXTERN int nummapplanes; /* nummapplanes will always be even */ +Q_EXTERN plane_t *mapplanes Q_ASSIGN(NULL); /* mapplanes[ num ^ 1 ] will always be the mirror or mapplanes[ num ] */ +Q_EXTERN int nummapplanes Q_ASSIGN(0); /* nummapplanes will always be even */ +Q_EXTERN int allocatedmapplanes Q_ASSIGN(0); Q_EXTERN int numMapPatches; Q_EXTERN vec3_t mapMins, mapMaxs; @@ -2001,6 +2108,7 @@ Q_EXTERN int numMapDrawSurfs; Q_EXTERN int numSurfacesByType[ NUM_SURFACE_TYPES ]; Q_EXTERN int numClearedSurfaces; Q_EXTERN int numStripSurfaces; +Q_EXTERN int numMaxAreaSurfaces; Q_EXTERN int numFanSurfaces; Q_EXTERN int numMergedSurfaces; Q_EXTERN int numMergedVerts; @@ -2047,13 +2155,12 @@ Q_EXTERN qboolean fastvis; Q_EXTERN qboolean noPassageVis; Q_EXTERN qboolean passageVisOnly; Q_EXTERN qboolean mergevis; +Q_EXTERN qboolean mergevisportals; Q_EXTERN qboolean nosort; Q_EXTERN qboolean saveprt; Q_EXTERN qboolean hint; /* ydnar */ Q_EXTERN char inbase[ MAX_QPATH ]; - -/* other bits */ -Q_EXTERN int totalvis; +Q_EXTERN char globalCelShader[ MAX_QPATH ]; Q_EXTERN float farPlaneDist; /* rr2do2, rf, mre, ydnar all contributed to this one... */ @@ -2094,10 +2201,13 @@ light global variables /* commandline arguments */ Q_EXTERN qboolean wolfLight Q_ASSIGN( qfalse ); +Q_EXTERN float extraDist Q_ASSIGN( 0.0f ); Q_EXTERN qboolean loMem Q_ASSIGN( qfalse ); Q_EXTERN qboolean noStyles Q_ASSIGN( qfalse ); +Q_EXTERN qboolean keepLights Q_ASSIGN( qfalse ); Q_EXTERN int sampleSize Q_ASSIGN( DEFAULT_LIGHTMAP_SAMPLE_SIZE ); +Q_EXTERN int minSampleSize Q_ASSIGN( DEFAULT_LIGHTMAP_MIN_SAMPLE_SIZE ); Q_EXTERN qboolean noVertexLighting Q_ASSIGN( qfalse ); Q_EXTERN qboolean noGridLighting Q_ASSIGN( qfalse ); @@ -2108,6 +2218,7 @@ Q_EXTERN qboolean cpmaHack Q_ASSIGN( qfalse ); 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 fast Q_ASSIGN( qfalse ); Q_EXTERN qboolean faster Q_ASSIGN( qfalse ); @@ -2125,14 +2236,19 @@ Q_EXTERN qboolean shade Q_ASSIGN( qfalse ); Q_EXTERN float shadeAngleDegrees Q_ASSIGN( 0.0f ); Q_EXTERN int superSample Q_ASSIGN( 0 ); Q_EXTERN int lightSamples Q_ASSIGN( 1 ); +Q_EXTERN qboolean lightRandomSamples Q_ASSIGN( qfalse ); +Q_EXTERN int lightSamplesSearchBoxSize Q_ASSIGN( 1 ); Q_EXTERN qboolean filter Q_ASSIGN( qfalse ); Q_EXTERN qboolean dark Q_ASSIGN( qfalse ); Q_EXTERN qboolean sunOnly Q_ASSIGN( qfalse ); Q_EXTERN int approximateTolerance Q_ASSIGN( 0 ); Q_EXTERN qboolean noCollapse Q_ASSIGN( qfalse ); +Q_EXTERN int lightmapSearchBlockSize Q_ASSIGN( 0 ); Q_EXTERN qboolean exportLightmaps Q_ASSIGN( qfalse ); Q_EXTERN qboolean externalLightmaps Q_ASSIGN( qfalse ); Q_EXTERN int lmCustomSize Q_ASSIGN( LIGHTMAP_WIDTH ); +Q_EXTERN char * lmCustomDir Q_ASSIGN( NULL ); +Q_EXTERN int lmLimitSize Q_ASSIGN( 0 ); Q_EXTERN qboolean dirty Q_ASSIGN( qfalse ); Q_EXTERN qboolean dirtDebug Q_ASSIGN( qfalse ); @@ -2141,6 +2257,15 @@ Q_EXTERN float dirtDepth Q_ASSIGN( 128.0f ); Q_EXTERN float dirtScale Q_ASSIGN( 1.0f ); Q_EXTERN float dirtGain Q_ASSIGN( 1.0f ); +/* 27: floodlighting */ +Q_EXTERN qboolean debugnormals Q_ASSIGN( qfalse ); +Q_EXTERN qboolean floodlighty Q_ASSIGN( qfalse ); +Q_EXTERN qboolean floodlight_lowquality Q_ASSIGN( qfalse ); +Q_EXTERN vec3_t floodlightRGB; +Q_EXTERN float floodlightIntensity Q_ASSIGN( 512.0f ); +Q_EXTERN float floodlightDistance Q_ASSIGN( 1024.0f ); +Q_EXTERN float floodlightDirectionScale Q_ASSIGN( 1.0f ); + Q_EXTERN qboolean dump Q_ASSIGN( qfalse ); Q_EXTERN qboolean debug Q_ASSIGN( qfalse ); Q_EXTERN qboolean debugUnused Q_ASSIGN( qfalse ); @@ -2158,8 +2283,19 @@ Q_EXTERN float areaScale Q_ASSIGN( 0.25f ); Q_EXTERN float skyScale Q_ASSIGN( 1.0f ); Q_EXTERN float bounceScale Q_ASSIGN( 0.25f ); +/* jal: alternative angle attenuation curve */ +Q_EXTERN qboolean lightAngleHL Q_ASSIGN( qfalse ); + +/* vortex: gridscale and gridambientscale */ +Q_EXTERN float gridScale Q_ASSIGN( 1.0f ); +Q_EXTERN float gridAmbientScale Q_ASSIGN( 1.0f ); +Q_EXTERN float gridDirectionality Q_ASSIGN( 1.0f ); +Q_EXTERN float gridAmbientDirectionality Q_ASSIGN( 0.0f ); +Q_EXTERN qboolean inGrid Q_ASSIGN(0); + /* ydnar: lightmap gamma/compensation */ Q_EXTERN float lightmapGamma Q_ASSIGN( 1.0f ); +Q_EXTERN float lightmapExposure Q_ASSIGN( 1.0f ); Q_EXTERN float lightmapCompensate Q_ASSIGN( 1.0f ); /* ydnar: for runtime tweaking of falloff tolerance */ @@ -2168,6 +2304,10 @@ Q_EXTERN qboolean exactPointToPolygon Q_ASSIGN( qtrue ); Q_EXTERN float formFactorValueScale Q_ASSIGN( 3.0f ); Q_EXTERN float linearScale Q_ASSIGN( 1.0f / 8000.0f ); +// for .ase conversion +Q_EXTERN qboolean shadersAsBitmap Q_ASSIGN( qfalse ); +Q_EXTERN qboolean lightmapsAsTexcoord Q_ASSIGN( qfalse ); + Q_EXTERN light_t *lights; Q_EXTERN int numPointLights; Q_EXTERN int numSpotLights; @@ -2264,6 +2404,9 @@ Q_EXTERN int numBSPLightmaps Q_ASSIGN( 0 ); Q_EXTERN int numExtLightmaps Q_ASSIGN( 0 ); Q_EXTERN outLightmap_t *outLightmaps Q_ASSIGN( NULL ); +/* vortex: per surface floodlight statictics */ +Q_EXTERN int numSurfacesFloodlighten Q_ASSIGN( 0 ); + /* grid points */ Q_EXTERN int numRawGridPoints Q_ASSIGN( 0 ); Q_EXTERN rawGridPoint_t *rawGridPoints Q_ASSIGN( NULL ); @@ -2306,34 +2449,43 @@ Q_EXTERN int numBSPEntities Q_ASSIGN( 0 ); Q_EXTERN entity_t entities[ MAX_MAP_ENTITIES ]; Q_EXTERN int numBSPModels Q_ASSIGN( 0 ); -Q_EXTERN bspModel_t bspModels[ MAX_MAP_MODELS ]; +Q_EXTERN int allocatedBSPModels Q_ASSIGN( 0 ); +Q_EXTERN bspModel_t* bspModels Q_ASSIGN(NULL); Q_EXTERN int numBSPShaders Q_ASSIGN( 0 ); -Q_EXTERN bspShader_t bspShaders[ MAX_MAP_MODELS ]; +Q_EXTERN int allocatedBSPShaders Q_ASSIGN( 0 ); +Q_EXTERN bspShader_t* bspShaders Q_ASSIGN(0); Q_EXTERN int bspEntDataSize Q_ASSIGN( 0 ); -Q_EXTERN char bspEntData[ MAX_MAP_ENTSTRING ]; +Q_EXTERN int allocatedBSPEntData Q_ASSIGN( 0 ); +Q_EXTERN char *bspEntData Q_ASSIGN(0); Q_EXTERN int numBSPLeafs Q_ASSIGN( 0 ); Q_EXTERN bspLeaf_t bspLeafs[ MAX_MAP_LEAFS ]; Q_EXTERN int numBSPPlanes Q_ASSIGN( 0 ); -Q_EXTERN bspPlane_t bspPlanes[ MAX_MAP_PLANES ]; +Q_EXTERN int allocatedBSPPlanes Q_ASSIGN(0); +Q_EXTERN bspPlane_t *bspPlanes; Q_EXTERN int numBSPNodes Q_ASSIGN( 0 ); -Q_EXTERN bspNode_t bspNodes[ MAX_MAP_NODES ]; +Q_EXTERN int allocatedBSPNodes Q_ASSIGN( 0 ); +Q_EXTERN bspNode_t* bspNodes Q_ASSIGN(NULL); Q_EXTERN int numBSPLeafSurfaces Q_ASSIGN( 0 ); -Q_EXTERN int bspLeafSurfaces[ MAX_MAP_LEAFFACES ]; +Q_EXTERN int allocatedBSPLeafSurfaces Q_ASSIGN( 0 ); +Q_EXTERN int* bspLeafSurfaces Q_ASSIGN(NULL); Q_EXTERN int numBSPLeafBrushes Q_ASSIGN( 0 ); -Q_EXTERN int bspLeafBrushes[ MAX_MAP_LEAFBRUSHES ]; +Q_EXTERN int allocatedBSPLeafBrushes Q_ASSIGN( 0 ); +Q_EXTERN int* bspLeafBrushes Q_ASSIGN(NULL); Q_EXTERN int numBSPBrushes Q_ASSIGN( 0 ); -Q_EXTERN bspBrush_t bspBrushes[ MAX_MAP_BRUSHES ]; +Q_EXTERN int allocatedBSPBrushes Q_ASSIGN( 0 ); +Q_EXTERN bspBrush_t* bspBrushes Q_ASSIGN(NULL); Q_EXTERN int numBSPBrushSides Q_ASSIGN( 0 ); -Q_EXTERN bspBrushSide_t bspBrushSides[ MAX_MAP_BRUSHSIDES ]; +Q_EXTERN int allocatedBSPBrushSides Q_ASSIGN( 0 ); +Q_EXTERN bspBrushSide_t* bspBrushSides Q_ASSIGN(NULL); Q_EXTERN int numBSPLightBytes Q_ASSIGN( 0 ); Q_EXTERN byte *bspLightBytes Q_ASSIGN( NULL ); @@ -2362,6 +2514,27 @@ Q_EXTERN bspFog_t bspFogs[ MAX_MAP_FOGS ]; Q_EXTERN int numBSPAds Q_ASSIGN( 0 ); Q_EXTERN bspAdvertisement_t bspAds[ MAX_MAP_ADVERTISEMENTS ]; +#define AUTOEXPAND_BY_REALLOC(ptr, reqitem, allocated, def) \ + do \ + { \ + if(reqitem >= allocated) \ + { \ + if(allocated == 0) \ + allocated = def; \ + while(reqitem >= allocated && allocated) \ + allocated *= 2; \ + if(!allocated || allocated > 2147483647 / (int)sizeof(*ptr)) \ + { \ + Error(#ptr " over 2 GB"); \ + } \ + ptr = realloc(ptr, sizeof(*ptr) * allocated); \ + if(!ptr) \ + Error(#ptr " out of memory"); \ + } \ + } \ + while(0) + +#define AUTOEXPAND_BY_REALLOC_BSP(suffix, def) AUTOEXPAND_BY_REALLOC(bsp##suffix, numBSP##suffix, allocatedBSP##suffix, def) /* end marker */ #endif diff --git a/tools/quake3/q3map2/q3map2.rc b/tools/quake3/q3map2/q3map2.rc index 78cf7b3a..bc120375 100644 --- a/tools/quake3/q3map2/q3map2.rc +++ b/tools/quake3/q3map2/q3map2.rc @@ -1 +1 @@ -101 ICON DISCARDABLE "q3map2.ico" +101 ICON DISCARDABLE "q3map2.ico" diff --git a/tools/quake3/q3map2/shaders.c b/tools/quake3/q3map2/shaders.c index 321a527b..3bf6cbe1 100644 --- a/tools/quake3/q3map2/shaders.c +++ b/tools/quake3/q3map2/shaders.c @@ -98,21 +98,47 @@ void ColorMod( colorMod_t *cm, int numVerts, bspDrawVert_t *drawVerts ) VectorSet( mult, c, c, c ); break; + case CM_COLOR_DOT_PRODUCT_SCALE: + c = DotProduct( dv->normal, cm2->data ); + c = (c - cm2->data[3]) / (cm2->data[4] - cm2->data[3]); + VectorSet( mult, c, c, c ); + break; + case CM_ALPHA_DOT_PRODUCT: mult[ 3 ] = DotProduct( dv->normal, cm2->data ); break; + case CM_ALPHA_DOT_PRODUCT_SCALE: + c = DotProduct( dv->normal, cm2->data ); + c = (c - cm2->data[3]) / (cm2->data[4] - cm2->data[3]); + mult[ 3 ] = c; + break; + case CM_COLOR_DOT_PRODUCT_2: c = DotProduct( dv->normal, cm2->data ); c *= c; VectorSet( mult, c, c, c ); break; + case CM_COLOR_DOT_PRODUCT_2_SCALE: + c = DotProduct( dv->normal, cm2->data ); + c *= c; + c = (c - cm2->data[3]) / (cm2->data[4] - cm2->data[3]); + VectorSet( mult, c, c, c ); + break; + case CM_ALPHA_DOT_PRODUCT_2: mult[ 3 ] = DotProduct( dv->normal, cm2->data ); mult[ 3 ] *= mult[ 3 ]; break; + case CM_ALPHA_DOT_PRODUCT_2_SCALE: + c = DotProduct( dv->normal, cm2->data ); + c *= c; + c = (c - cm2->data[3]) / (cm2->data[4] - cm2->data[3]); + mult[ 3 ] = c; + break; + default: break; } @@ -408,7 +434,6 @@ shaderInfo_t *CustomShader( shaderInfo_t *si, char *find, char *replace ) char shader[ MAX_QPATH ]; char *s; int loc; - md5_state_t mh; byte digest[ 16 ]; char *srcShaderText, temp[ 8192 ], shaderText[ 8192 ]; /* ydnar: fixme (make this bigger?) */ @@ -529,10 +554,8 @@ shaderInfo_t *CustomShader( shaderInfo_t *si, char *find, char *replace ) strcat( shaderText, &srcShaderText[ loc + strlen( find ) ] ); } - /* make md5 hash of the shader text */ - md5_init( &mh ); - md5_append( &mh, shaderText, strlen( shaderText ) ); - md5_finish( &mh, digest ); + /* make md4 hash of the shader text */ + Com_BlockFullChecksum(shaderText, strlen(shaderText), digest); /* mangle hash into a shader name */ sprintf( shader, "%s/%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", mapName, @@ -568,7 +591,6 @@ adds a vertexremapshader key/value pair to worldspawn void EmitVertexRemapShader( char *from, char *to ) { - md5_state_t mh; byte digest[ 16 ]; char key[ 64 ], value[ 256 ]; @@ -581,10 +603,8 @@ void EmitVertexRemapShader( char *from, char *to ) /* build value */ sprintf( value, "%s;%s", from, to ); - /* make md5 hash */ - md5_init( &mh ); - md5_append( &mh, value, strlen( value ) ); - md5_finish( &mh, digest ); + /* make md4 hash */ + Com_BlockFullChecksum(value, strlen(value), digest); /* make key (this is annoying, as vertexremapshader is precisely 17 characters, which is one too long, so we leave off the last byte of the md5 digest) */ @@ -790,8 +810,14 @@ static void LoadShaderImages( shaderInfo_t *si ) } if( VectorLength( si->color ) <= 0.0f ) + { ColorNormalize( color, si->color ); - VectorScale( color, (1.0f / count), si->averageColor ); + VectorScale( color, (1.0f / count), si->averageColor ); + } + else + { + VectorCopy( si->color, si->averageColor ); + } } @@ -801,13 +827,15 @@ ShaderInfoForShader() finds a shaderinfo for a named shader */ +#define MAX_SHADER_DEPRECATION_DEPTH 16 + shaderInfo_t *ShaderInfoForShader( const char *shaderName ) { int i; + int deprecationDepth; shaderInfo_t *si; char shader[ MAX_QPATH ]; - - + /* dummy check */ if( shaderName == NULL || shaderName[ 0 ] == '\0' ) { @@ -820,11 +848,27 @@ shaderInfo_t *ShaderInfoForShader( const char *shaderName ) StripExtension( shader ); /* search for it */ + deprecationDepth = 0; for( i = 0; i < numShaderInfo; i++ ) { si = &shaderInfo[ i ]; if( !Q_stricmp( shader, si->shader ) ) { + /* check if shader is deprecated */ + if (deprecationDepth < MAX_SHADER_DEPRECATION_DEPTH && si->deprecateShader && si->deprecateShader[ 0 ] ) + { + /* override name */ + strcpy( shader, si->deprecateShader ); + StripExtension( shader ); + /* increase deprecation depth */ + deprecationDepth++; + if (deprecationDepth == MAX_SHADER_DEPRECATION_DEPTH) + Sys_Printf("WARNING: Max deprecation depth of %i is reached on shader '%s'\n", MAX_SHADER_DEPRECATION_DEPTH, shader); + /* search again from beginning */ + i = -1; + continue; + } + /* load image if necessary */ if( si->finished == qfalse ) { @@ -1337,7 +1381,6 @@ static void ParseShaderFile( const char *filename ) { surfaceModel_t *model; - /* allocate new model and attach it */ model = safe_malloc( sizeof( *model ) ); memset( model, 0, sizeof( *model ) ); @@ -1462,6 +1505,30 @@ static void ParseShaderFile( const char *filename ) GetTokenAppend( shaderText, qfalse ); si->backsplashDistance = atof( token ); } + + /* q3map_floodLight */ + else if( !Q_stricmp( token, "q3map_floodLight" ) ) + { + /* get color */ + GetTokenAppend( shaderText, qfalse ); + si->floodlightRGB[ 0 ] = atof( token ); + GetTokenAppend( shaderText, qfalse ); + si->floodlightRGB[ 1 ] = atof( token ); + GetTokenAppend( shaderText, qfalse ); + si->floodlightRGB[ 2 ] = atof( token ); + GetTokenAppend( shaderText, qfalse ); + si->floodlightDistance = atof( token ); + GetTokenAppend( shaderText, qfalse ); + si->floodlightIntensity = atof( token ); + GetTokenAppend( shaderText, qfalse ); + si->floodlightDirectionScale = atof( token ); + } + + /* jal: q3map_nodirty : skip dirty */ + else if( !Q_stricmp( token, "q3map_nodirty" ) ) + { + si->noDirty = qtrue; + } /* q3map_lightmapSampleSize */ else if( !Q_stricmp( token, "q3map_lightmapSampleSize" ) ) @@ -1470,7 +1537,7 @@ static void ParseShaderFile( const char *filename ) si->lightmapSampleSize = atoi( token ); } - /* q3map_lightmapSampleSffset */ + /* q3map_lightmapSampleOffset */ else if( !Q_stricmp( token, "q3map_lightmapSampleOffset" ) ) { GetTokenAppend( shaderText, qfalse ); @@ -1587,6 +1654,18 @@ static void ParseShaderFile( const char *filename ) strcpy( si->remapShader, token ); } } + + /* q3map_deprecateShader */ + else if( !Q_stricmp( token, "q3map_deprecateShader" ) ) + { + GetTokenAppend( shaderText, qfalse ); + if( token[ 0 ] != '\0' ) + { + + si->deprecateShader = safe_malloc( strlen( token ) + 1 ); + strcpy( si->deprecateShader, token ); + } + } /* ydnar: q3map_offset */ else if( !Q_stricmp( token, "q3map_offset" ) ) @@ -1595,7 +1674,7 @@ static void ParseShaderFile( const char *filename ) si->offset = atof( token ); } - /* ydnar: q3map_textureSize (substitute for q3map_lightimage derivation for terrain) */ + /* ydnar: q3map_fur */ else if( !Q_stricmp( token, "q3map_fur" ) ) { GetTokenAppend( shaderText, qfalse ); @@ -1746,6 +1825,13 @@ static void ParseShaderFile( const char *filename ) Parse1DMatrixAppend( shaderText, 3, cm->data ); } + /* dotProductScale ( X Y Z MIN MAX ) */ + else if( !Q_stricmp( token, "dotProductScale" ) ) + { + cm->type = CM_COLOR_DOT_PRODUCT_SCALE + alpha; + Parse1DMatrixAppend( shaderText, 5, cm->data ); + } + /* dotProduct2 ( X Y Z ) */ else if( !Q_stricmp( token, "dotProduct2" ) ) { @@ -1753,6 +1839,13 @@ static void ParseShaderFile( const char *filename ) Parse1DMatrixAppend( shaderText, 3, cm->data ); } + /* dotProduct2scale ( X Y Z MIN MAX ) */ + else if( !Q_stricmp( token, "dotProduct2scale" ) ) + { + cm->type = CM_COLOR_DOT_PRODUCT_2_SCALE + alpha; + Parse1DMatrixAppend( shaderText, 5, cm->data ); + } + /* volume */ else if( !Q_stricmp( token, "volume" ) ) { @@ -1893,12 +1986,14 @@ static void ParseShaderFile( const char *filename ) si->styleMarker = 2; /* ydnar: default to searching for q3map_ */ - else +#if 0 + else { - //% Sys_FPrintf( SYS_VRB, "Attempting to match %s with a known surfaceparm\n", token ); + Sys_FPrintf( SYS_VRB, "Attempting to match %s with a known surfaceparm\n", token ); if( ApplySurfaceParm( &token[ 6 ], &si->contentFlags, &si->surfaceFlags, &si->compileFlags ) == qfalse ) - ;//% Sys_Printf( "WARNING: Unknown q3map_* directive \"%s\"\n", token ); + Sys_Printf( "WARNING: Unknown q3map_* directive \"%s\"\n", token ); } +#endif } diff --git a/tools/quake3/q3map2/surface.c b/tools/quake3/q3map2/surface.c index 5415ae10..ca4f5fa6 100644 --- a/tools/quake3/q3map2/surface.c +++ b/tools/quake3/q3map2/surface.c @@ -181,6 +181,7 @@ mapDrawSurface_t *MakeCelSurface( mapDrawSurface_t *src, shaderInfo_t *si ) /* do some fixups for celshading */ ds->planar = qfalse; ds->planeNum = -1; + ds->celShader = NULL; /* don't cel shade cels :P */ /* return the surface */ return ds; @@ -290,7 +291,7 @@ deletes all empty or bad surfaces from the surface list void TidyEntitySurfaces( entity_t *e ) { int i, j, deleted; - mapDrawSurface_t *out, *in; + mapDrawSurface_t *out, *in = NULL; /* note it */ @@ -630,19 +631,26 @@ void ClassifySurfaces( int numSurfs, mapDrawSurface_t *ds ) //% Sys_Printf( "Failed to map axis %d onto patch\n", bestAxis ); } - /* get lightmap sample size */ - if( ds->sampleSize <= 0 ) + /* calculate lightmap sample size */ + if( ds->shaderInfo->lightmapSampleSize > 0 ) /* shader value overrides every other */ + ds->sampleSize = ds->shaderInfo->lightmapSampleSize; + else if( ds->sampleSize <= 0 ) /* may contain the entity asigned value */ + ds->sampleSize = sampleSize; /* otherwise use global default */ + + if( ds->lightmapScale > 0.0f ) /* apply surface lightmap scaling factor */ { - ds->sampleSize = sampleSize; - if( ds->shaderInfo->lightmapSampleSize ) - ds->sampleSize = ds->shaderInfo->lightmapSampleSize; - if( ds->lightmapScale > 0 ) - ds->sampleSize *= ds->lightmapScale; - if( ds->sampleSize <= 0 ) - ds->sampleSize = 1; - else if( ds->sampleSize > 16384 ) /* powers of 2 are preferred */ - ds->sampleSize = 16384; + ds->sampleSize = ds->lightmapScale * (float)ds->sampleSize; + ds->lightmapScale = 0; /* applied */ } + + if( ds->sampleSize < minSampleSize ) + ds->sampleSize = minSampleSize; + + if( ds->sampleSize < 1 ) + ds->sampleSize = 1; + + if( ds->sampleSize > 16384 ) /* powers of 2 are preferred */ + ds->sampleSize = 16384; } } @@ -911,6 +919,7 @@ mapDrawSurface_t *DrawSurfaceForSide( entity_t *e, brush_t *b, side_t *s, windin ds->mapBrush = b; ds->sideRef = AllocSideRef( s, NULL ); ds->fogNum = -1; + ds->sampleSize = b->lightmapSampleSize; ds->lightmapScale = b->lightmapScale; ds->numVerts = w->numpoints; ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) ); @@ -986,6 +995,10 @@ mapDrawSurface_t *DrawSurfaceForSide( entity_t *e, brush_t *b, side_t *s, windin /* set cel shader */ ds->celShader = b->celShader; + + /* set shade angle */ + if( b->shadeAngleDegrees > 0.0f ) + ds->shadeAngleDegrees = b->shadeAngleDegrees; /* ydnar: gs mods: moved st biasing elsewhere */ return ds; @@ -1094,6 +1107,7 @@ mapDrawSurface_t *DrawSurfaceForMesh( entity_t *e, parseMesh_t *p, mesh_t *mesh ds->shaderInfo = si; ds->mapMesh = p; + ds->sampleSize = p->lightmapSampleSize; ds->lightmapScale = p->lightmapScale; /* ydnar */ ds->patchWidth = mesh->width; ds->patchHeight = mesh->height; @@ -1193,7 +1207,7 @@ DrawSurfaceForFlare() - ydnar creates a flare draw surface */ -mapDrawSurface_t *DrawSurfaceForFlare( int entNum, vec3_t origin, vec3_t normal, vec3_t color, char *flareShader, int lightStyle ) +mapDrawSurface_t *DrawSurfaceForFlare( int entNum, vec3_t origin, vec3_t normal, vec3_t color, const char *flareShader, int lightStyle ) { mapDrawSurface_t *ds; @@ -1951,6 +1965,51 @@ int FilterPointIntoTree_r( vec3_t point, mapDrawSurface_t *ds, node_t *node ) return AddReferenceToLeaf( ds, node ); } +/* +FilterPointConvexHullIntoTree_r() - ydnar +filters the convex hull of multiple points from a surface into the tree +*/ + +int FilterPointConvexHullIntoTree_r( vec3_t **points, int npoints, mapDrawSurface_t *ds, node_t *node ) +{ + float d, dmin, dmax; + plane_t *plane; + int refs = 0; + int i; + + if(!points) + return 0; + + /* is this a decision node? */ + if( node->planenum != PLANENUM_LEAF ) + { + /* classify the point in relation to the plane */ + plane = &mapplanes[ node->planenum ]; + + dmin = dmax = DotProduct( *(points[0]), plane->normal ) - plane->dist; + for(i = 1; i < npoints; ++i) + { + d = DotProduct( *(points[i]), plane->normal ) - plane->dist; + if(d > dmax) + dmax = d; + if(d < dmin) + dmin = d; + } + + /* filter by this plane */ + refs = 0; + if( dmax >= -ON_EPSILON ) + refs += FilterPointConvexHullIntoTree_r( points, npoints, ds, node->children[ 0 ] ); + if( dmin <= ON_EPSILON ) + refs += FilterPointConvexHullIntoTree_r( points, npoints, ds, node->children[ 1 ] ); + + /* return */ + return refs; + } + + /* add a reference */ + return AddReferenceToLeaf( ds, node ); +} /* @@ -1978,14 +2037,25 @@ int FilterWindingIntoTree_r( winding_t *w, mapDrawSurface_t *ds, node_t *node ) { /* 'fatten' the winding by the shader mins/maxs (parsed from vertexDeform move) */ /* note this winding is completely invalid (concave, nonplanar, etc) */ - fat = AllocWinding( w->numpoints * 3 ); - fat->numpoints = w->numpoints * 3; + fat = AllocWinding( w->numpoints * 3 + 3 ); + fat->numpoints = w->numpoints * 3 + 3; for( i = 0; i < w->numpoints; i++ ) { VectorCopy( w->p[ i ], fat->p[ i ] ); - VectorAdd( w->p[ i ], si->mins, fat->p[ i * 2 ] ); - VectorAdd( w->p[ i ], si->maxs, fat->p[ i * 3 ] ); + VectorAdd( w->p[ i ], si->mins, fat->p[ i + (w->numpoints+1) ] ); + VectorAdd( w->p[ i ], si->maxs, fat->p[ i + (w->numpoints+1) * 2 ] ); } + VectorCopy( w->p[ 0 ], fat->p[ i ] ); + VectorAdd( w->p[ 0 ], si->mins, fat->p[ i + w->numpoints ] ); + VectorAdd( w->p[ 0 ], si->maxs, fat->p[ i + w->numpoints * 2 ] ); + + /* + * note: this winding is STILL not suitable for ClipWindingEpsilon, and + * also does not really fulfill the intention as it only contains + * origin, +mins, +maxs, but thanks to the "closing" points I just + * added to the three sub-windings, the fattening at least doesn't make + * it worse + */ FreeWinding( w ); w = fat; @@ -2077,48 +2147,24 @@ subdivides a patch into an approximate curve and filters it into the tree static int FilterPatchIntoTree( mapDrawSurface_t *ds, tree_t *tree ) { - int i, x, y, refs; - mesh_t src, *mesh; - winding_t *w; + int x, y, refs; - - /* subdivide the surface */ - src.width = ds->patchWidth; - src.height = ds->patchHeight; - src.verts = ds->verts; - mesh = SubdivideMesh( src, FILTER_SUBDIVISION, 32 ); - - - /* filter each quad into the tree (fixme: use new patch x-triangulation code?) */ - refs = 0; - for( y = 0; y < (mesh->height - 1); y++ ) - { - for( x = 0; x < (mesh->width - 1); x++ ) + for(y = 0; y + 2 < ds->patchHeight; y += 2) + for(x = 0; x + 2 < ds->patchWidth; x += 2) { - /* triangle 1 */ - w = AllocWinding( 3 ); - w->numpoints = 3; - VectorCopy( mesh->verts[ y * mesh->width + x ].xyz, w->p[ 0 ] ); - VectorCopy( mesh->verts[ y * mesh->width + x + 1 ].xyz, w->p[ 1 ] ); - VectorCopy( mesh->verts[ (y + 1) * mesh->width + x ].xyz, w->p[ 2 ] ); - refs += FilterWindingIntoTree_r( w, ds, tree->headnode ); - - /* triangle 2 */ - w = AllocWinding( 3 ); - w->numpoints = 3; - VectorCopy( mesh->verts[ y * mesh->width + x + 1 ].xyz, w->p[ 0 ] ); - VectorCopy( mesh->verts[ (y + 1 ) * mesh->width + x + 1 ].xyz, w->p[ 1 ] ); - VectorCopy( mesh->verts[ (y + 1 ) * mesh->width + x ].xyz, w->p[ 2 ] ); - refs += FilterWindingIntoTree_r( w, ds, tree->headnode ); + vec3_t *points[9]; + points[0] = &ds->verts[(y+0) * ds->patchWidth + (x+0)].xyz; + points[1] = &ds->verts[(y+0) * ds->patchWidth + (x+1)].xyz; + points[2] = &ds->verts[(y+0) * ds->patchWidth + (x+2)].xyz; + points[3] = &ds->verts[(y+1) * ds->patchWidth + (x+0)].xyz; + points[4] = &ds->verts[(y+1) * ds->patchWidth + (x+1)].xyz; + points[5] = &ds->verts[(y+1) * ds->patchWidth + (x+2)].xyz; + points[6] = &ds->verts[(y+2) * ds->patchWidth + (x+0)].xyz; + points[7] = &ds->verts[(y+2) * ds->patchWidth + (x+1)].xyz; + points[8] = &ds->verts[(y+2) * ds->patchWidth + (x+2)].xyz; + refs += FilterPointConvexHullIntoTree_r(points, 9, ds, tree->headnode); } - } - - /* use point filtering as well */ - for( i = 0; i < (mesh->width * mesh->height); i++ ) - refs += FilterPointIntoTree_r( mesh->verts[ i ].xyz, ds, tree->headnode ); - - /* free the subdivided mesh and return */ - FreeMesh( mesh ); + return refs; } @@ -2248,8 +2294,6 @@ void EmitDrawVerts( mapDrawSurface_t *ds, bspDrawSurface_t *out ) for( i = 0; i < ds->numVerts; i++ ) { /* allocate a new vert */ - if( numBSPDrawVerts == MAX_MAP_DRAW_VERTS ) - Error( "MAX_MAP_DRAW_VERTS" ); IncDrawVerts(); dv = &bspDrawVerts[ numBSPDrawVerts - 1 ]; @@ -2445,25 +2489,27 @@ void EmitFlareSurface( mapDrawSurface_t *ds ) numSurfacesByType[ ds->type ]++; } - - /* EmitPatchSurface() emits a bsp patch drawsurface */ -void EmitPatchSurface( mapDrawSurface_t *ds ) +void EmitPatchSurface( entity_t *e, mapDrawSurface_t *ds ) { int i, j; bspDrawSurface_t *out; int surfaceFlags, contentFlags; - + int forcePatchMeta; + + /* vortex: _patchMeta support */ + forcePatchMeta = IntForKey(e, "_patchMeta" ); + if (!forcePatchMeta) + forcePatchMeta = IntForKey(e, "patchMeta" ); /* invert the surface if necessary */ if( ds->backSide || ds->shaderInfo->invert ) { bspDrawVert_t *dv1, *dv2, temp; - /* walk the verts, flip the normal */ for( i = 0; i < ds->numVerts; i++ ) @@ -2485,7 +2531,7 @@ void EmitPatchSurface( mapDrawSurface_t *ds ) /* invert facing */ VectorScale( ds->lightmapVecs[ 2 ], -1.0f, ds->lightmapVecs[ 2 ] ); } - + /* allocate a new surface */ if( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS ) Error( "MAX_MAP_DRAW_SURFS" ); @@ -2493,12 +2539,12 @@ void EmitPatchSurface( mapDrawSurface_t *ds ) ds->outputNum = numBSPDrawSurfaces; numBSPDrawSurfaces++; memset( out, 0, sizeof( *out ) ); - + /* set it up */ out->surfaceType = MST_PATCH; if( debugSurfaces ) out->shaderNum = EmitShader( "debugsurfaces", NULL, NULL ); - else if( patchMeta ) + else if( patchMeta || forcePatchMeta ) { /* patch meta requires that we have nodraw patches for collision */ surfaceFlags = ds->shaderInfo->surfaceFlags; @@ -2548,8 +2594,6 @@ void EmitPatchSurface( mapDrawSurface_t *ds ) numSurfacesByType[ ds->type ]++; } - - /* OptimizeTriangleSurface() - ydnar optimizes the vertex/index data in a triangle surface @@ -2673,12 +2717,11 @@ EmitTriangleSurface() creates a bsp drawsurface from arbitrary triangle surfaces */ -static void EmitTriangleSurface( mapDrawSurface_t *ds ) +void EmitTriangleSurface( mapDrawSurface_t *ds ) { int i, temp; bspDrawSurface_t *out; - - + /* invert the surface if necessary */ if( ds->backSide || ds->shaderInfo->invert ) { @@ -2689,15 +2732,15 @@ static void EmitTriangleSurface( mapDrawSurface_t *ds ) ds->indexes[ i ] = ds->indexes[ i + 1 ]; ds->indexes[ i + 1 ] = temp; } - + /* walk the verts, flip the normal */ for( i = 0; i < ds->numVerts; i++ ) VectorScale( ds->verts[ i ].normal, -1.0f, ds->verts[ i ].normal ); - + /* invert facing */ VectorScale( ds->lightmapVecs[ 2 ], -1.0f, ds->lightmapVecs[ 2 ] ); } - + /* allocate a new surface */ if( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS ) Error( "MAX_MAP_DRAW_SURFS" ); @@ -2804,15 +2847,17 @@ EmitFaceSurface() emits a bsp planar winding (brush face) drawsurface */ -static void EmitFaceSurface( mapDrawSurface_t *ds ) +static void EmitFaceSurface(mapDrawSurface_t *ds ) { /* strip/fan finding was moved elsewhere */ - StripFaceSurface( ds ); - EmitTriangleSurface( ds ); + if(maxAreaFaceSurface) + MaxAreaFaceSurface( ds ); + else + StripFaceSurface( ds ); + EmitTriangleSurface(ds); } - /* MakeDebugPortalSurfs_r() - ydnar generates drawsurfaces for passable portals in the bsp @@ -3128,7 +3173,7 @@ int AddSurfaceModelsToTriangle_r( mapDrawSurface_t *ds, surfaceModel_t *model, b } /* insert the model */ - InsertModel( (char *) model->model, 0, transform, NULL, ds->celShader, ds->entityNum, ds->castShadows, ds->recvShadows, 0, ds->lightmapScale ); + InsertModel( (char *) model->model, 0, 0, transform, NULL, ds->celShader, ds->entityNum, ds->castShadows, ds->recvShadows, 0, ds->lightmapScale, 0, 0 ); /* return to sender */ return 1; @@ -3406,6 +3451,7 @@ void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ) vec3_t origin, mins, maxs; int refs; int numSurfs, numRefs, numSkyboxSurfaces; + qboolean sb; /* note it */ @@ -3424,15 +3470,18 @@ void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ) /* get shader */ si = ds->shaderInfo; - + /* ydnar: skybox surfaces are special */ if( ds->skybox ) { refs = AddReferenceToTree_r( ds, tree->headnode, qtrue ); ds->skybox = qfalse; + sb = qtrue; } else { + sb = qfalse; + /* refs initially zero */ refs = 0; @@ -3502,7 +3551,7 @@ void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ) if( refs == 0 ) refs = FilterPatchIntoTree( ds, tree ); if( refs > 0 ) - EmitPatchSurface( ds ); + EmitPatchSurface( e, ds ); break; /* handle triangle surfaces */ @@ -3552,6 +3601,11 @@ void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ) refs = 0; break; } + + /* maybe surface got marked as skybox again */ + /* if we keep that flag, it will get scaled up AGAIN */ + if(sb) + ds->skybox = qfalse; /* tot up the references */ if( refs > 0 ) @@ -3590,6 +3644,7 @@ void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ) Sys_FPrintf( SYS_VRB, "%9d (%d) emitted drawsurfs\n", numSurfs, numBSPDrawSurfaces ); Sys_FPrintf( SYS_VRB, "%9d stripped face surfaces\n", numStripSurfaces ); Sys_FPrintf( SYS_VRB, "%9d fanned face surfaces\n", numFanSurfaces ); + Sys_FPrintf( SYS_VRB, "%9d maxarea'd face surfaces\n", numMaxAreaSurfaces ); Sys_FPrintf( SYS_VRB, "%9d surface models generated\n", numSurfaceModels ); Sys_FPrintf( SYS_VRB, "%9d skybox surfaces generated\n", numSkyboxSurfaces ); for( i = 0; i < NUM_SURFACE_TYPES; i++ ) diff --git a/tools/quake3/q3map2/surface_extra.c b/tools/quake3/q3map2/surface_extra.c index 440fd946..5cadc1d9 100644 --- a/tools/quake3/q3map2/surface_extra.c +++ b/tools/quake3/q3map2/surface_extra.c @@ -346,7 +346,7 @@ void LoadSurfaceExtraFile( const char *path ) } /* parse the file */ - ParseFromMemory( buffer, size ); + ParseFromMemory( (char *) buffer, size ); /* tokenize it */ while( 1 ) diff --git a/tools/quake3/q3map2/surface_foliage.c b/tools/quake3/q3map2/surface_foliage.c index e9a8ec71..cc5452ae 100644 --- a/tools/quake3/q3map2/surface_foliage.c +++ b/tools/quake3/q3map2/surface_foliage.c @@ -275,7 +275,7 @@ void Foliage( mapDrawSurface_t *src ) m4x4_scale_for_vec3( transform, scale ); /* add the model to the bsp */ - InsertModel( foliage->model, 0, transform, NULL, NULL, src->entityNum, src->castShadows, src->recvShadows, 0, src->lightmapScale ); + InsertModel( foliage->model, 0, 0, transform, NULL, NULL, src->entityNum, src->castShadows, src->recvShadows, 0, src->lightmapScale, 0, 0 ); /* walk each new surface */ for( i = oldNumMapDrawSurfs; i < numMapDrawSurfs; i++ ) diff --git a/tools/quake3/q3map2/surface_meta.c b/tools/quake3/q3map2/surface_meta.c index 9191ac14..0e300dde 100644 --- a/tools/quake3/q3map2/surface_meta.c +++ b/tools/quake3/q3map2/surface_meta.c @@ -84,7 +84,7 @@ static int FindMetaVertex( bspDrawVert_t *src ) { int i; bspDrawVert_t *v, *temp; - + /* try to find an existing drawvert */ for( i = firstSearchMetaVert, v = &metaVerts[ i ]; i < numMetaVerts; i++, v++ ) @@ -288,6 +288,7 @@ static void SurfaceToMetaTriangles( mapDrawSurface_t *ds ) src.recvShadows = ds->recvShadows; src.fogNum = ds->fogNum; src.sampleSize = ds->sampleSize; + src.shadeAngleDegrees = ds->shadeAngleDegrees; VectorCopy( ds->lightmapAxis, src.lightmapAxis ); /* copy drawverts */ @@ -312,23 +313,41 @@ TriangulatePatchSurface() creates triangles from a patch */ -void TriangulatePatchSurface( mapDrawSurface_t *ds ) +void TriangulatePatchSurface( entity_t *e , mapDrawSurface_t *ds ) { int iterations, x, y, pw[ 5 ], r; mapDrawSurface_t *dsNew; mesh_t src, *subdivided, *mesh; - - + int forcePatchMeta; + int patchQuality; + int patchSubdivision; + + /* vortex: _patchMeta, _patchQuality, _patchSubdivide support */ + forcePatchMeta = IntForKey(e, "_patchMeta" ); + if (!forcePatchMeta) + forcePatchMeta = IntForKey(e, "patchMeta" ); + patchQuality = IntForKey(e, "_patchQuality" ); + if (!patchQuality) + patchQuality = IntForKey(e, "patchQuality" ); + if (!patchQuality) + patchQuality = 1.0; + patchSubdivision = IntForKey(e, "_patchSubdivide" ); + if (!patchSubdivision) + patchSubdivision = IntForKey(e, "patchSubdivide" ); + /* try to early out */ - if( ds->numVerts == 0 || ds->type != SURFACE_PATCH || patchMeta == qfalse ) + if(ds->numVerts == 0 || ds->type != SURFACE_PATCH || ( patchMeta == qfalse && !forcePatchMeta) ) return; - /* make a mesh from the drawsurf */ src.width = ds->patchWidth; src.height = ds->patchHeight; src.verts = ds->verts; //% subdivided = SubdivideMesh( src, 8, 999 ); - iterations = IterationsForCurve( ds->longestCurve, patchSubdivisions ); + if (patchSubdivision) + iterations = IterationsForCurve( ds->longestCurve, patchSubdivision ); + else + iterations = IterationsForCurve( ds->longestCurve, patchSubdivisions / patchQuality ); + subdivided = SubdivideMesh2( src, iterations ); //% ds->maxIterations /* fit it to the curve and remove colinear verts on rows/columns */ @@ -394,6 +413,222 @@ void TriangulatePatchSurface( mapDrawSurface_t *ds ) ClassifySurfaces( 1, ds ); } +#define TINY_AREA 1.0f +#define MAXAREA_MAXTRIES 8 +int MaxAreaIndexes(bspDrawVert_t *vert, int cnt, int *indexes) +{ + int r, s, t, bestR = 0, bestS = 1, bestT = 2; + int i, j, try; + double A, bestA = -1, V, bestV = -1; + vec3_t ab, ac, bc, cross; + bspDrawVert_t *buf; + double shiftWidth; + + if(cnt < 3) + return 0; + + /* calculate total area */ + A = 0; + for(i = 1; i+1 < cnt; ++i) + { + VectorSubtract(vert[i].xyz, vert[0].xyz, ab); + VectorSubtract(vert[i+1].xyz, vert[0].xyz, ac); + CrossProduct(ab, ac, cross); + A += VectorLength(cross); + } + V = 0; + for(i = 0; i < cnt; ++i) + { + VectorSubtract(vert[(i+1)%cnt].xyz, vert[i].xyz, ab); + V += VectorLength(ab); + } + + /* calculate shift width from the area sensibly, assuming the polygon + * fits about 25% of the screen in both dimensions + * we assume 1280x1024 + * 1 pixel is then about sqrt(A) / (0.25 * screenwidth) + * 8 pixels are then about sqrt(A) / (0.25 * 1280) * 8 + * 8 pixels are then about sqrt(A) * 0.025 + * */ + shiftWidth = sqrt(A) * 0.0125; + /* 3->1 6->2 12->3 ... */ + if(A - ceil(log(cnt/1.5) / log(2)) * V * shiftWidth * 2 < 0) + { + /* printf("Small triangle detected (area %f, circumference %f), adjusting shiftWidth from %f to ", A, V, shiftWidth); */ + shiftWidth = A / (ceil(log(cnt/1.5) / log(2)) * V * 2); + /* printf("%f\n", shiftWidth); */ + } + + /* find the triangle with highest area */ + for(r = 0; r+2 < cnt; ++r) + for(s = r+1; s+1 < cnt; ++s) + for(t = s+1; t < cnt; ++t) + { + VectorSubtract(vert[s].xyz, vert[r].xyz, ab); + VectorSubtract(vert[t].xyz, vert[r].xyz, ac); + VectorSubtract(vert[t].xyz, vert[s].xyz, bc); + CrossProduct(ab, ac, cross); + A = VectorLength(cross); + + V = A - (VectorLength(ab) - VectorLength(ac) - VectorLength(bc)) * shiftWidth; + /* value = A - circumference * shiftWidth, i.e. we back out by shiftWidth units from each side, to prevent too acute triangles */ + /* this kind of simulates "number of shiftWidth*shiftWidth fragments in the triangle not touched by an edge" */ + + if(bestA < 0 || V > bestV) + { + bestA = A; + bestV = V; + bestR = r; + bestS = s; + bestT = t; + } + } + + /* + if(bestV < 0) + printf("value was REALLY bad\n"); + */ + + for(try = 0; try < MAXAREA_MAXTRIES; ++try) + { + if(try) + { + bestR = rand() % cnt; + bestS = rand() % cnt; + bestT = rand() % cnt; + if(bestR == bestS || bestR == bestT || bestS == bestT) + continue; + // bubblesort inline + // abc acb bac bca cab cba + if(bestR > bestS) + { + j = bestR; + bestR = bestS; + bestS = j; + } + // abc acb abc bca acb bca + if(bestS > bestT) + { + j = bestS; + bestS = bestT; + bestT = j; + } + // abc abc abc bac abc bac + if(bestR > bestS) + { + j = bestR; + bestR = bestS; + bestS = j; + } + // abc abc abc abc abc abc + + VectorSubtract(vert[bestS].xyz, vert[bestR].xyz, ab); + VectorSubtract(vert[bestT].xyz, vert[bestR].xyz, ac); + CrossProduct(ab, ac, cross); + bestA = VectorLength(cross); + } + + if(bestA < TINY_AREA) + /* the biggest triangle is degenerate - then every other is too, and the other algorithms wouldn't generate anything useful either */ + continue; + + i = 0; + indexes[i++] = bestR; + indexes[i++] = bestS; + indexes[i++] = bestT; + /* uses 3 */ + + /* identify the other fragments */ + + /* full polygon without triangle (bestR,bestS,bestT) = three new polygons: + * 1. bestR..bestS + * 2. bestS..bestT + * 3. bestT..bestR + */ + + j = MaxAreaIndexes(vert + bestR, bestS - bestR + 1, indexes + i); + if(j < 0) + continue; + j += i; + for(; i < j; ++i) + indexes[i] += bestR; + /* uses 3*(bestS-bestR+1)-6 */ + j = MaxAreaIndexes(vert + bestS, bestT - bestS + 1, indexes + i); + if(j < 0) + continue; + j += i; + for(; i < j; ++i) + indexes[i] += bestS; + /* uses 3*(bestT-bestS+1)-6 */ + + /* can'bestT recurse this one directly... therefore, buffering */ + if(cnt + bestR - bestT + 1 >= 3) + { + buf = safe_malloc(sizeof(*vert) * (cnt + bestR - bestT + 1)); + memcpy(buf, vert + bestT, sizeof(*vert) * (cnt - bestT)); + memcpy(buf + (cnt - bestT), vert, sizeof(*vert) * (bestR + 1)); + j = MaxAreaIndexes(buf, cnt + bestR - bestT + 1, indexes + i); + if(j < 0) + { + free(buf); + continue; + } + j += i; + for(; i < j; ++i) + indexes[i] = (indexes[i] + bestT) % cnt; + /* uses 3*(cnt+bestR-bestT+1)-6 */ + free(buf); + } + + /* together 3 + 3*(cnt+3) - 18 = 3*cnt-6 q.e.d. */ + return i; + } + + return -1; +} + +/* +MaxAreaFaceSurface() - divVerent +creates a triangle list using max area indexes +*/ + +void MaxAreaFaceSurface(mapDrawSurface_t *ds) +{ + int n; + /* try to early out */ + if( !ds->numVerts || (ds->type != SURFACE_FACE && ds->type != SURFACE_DECAL) ) + return; + + /* is this a simple triangle? */ + if( ds->numVerts == 3 ) + { + ds->numIndexes = 3; + ds->indexes = safe_malloc( ds->numIndexes * sizeof( int ) ); + VectorSet( ds->indexes, 0, 1, 2 ); + numMaxAreaSurfaces++; + return; + } + + /* do it! */ + ds->numIndexes = 3 * ds->numVerts - 6; + ds->indexes = safe_malloc( ds->numIndexes * sizeof( int ) ); + n = MaxAreaIndexes(ds->verts, ds->numVerts, ds->indexes); + if(n < 0) + { + /* whatever we do, it's degenerate */ + free(ds->indexes); + ds->numIndexes = 0; + StripFaceSurface(ds); + return; + } + ds->numIndexes = n; + + /* add to count */ + numMaxAreaSurfaces++; + + /* classify it */ + ClassifySurfaces( 1, ds ); +} /* @@ -536,6 +771,7 @@ void StripFaceSurface( mapDrawSurface_t *ds ) Error( "MAX_INDEXES exceeded for surface (%d > %d) (%d verts)", numIndexes, MAX_INDEXES, ds->numVerts ); /* try all possible orderings of the points looking for a non-degenerate strip order */ + ni = 0; for( r = 0; r < ds->numVerts; r++ ) { /* set rotation */ @@ -597,8 +833,24 @@ void StripFaceSurface( mapDrawSurface_t *ds ) /* classify it */ ClassifySurfaces( 1, ds ); } + + +/* +EmitMetaStatictics +vortex: prints meta statistics in general output +*/ - +void EmitMetaStats() +{ + Sys_Printf( "--- EmitMetaStats ---\n" ); + Sys_Printf( "%9d total meta surfaces\n", numMetaSurfaces ); + Sys_Printf( "%9d stripped surfaces\n", numStripSurfaces ); + Sys_Printf( "%9d fanned surfaces\n", numFanSurfaces ); + Sys_Printf( "%9d maxarea'd surfaces\n", numMaxAreaSurfaces ); + Sys_Printf( "%9d patch meta surfaces\n", numPatchMetaSurfaces ); + Sys_Printf( "%9d meta verts\n", numMetaVerts ); + Sys_Printf( "%9d meta triangles\n", numMetaTriangles ); +} /* MakeEntityMetaTriangles() @@ -647,17 +899,20 @@ void MakeEntityMetaTriangles( entity_t *e ) { case SURFACE_FACE: case SURFACE_DECAL: - StripFaceSurface( ds ); + if(maxAreaFaceSurface) + MaxAreaFaceSurface( ds ); + else + StripFaceSurface( ds ); SurfaceToMetaTriangles( ds ); break; case SURFACE_PATCH: - TriangulatePatchSurface( ds ); + TriangulatePatchSurface(e, ds ); break; case SURFACE_TRIANGLES: break; - + case SURFACE_FORCED_META: case SURFACE_META: SurfaceToMetaTriangles( ds ); @@ -676,6 +931,7 @@ void MakeEntityMetaTriangles( entity_t *e ) Sys_FPrintf( SYS_VRB, "%9d total meta surfaces\n", numMetaSurfaces ); Sys_FPrintf( SYS_VRB, "%9d stripped surfaces\n", numStripSurfaces ); Sys_FPrintf( SYS_VRB, "%9d fanned surfaces\n", numFanSurfaces ); + Sys_FPrintf( SYS_VRB, "%9d maxarea'd surfaces\n", numMaxAreaSurfaces ); Sys_FPrintf( SYS_VRB, "%9d patch meta surfaces\n", numPatchMetaSurfaces ); Sys_FPrintf( SYS_VRB, "%9d meta verts\n", numMetaVerts ); Sys_FPrintf( SYS_VRB, "%9d meta triangles\n", numMetaTriangles ); @@ -686,50 +942,6 @@ void MakeEntityMetaTriangles( entity_t *e ) -/* -PointTriangleIntersect() -assuming that all points lie in plane, determine if pt -is inside the triangle abc -code originally (c) 2001 softSurfer (www.softsurfer.com) -*/ - -#define MIN_OUTSIDE_EPSILON -0.01f -#define MAX_OUTSIDE_EPSILON 1.01f - -static qboolean PointTriangleIntersect( vec3_t pt, vec4_t plane, vec3_t a, vec3_t b, vec3_t c, vec3_t bary ) -{ - vec3_t u, v, w; - float uu, uv, vv, wu, wv, d; - - - /* make vectors */ - VectorSubtract( b, a, u ); - VectorSubtract( c, a, v ); - VectorSubtract( pt, a, w ); - - /* more setup */ - uu = DotProduct( u, u ); - uv = DotProduct( u, v ); - vv = DotProduct( v, v ); - wu = DotProduct( w, u ); - wv = DotProduct( w, v ); - d = uv * uv - uu * vv; - - /* calculate barycentric coordinates */ - bary[ 1 ] = (uv * wv - vv * wu) / d; - if( bary[ 1 ] < MIN_OUTSIDE_EPSILON || bary[ 1 ] > MAX_OUTSIDE_EPSILON ) - return qfalse; - bary[ 2 ] = (uv * wv - uu * wv) / d; - if( bary[ 2 ] < MIN_OUTSIDE_EPSILON || bary[ 2 ] > MAX_OUTSIDE_EPSILON ) - return qfalse; - bary[ 0 ] = 1.0f - (bary[ 1 ] + bary[ 2 ]); - - /* point is in triangle */ - return qtrue; -} - - - /* CreateEdge() sets up an edge structure from a plane and 2 points that the edge ab falls lies in @@ -835,10 +1047,6 @@ void FixMetaTJunctions( void ) /* get vert */ VectorCopy( metaVerts[ j ].xyz, pt ); - /* debug code: darken verts */ - if( i == 0 ) - VectorSet( metaVerts[ j ].color[ 0 ], 8, 8, 8 ); - /* determine if point lies in the triangle's plane */ dist = DotProduct( pt, plane ) - plane[ 3 ]; if( fabs( dist ) > TJ_PLANE_EPSILON ) @@ -879,13 +1087,6 @@ void FixMetaTJunctions( void ) amount = dist / edges[ k ].length; #endif - /* debug code: brighten this point */ - //% metaVerts[ j ].color[ 0 ][ 0 ] += 5; - //% metaVerts[ j ].color[ 0 ][ 1 ] += 4; - VectorSet( metaVerts[ tri->indexes[ k ] ].color[ 0 ], 255, 204, 0 ); - VectorSet( metaVerts[ tri->indexes[ (k + 1) % 3 ] ].color[ 0 ], 255, 204, 0 ); - - /* the edge opposite the zero-weighted vertex was hit, so use that as an amount */ a = &metaVerts[ tri->indexes[ k % 3 ] ]; b = &metaVerts[ tri->indexes[ (k + 1) % 3 ] ]; @@ -973,7 +1174,6 @@ void SmoothMetaTriangles( void ) int indexes[ MAX_SAMPLES ]; vec3_t votes[ MAX_SAMPLES ]; - /* note it */ Sys_FPrintf( SYS_VRB, "--- SmoothMetaTriangles ---\n" ); @@ -994,11 +1194,18 @@ void SmoothMetaTriangles( void ) and set per-vertex smoothing angle */ for( i = 0, tri = &metaTriangles[ i ]; i < numMetaTriangles; i++, tri++ ) { - /* get shader for shade angle */ + shadeAngle = defaultShadeAngle; + + /* get shade angle from shader */ if( tri->si->shadeAngleDegrees > 0.0f ) shadeAngle = DEG2RAD( tri->si->shadeAngleDegrees ); - else + /* get shade angle from entity */ + else if( tri->shadeAngleDegrees > 0.0f ) + shadeAngle = DEG2RAD( tri->shadeAngleDegrees ); + + if( shadeAngle <= 0.0f ) shadeAngle = defaultShadeAngle; + if( shadeAngle > maxShadeAngle ) maxShadeAngle = shadeAngle; @@ -1186,8 +1393,9 @@ returns the score of the triangle added #define ST_SCORE2 (2 * (ST_SCORE)) #define ADEQUATE_SCORE ((AXIS_MIN) + 1 * (VERT_SCORE)) -#define GOOD_SCORE ((AXIS_MIN) + 2 * (VERT_SCORE) + 4 * (ST_SCORE)) -#define PERFECT_SCORE ((AXIS_MIN) + + 3 * (VERT_SCORE) + (SURFACE_SCORE) + 4 * (ST_SCORE)) +#define GOOD_SCORE ((AXIS_MIN) + 2 * (VERT_SCORE) + 4 * (ST_SCORE)) +#define PERFECT_SCORE ((AXIS_MIN) + 3 * (VERT_SCORE) + (SURFACE_SCORE) + 4 * (ST_SCORE)) +//#define MAX_BBOX_DISTANCE 16 static int AddMetaTriangleToSurface( mapDrawSurface_t *ds, metaTriangle_t *tri, qboolean testAdd ) { @@ -1224,6 +1432,32 @@ static int AddMetaTriangleToSurface( mapDrawSurface_t *ds, metaTriangle_t *tri, if( tri->planeNum >= 0 && tri->planeNum != ds->planeNum ) return 0; } + +#if MAX_BBOX_DISTANCE > 0 + VectorCopy( ds->mins, mins ); + VectorCopy( ds->maxs, maxs ); + mins[0] -= MAX_BBOX_DISTANCE; + mins[1] -= MAX_BBOX_DISTANCE; + mins[2] -= MAX_BBOX_DISTANCE; + maxs[0] += MAX_BBOX_DISTANCE; + maxs[1] += MAX_BBOX_DISTANCE; + maxs[2] += MAX_BBOX_DISTANCE; +#define CHECK_1D(mins, v, maxs) ((mins) <= (v) && (v) <= (maxs)) +#define CHECK_3D(mins, v, maxs) (CHECK_1D((mins)[0], (v)[0], (maxs)[0]) && CHECK_1D((mins)[1], (v)[1], (maxs)[1]) && CHECK_1D((mins)[2], (v)[2], (maxs)[2])) + VectorCopy(metaVerts[ tri->indexes[ 0 ] ].xyz, p); + if(!CHECK_3D(mins, p, maxs)) + { + VectorCopy(metaVerts[ tri->indexes[ 1 ] ].xyz, p); + if(!CHECK_3D(mins, p, maxs)) + { + VectorCopy(metaVerts[ tri->indexes[ 2 ] ].xyz, p); + if(!CHECK_3D(mins, p, maxs)) + return 0; + } + } +#undef CHECK_3D +#undef CHECK_1D +#endif /* set initial score */ score = tri->surfaceNum == ds->surfaceNum ? SURFACE_SCORE : 0; @@ -1422,6 +1656,7 @@ static void MetaTrianglesToSurface( int numPossibles, metaTriangle_t *possibles, ds->planeNum = seed->planeNum; ds->fogNum = seed->fogNum; ds->sampleSize = seed->sampleSize; + ds->shadeAngleDegrees = seed->shadeAngleDegrees; ds->verts = verts; ds->indexes = indexes; VectorCopy( seed->lightmapAxis, ds->lightmapAxis ); @@ -1529,37 +1764,37 @@ static int CompareMetaTriangles( const void *a, const void *b ) /* shader first */ - if( ((metaTriangle_t*) a)->si < ((metaTriangle_t*) b)->si ) + if( ((const metaTriangle_t*) a)->si < ((const metaTriangle_t*) b)->si ) return 1; - else if( ((metaTriangle_t*) a)->si > ((metaTriangle_t*) b)->si ) + else if( ((const metaTriangle_t*) a)->si > ((const metaTriangle_t*) b)->si ) return -1; /* then fog */ - else if( ((metaTriangle_t*) a)->fogNum < ((metaTriangle_t*) b)->fogNum ) + else if( ((const metaTriangle_t*) a)->fogNum < ((const metaTriangle_t*) b)->fogNum ) return 1; - else if( ((metaTriangle_t*) a)->fogNum > ((metaTriangle_t*) b)->fogNum ) + else if( ((const metaTriangle_t*) a)->fogNum > ((const metaTriangle_t*) b)->fogNum ) return -1; /* then plane */ #if 0 - else if( npDegrees == 0.0f && ((metaTriangle_t*) a)->si->nonplanar == qfalse && - ((metaTriangle_t*) a)->planeNum >= 0 && ((metaTriangle_t*) a)->planeNum >= 0 ) + else if( npDegrees == 0.0f && ((const metaTriangle_t*) a)->si->nonplanar == qfalse && + ((const metaTriangle_t*) a)->planeNum >= 0 && ((const metaTriangle_t*) a)->planeNum >= 0 ) { - if( ((metaTriangle_t*) a)->plane[ 3 ] < ((metaTriangle_t*) b)->plane[ 3 ] ) + if( ((const metaTriangle_t*) a)->plane[ 3 ] < ((const metaTriangle_t*) b)->plane[ 3 ] ) return 1; - else if( ((metaTriangle_t*) a)->plane[ 3 ] > ((metaTriangle_t*) b)->plane[ 3 ] ) + else if( ((const metaTriangle_t*) a)->plane[ 3 ] > ((const metaTriangle_t*) b)->plane[ 3 ] ) return -1; - else if( ((metaTriangle_t*) a)->plane[ 0 ] < ((metaTriangle_t*) b)->plane[ 0 ] ) + else if( ((const metaTriangle_t*) a)->plane[ 0 ] < ((const metaTriangle_t*) b)->plane[ 0 ] ) return 1; - else if( ((metaTriangle_t*) a)->plane[ 0 ] > ((metaTriangle_t*) b)->plane[ 0 ] ) + else if( ((const metaTriangle_t*) a)->plane[ 0 ] > ((const metaTriangle_t*) b)->plane[ 0 ] ) return -1; - else if( ((metaTriangle_t*) a)->plane[ 1 ] < ((metaTriangle_t*) b)->plane[ 1 ] ) + else if( ((const metaTriangle_t*) a)->plane[ 1 ] < ((const metaTriangle_t*) b)->plane[ 1 ] ) return 1; - else if( ((metaTriangle_t*) a)->plane[ 1 ] > ((metaTriangle_t*) b)->plane[ 1 ] ) + else if( ((const metaTriangle_t*) a)->plane[ 1 ] > ((const metaTriangle_t*) b)->plane[ 1 ] ) return -1; - else if( ((metaTriangle_t*) a)->plane[ 2 ] < ((metaTriangle_t*) b)->plane[ 2 ] ) + else if( ((const metaTriangle_t*) a)->plane[ 2 ] < ((const metaTriangle_t*) b)->plane[ 2 ] ) return 1; - else if( ((metaTriangle_t*) a)->plane[ 2 ] > ((metaTriangle_t*) b)->plane[ 2 ] ) + else if( ((const metaTriangle_t*) a)->plane[ 2 ] > ((const metaTriangle_t*) b)->plane[ 2 ] ) return -1; } #endif @@ -1571,8 +1806,8 @@ static int CompareMetaTriangles( const void *a, const void *b ) VectorSet( bMins, 999999, 999999, 999999 ); for( i = 0; i < 3; i++ ) { - av = ((metaTriangle_t*) a)->indexes[ i ]; - bv = ((metaTriangle_t*) b)->indexes[ i ]; + av = ((const metaTriangle_t*) a)->indexes[ i ]; + bv = ((const metaTriangle_t*) b)->indexes[ i ]; for( j = 0; j < 3; j++ ) { if( metaVerts[ av ].xyz[ j ] < aMins[ j ] ) diff --git a/tools/quake3/q3map2/tjunction.c b/tools/quake3/q3map2/tjunction.c index d728c185..cde7ece4 100644 --- a/tools/quake3/q3map2/tjunction.c +++ b/tools/quake3/q3map2/tjunction.c @@ -55,7 +55,7 @@ typedef struct edgeLine_s { vec3_t origin; vec3_t dir; - edgePoint_t chain; // unused element of doubly linked list + edgePoint_t *chain; // unused element of doubly linked list } edgeLine_t; typedef struct { @@ -63,14 +63,14 @@ typedef struct { bspDrawVert_t *dv[2]; } originalEdge_t; -#define MAX_ORIGINAL_EDGES 0x20000 -originalEdge_t originalEdges[MAX_ORIGINAL_EDGES]; +originalEdge_t *originalEdges = NULL; int numOriginalEdges; +int allocatedOriginalEdges = 0; -#define MAX_EDGE_LINES 0x10000 -edgeLine_t edgeLines[MAX_EDGE_LINES]; +edgeLine_t *edgeLines = NULL; int numEdgeLines; +int allocatedEdgeLines = 0; int c_degenerateEdges; int c_addedVerts; @@ -100,14 +100,14 @@ void InsertPointOnEdge( vec3_t v, edgeLine_t *e ) { p->intercept = d; VectorCopy( v, p->xyz ); - if ( e->chain.next == &e->chain ) { - e->chain.next = e->chain.prev = p; - p->next = p->prev = &e->chain; + if ( e->chain->next == e->chain ) { + e->chain->next = e->chain->prev = p; + p->next = p->prev = e->chain; return; } - scan = e->chain.next; - for ( ; scan != &e->chain ; scan = scan->next ) { + scan = e->chain->next; + for ( ; scan != e->chain ; scan = scan->next ) { d = p->intercept - scan->intercept; if ( d > -LINE_POSITION_EPSILON && d < LINE_POSITION_EPSILON ) { free( p ); @@ -153,9 +153,7 @@ int AddEdge( vec3_t v1, vec3_t v2, qboolean createNonAxial ) { if ( !createNonAxial ) { if ( fabs( dir[0] + dir[1] + dir[2] ) != 1.0 ) { - if ( numOriginalEdges == MAX_ORIGINAL_EDGES ) { - Error( "MAX_ORIGINAL_EDGES" ); - } + AUTOEXPAND_BY_REALLOC(originalEdges, numOriginalEdges, allocatedOriginalEdges, 1024); originalEdges[ numOriginalEdges ].dv[0] = (bspDrawVert_t *)v1; originalEdges[ numOriginalEdges ].dv[1] = (bspDrawVert_t *)v2; originalEdges[ numOriginalEdges ].length = d; @@ -192,14 +190,13 @@ int AddEdge( vec3_t v1, vec3_t v2, qboolean createNonAxial ) { } // create a new edge - if ( numEdgeLines >= MAX_EDGE_LINES ) { - Error( "MAX_EDGE_LINES" ); - } + AUTOEXPAND_BY_REALLOC(edgeLines, numEdgeLines, allocatedEdgeLines, 1024); e = &edgeLines[ numEdgeLines ]; numEdgeLines++; - e->chain.next = e->chain.prev = &e->chain; + e->chain = safe_malloc( sizeof(edgePoint_t) ); + e->chain->next = e->chain->prev = e->chain; VectorCopy( v1, e->origin ); VectorCopy( dir, e->dir ); @@ -377,12 +374,12 @@ void FixSurfaceJunctions( mapDrawSurface_t *ds ) { if ( start < end ) { - p = e->chain.next; + p = e->chain->next; } else { - p = e->chain.prev; + p = e->chain->prev; } - for ( ; p != &e->chain ; ) { + for ( ; p != e->chain ; ) { if ( start < end ) { if ( p->intercept > end - ON_EPSILON ) { break; @@ -519,7 +516,6 @@ int c_broken = 0; qboolean FixBrokenSurface( mapDrawSurface_t *ds ) { - qboolean valid = qtrue; bspDrawVert_t *dv1, *dv2, avg; int i, j, k; float dist; @@ -534,10 +530,6 @@ qboolean FixBrokenSurface( mapDrawSurface_t *ds ) /* check all verts */ for( i = 0; i < ds->numVerts; i++ ) { - /* don't remove points if winding is a triangle */ - if( ds->numVerts == 3 ) - return valid; - /* get verts */ dv1 = &ds->verts[ i ]; dv2 = &ds->verts[ (i + 1) % ds->numVerts ]; @@ -547,7 +539,6 @@ qboolean FixBrokenSurface( mapDrawSurface_t *ds ) dist = VectorLength( avg.xyz ); if( dist < DEGENERATE_EPSILON ) { - valid = qfalse; Sys_FPrintf( SYS_VRB, "WARNING: Degenerate T-junction edge found, fixing...\n" ); /* create an average drawvert */ @@ -581,13 +572,16 @@ qboolean FixBrokenSurface( mapDrawSurface_t *ds ) memcpy( dv2, dv1, sizeof( bspDrawVert_t ) ); } ds->numVerts--; + + /* after welding, we have to consider the same vertex again, as it now has a new neighbor dv2 */ + --i; + + /* should ds->numVerts have become 0, then i is now -1. In the next iteration, the loop will abort. */ } } /* one last check and return */ - if( ds->numVerts < 3 ) - valid = qfalse; - return valid; + return ds->numVerts >= 3; } @@ -606,8 +600,8 @@ EdgeCompare int EdgeCompare( const void *elem1, const void *elem2 ) { float d1, d2; - d1 = ((originalEdge_t *)elem1)->length; - d2 = ((originalEdge_t *)elem2)->length; + d1 = ((const originalEdge_t *)elem1)->length; + d2 = ((const originalEdge_t *)elem2)->length; if ( d1 < d2 ) { return -1; @@ -632,7 +626,7 @@ void FixTJunctions( entity_t *ent ) shaderInfo_t *si; int axialEdgeLines; originalEdge_t *e; - + bspDrawVert_t *dv; /* meta mode has its own t-junction code (currently not as good as this code) */ //% if( meta ) @@ -683,7 +677,8 @@ void FixTJunctions( entity_t *ent ) // this gives the most accurate edge description for ( i = 0 ; i < numOriginalEdges ; i++ ) { e = &originalEdges[i]; - e->dv[ 0 ]->lightmap[ 0 ][ 0 ] = AddEdge( e->dv[ 0 ]->xyz, e->dv[ 1 ]->xyz, qtrue ); + dv = e->dv[0]; // e might change during AddEdge + dv->lightmap[ 0 ][ 0 ] = AddEdge( e->dv[ 0 ]->xyz, e->dv[ 1 ]->xyz, qtrue ); } Sys_FPrintf( SYS_VRB, "%9d axial edge lines\n", axialEdgeLines ); diff --git a/tools/quake3/q3map2/vis.c b/tools/quake3/q3map2/vis.c index 4ee843a0..b9291922 100644 --- a/tools/quake3/q3map2/vis.c +++ b/tools/quake3/q3map2/vis.c @@ -102,9 +102,9 @@ the earlier information. */ int PComp (const void *a, const void *b) { - if ( (*(vportal_t **)a)->nummightsee == (*(vportal_t **)b)->nummightsee) + if ( (*(const vportal_t *const *)a)->nummightsee == (*(const vportal_t *const *)b)->nummightsee) return 0; - if ( (*(vportal_t **)a)->nummightsee < (*(vportal_t **)b)->nummightsee) + if ( (*(const vportal_t *const *)a)->nummightsee < (*(const vportal_t *const *)b)->nummightsee) return -1; return 1; } @@ -167,6 +167,7 @@ ClusterMerge Merges the portal visibility for a leaf =============== */ +static int clustersizehistogram[MAX_MAP_LEAFS] = {0}; void ClusterMerge (int leafnum) { leaf_t *leaf; @@ -212,9 +213,8 @@ void ClusterMerge (int leafnum) numvis++; // count the leaf itself - totalvis += numvis; - - Sys_FPrintf (SYS_VRB,"cluster %4i : %4i visible\n", leafnum, numvis); + //Sys_FPrintf (SYS_VRB,"cluster %4i : %4i visible\n", leafnum, numvis); + ++clustersizehistogram[numvis]; memcpy (bspVisBytes + VIS_HEADER_SIZE + leafnum*leafbytes, uncompressed, leafbytes); } @@ -310,8 +310,9 @@ CalcVis */ void CalcVis (void) { - int i; + int i, minvis, maxvis; const char *value; + double mu, sigma, totalvis, totalvis2; /* ydnar: rr2do2's farplane code */ @@ -357,9 +358,34 @@ void CalcVis (void) Sys_Printf("creating leaf vis...\n"); for (i=0 ; i MAX_PORTALS) + Error("MAX_PORTALS"); // these counts should take advantage of 64 bit systems automatically leafbytes = ((portalclusters+63)&~63)>>3; @@ -903,8 +932,8 @@ void LoadPortals (char *name) Error ("LoadPortals: reading portal %i", i); if (numpoints > MAX_POINTS_ON_WINDING) Error ("LoadPortals: portal %i has too many points", i); - if ( (unsigned)leafnums[0] > portalclusters - || (unsigned)leafnums[1] > portalclusters) + if (leafnums[0] > portalclusters + || leafnums[1] > portalclusters) Error ("LoadPortals: reading portal %i", i); if (fscanf (f, "%i ", &hint) != 1) Error ("LoadPortals: reading hint state"); @@ -925,7 +954,10 @@ void LoadPortals (char *name) for (k=0 ; k<3 ; k++) w->points[j][k] = v[k]; } - fscanf (f, "\n"); + if(fscanf (f, "\n") != 0) + { + // silence gcc warning + } // calc plane PlaneFromWinding (w, &plane); @@ -996,7 +1028,10 @@ void LoadPortals (char *name) for (k=0 ; k<3 ; k++) w->points[j][k] = v[k]; } - fscanf (f, "\n"); + if(fscanf (f, "\n") != 0) + { + // silence gcc warning + } // calc plane PlaneFromWinding (w, &plane); @@ -1046,6 +1081,9 @@ int VisMain (int argc, char **argv) } else if (!strcmp(argv[i], "-merge")) { Sys_Printf ("merge = true\n"); mergevis = qtrue; + } else if (!strcmp(argv[i], "-mergeportals")) { + Sys_Printf ("mergeportals = true\n"); + mergevisportals = qtrue; } else if (!strcmp(argv[i], "-nopassage")) { Sys_Printf ("nopassage = true\n"); noPassageVis = qtrue; @@ -1058,6 +1096,9 @@ int VisMain (int argc, char **argv) } else if (!strcmp (argv[i],"-saveprt")) { Sys_Printf ("saveprt = true\n"); saveprt = qtrue; + } else if( !strcmp( argv[ i ], "-v" ) ) { + debugCluster = qtrue; + Sys_Printf( "Extra verbous mode enabled\n" ); } else if (!strcmp (argv[i],"-tmpin")) { strcpy (inbase, "/tmp"); } else if (!strcmp (argv[i],"-tmpout")) { @@ -1074,7 +1115,9 @@ int VisMain (int argc, char **argv) } else + { Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] ); + } } if( i != argc - 1 ) @@ -1105,11 +1148,15 @@ int VisMain (int argc, char **argv) /* ydnar: for getting far plane */ ParseEntities(); + /* inject command line parameters */ + InjectCommandLine(argv, 0, argc - 1); + UnparseEntities(); + if( mergevis ) - { MergeLeaves(); + + if( mergevis || mergevisportals ) MergeLeafPortals(); - } CountActivePortals(); /* WritePortals( "maps/hints.prs" );*/ diff --git a/tools/quake3/q3map2/writebsp.c b/tools/quake3/q3map2/writebsp.c index 4cdd3a99..2e6e67a0 100644 --- a/tools/quake3/q3map2/writebsp.c +++ b/tools/quake3/q3map2/writebsp.c @@ -66,13 +66,15 @@ int EmitShader( const char *shader, int *contentFlags, int *surfaceFlags ) if( !Q_stricmp( shader, bspShaders[ i ].shader ) ) return i; } + + // i == numBSPShaders /* get shaderinfo */ si = ShaderInfoForShader( shader ); /* emit a new shader */ - if( i == MAX_MAP_SHADERS ) - Error( "MAX_MAP_SHADERS" ); + AUTOEXPAND_BY_REALLOC_BSP(Shaders, 1024); + numBSPShaders++; strcpy( bspShaders[ i ].shader, shader ); bspShaders[ i ].surfaceFlags = si->surfaceFlags; @@ -114,6 +116,7 @@ void EmitPlanes( void ) mp = mapplanes; for( i = 0; i < nummapplanes; i++, mp++ ) { + AUTOEXPAND_BY_REALLOC_BSP(Planes, 1024); bp = &bspPlanes[ numBSPPlanes ]; VectorCopy( mp->normal, bp->normal ); bp->dist = mp->dist; @@ -165,8 +168,7 @@ void EmitLeaf( node_t *node ) //% if( b->guard != 0xDEADBEEF ) //% Sys_Printf( "Brush %6d: 0x%08X Guard: 0x%08X Next: 0x%08X Original: 0x%08X Sides: %d\n", b->brushNum, b, b, b->next, b->original, b->numsides ); - if( numBSPLeafBrushes >= MAX_MAP_LEAFBRUSHES ) - Error( "MAX_MAP_LEAFBRUSHES" ); + AUTOEXPAND_BY_REALLOC_BSP(LeafBrushes, 1024); bspLeafBrushes[ numBSPLeafBrushes ] = b->original->outputNum; numBSPLeafBrushes++; } @@ -181,8 +183,7 @@ void EmitLeaf( node_t *node ) leaf_p->firstBSPLeafSurface = numBSPLeafSurfaces; for ( dsr = node->drawSurfReferences; dsr; dsr = dsr->nextRef ) { - if( numBSPLeafSurfaces >= MAX_MAP_LEAFFACES ) - Error( "MAX_MAP_LEAFFACES" ); + AUTOEXPAND_BY_REALLOC_BSP(LeafSurfaces, 1024); bspLeafSurfaces[ numBSPLeafSurfaces ] = dsr->outputNum; numBSPLeafSurfaces++; } @@ -199,7 +200,7 @@ recursively emit the bsp nodes int EmitDrawNode_r( node_t *node ) { bspNode_t *n; - int i; + int i, n0; /* check for leafnode */ @@ -210,9 +211,9 @@ int EmitDrawNode_r( node_t *node ) } /* emit a node */ - if( numBSPNodes == MAX_MAP_NODES ) - Error( "MAX_MAP_NODES" ); - n = &bspNodes[ numBSPNodes ]; + AUTOEXPAND_BY_REALLOC_BSP(Nodes, 1024); + n0 = numBSPNodes; + n = &bspNodes[ n0 ]; numBSPNodes++; VectorCopy (node->mins, n->mins); @@ -236,6 +237,8 @@ int EmitDrawNode_r( node_t *node ) { n->children[i] = numBSPNodes; EmitDrawNode_r (node->children[i]); + // n may have become invalid here, so... + n = &bspNodes[ n0 ]; } } @@ -277,18 +280,19 @@ sets style keys for entity lights void SetLightStyles( void ) { int i, j, style, numStyles; - qboolean keepLights; const char *t; entity_t *e; epair_t *ep, *next; char value[ 10 ]; char lightTargets[ MAX_SWITCHED_LIGHTS ][ 64 ]; int lightStyles[ MAX_SWITCHED_LIGHTS ]; - - + /* ydnar: determine if we keep lights in the bsp */ - t = ValueForKey( &entities[ 0 ], "_keepLights" ); - keepLights = (t[ 0 ] == '1') ? qtrue : qfalse; + if (KeyExists(&entities[ 0 ], "_keepLights") == qtrue) + { + t = ValueForKey( &entities[ 0 ], "_keepLights" ); + keepLights = (t[ 0 ] == '1') ? qtrue : qfalse; + } /* any light that is controlled (has a targetname) must have a unique style number generated for it */ numStyles = 0; @@ -395,7 +399,7 @@ EndBSPFile() finishes a new bsp and writes to disk */ -void EndBSPFile( void ) +void EndBSPFile(qboolean do_write) { char path[ 1024 ]; @@ -407,13 +411,16 @@ void EndBSPFile( void ) numBSPEntities = numEntities; UnparseEntities(); - /* write the surface extra file */ - WriteSurfaceExtraFile( source ); - - /* write the bsp */ - sprintf( path, "%s.bsp", source ); - Sys_Printf( "Writing %s\n", path ); - WriteBSPFile( path ); + if(do_write) + { + /* write the surface extra file */ + WriteSurfaceExtraFile( source ); + + /* write the bsp */ + sprintf( path, "%s.bsp", source ); + Sys_Printf( "Writing %s\n", path ); + WriteBSPFile( path ); + } } @@ -441,8 +448,7 @@ void EmitBrushes( brush_t *brushes, int *firstBrush, int *numBrushes ) for( b = brushes; b != NULL; b = b->next ) { /* check limits */ - if( numBSPBrushes == MAX_MAP_BRUSHES ) - Error( "MAX_MAP_BRUSHES (%d)", numBSPBrushes ); + AUTOEXPAND_BY_REALLOC_BSP(Brushes, 1024); /* get bsp brush */ b->outputNum = numBSPBrushes; @@ -462,8 +468,7 @@ void EmitBrushes( brush_t *brushes, int *firstBrush, int *numBrushes ) b->sides[ j ].outputNum = -1; /* check count */ - if( numBSPBrushSides == MAX_MAP_BRUSHSIDES ) - Error( "MAX_MAP_BRUSHSIDES "); + AUTOEXPAND_BY_REALLOC_BSP(BrushSides, 1024); /* emit side */ b->sides[ j ].outputNum = numBSPBrushSides; @@ -553,8 +558,7 @@ void BeginModel( void ) /* test limits */ - if( numBSPModels == MAX_MAP_MODELS ) - Error( "MAX_MAP_MODELS" ); + AUTOEXPAND_BY_REALLOC_BSP(Models, 256); /* get model and entity */ mod = &bspModels[ numBSPModels ]; -- 2.39.2