]> git.xonotic.org Git - xonotic/netradiant.git/commitdiff
use q3map2 from NetRadiant (VOLUNTEERS: split this commit into functional parts!) divVerent/zeroradiant-split-up-the-q3map2-commit-goal
authorRudolf Polzer <divverent@alientrap.org>
Wed, 23 Feb 2011 10:12:03 +0000 (11:12 +0100)
committerRudolf Polzer <divverent@alientrap.org>
Wed, 23 Feb 2011 10:12:03 +0000 (11:12 +0100)
54 files changed:
tools/quake3/q3map2/brush.c
tools/quake3/q3map2/bsp.c
tools/quake3/q3map2/bspfile_abstract.c
tools/quake3/q3map2/bspfile_ibsp.c
tools/quake3/q3map2/bspfile_rbsp.c
tools/quake3/q3map2/convert_ase.c
tools/quake3/q3map2/convert_map.c
tools/quake3/q3map2/convert_obj.c [new file with mode: 0644]
tools/quake3/q3map2/decals.c
tools/quake3/q3map2/facebsp.c
tools/quake3/q3map2/game__null.h [new file with mode: 0644]
tools/quake3/q3map2/game_darkplaces.h [new file with mode: 0644]
tools/quake3/q3map2/game_dq.h [new file with mode: 0644]
tools/quake3/q3map2/game_ef.h
tools/quake3/q3map2/game_etut.h
tools/quake3/q3map2/game_ja.h
tools/quake3/q3map2/game_jk2.h
tools/quake3/q3map2/game_nexuiz.h
tools/quake3/q3map2/game_prophecy.h [new file with mode: 0644]
tools/quake3/q3map2/game_qfusion.h
tools/quake3/q3map2/game_quake3.h
tools/quake3/q3map2/game_quakelive.h
tools/quake3/q3map2/game_reaction.h
tools/quake3/q3map2/game_sof2.h
tools/quake3/q3map2/game_tenebrae.h
tools/quake3/q3map2/game_tremulous.h
tools/quake3/q3map2/game_wolf.h
tools/quake3/q3map2/game_wolfet.h
tools/quake3/q3map2/game_xonotic.h [new file with mode: 0644]
tools/quake3/q3map2/image.c
tools/quake3/q3map2/leakfile.c
tools/quake3/q3map2/light.c
tools/quake3/q3map2/light_bounce.c
tools/quake3/q3map2/light_trace.c
tools/quake3/q3map2/light_ydnar.c
tools/quake3/q3map2/lightmaps.c
tools/quake3/q3map2/lightmaps_ydnar.c
tools/quake3/q3map2/main.c
tools/quake3/q3map2/map.c
tools/quake3/q3map2/model.c
tools/quake3/q3map2/patch.c
tools/quake3/q3map2/path_init.c
tools/quake3/q3map2/portals.c
tools/quake3/q3map2/prtfile.c
tools/quake3/q3map2/q3map2.h
tools/quake3/q3map2/q3map2.rc
tools/quake3/q3map2/shaders.c
tools/quake3/q3map2/surface.c
tools/quake3/q3map2/surface_extra.c
tools/quake3/q3map2/surface_foliage.c
tools/quake3/q3map2/surface_meta.c
tools/quake3/q3map2/tjunction.c
tools/quake3/q3map2/vis.c
tools/quake3/q3map2/writebsp.c

index 1093be3b4a11d49c58f6a7b52940c0b846191828..b7c50f4c3348a998a674aca65af4b14dfadc5f76 100644 (file)
@@ -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
index 3a16b0c22f645d189623cdd0c5172de04c535822..7901979237dc0b8bfc7a676e15d33e3f26410dcd 100644 (file)
@@ -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)
index 31b6f171bd4a425d9fe586ada8b2e122ed62ab5b..ef78160f737ad15bd9e35586f09f33aafd53f54e 100644 (file)
@@ -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;
+               }
+       }
 }
 
index 26fc56dcdfbb3cc135f62cff9627ac4dbc5a9cce..77ffd704a747586e705744b26e1bff89b1b4b10e 100644 (file)
@@ -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 );
 
index 74d77ae9f67a8519c6780a26c30596c82c006fec..79f177ea81d2a5ff8b0f80fd0d70afcd96815a5c 100644 (file)
@@ -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 );
        
index 2be25a4357b991f39cfa5f3eda8ba75881acfece..56262311b77bcd124ffeea19d836ce742a38b77d 100644 (file)
@@ -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" );
        
index 1fabbc6366216bffaca73ceb8d1a62c3e7352d0b..0f37665d672aef5ba8136d2d23bed45416db7c02 100644 (file)
@@ -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 (file)
index 0000000..08e75e1
--- /dev/null
@@ -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;
+}
+
+
+
index f4de7cea8da3de3aa974d87ad17cdef56569ec91..a130334f57b98d64917b01cbac852c8f71f33e2a 100644 (file)
@@ -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 ) );
index 270eefe280014c415b15031a73ed1b331834a0f9..9291f5649fc8dc63decd9e77f6e7293b2d60f815 100644 (file)
@@ -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 (file)
index 0000000..c2f2484
--- /dev/null
@@ -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 (file)
index 0000000..e91fdb7
--- /dev/null
@@ -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 (file)
index 0000000..97d2d6d
--- /dev/null
@@ -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
+
index f8d21d1a59ef0629dd9baa69d3bd38b420ff9dc0..84ea664cb5d0ca06eb688e4e08991fc88b712f3d 100644 (file)
@@ -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 */
index 9823ff96dd42cc51e0efc6cd2da7451a2be60cdf..8add5bbe09a78a221559536d92ce5309d5809bc9 100644 (file)
@@ -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 */
index 79007ed67508158ef08a150ee2d22bdb9daf8809..3d25129edffe929a85cde8698d0036de7a68862b 100644 (file)
@@ -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 */
index a8dc01a079d02a176f76282e12de799b97ba67fd..056baf015bfb64e18f01956146a0590c733ede1e 100644 (file)
@@ -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 */
index 0d23766db339921c9aa590724592d5847fda3b4e..4d496c339c25993b6375018525936ee2791069ac 100644 (file)
@@ -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 (file)
index 0000000..60e299d
--- /dev/null
@@ -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
+
index 43c27fc5dded0c62f48cbf29b4243e429a2fe13f..7645ad0a384556939af78e8a8c41a43c8fcae43a 100644 (file)
@@ -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 */
index be1f3397acc1eac35e7d16b9e7992a846afa6fc2..98d4c4b8245c1481e76211a853853abbc253d761 100644 (file)
@@ -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 */
index 18fd90f3beb166f1bbfeaefe8104608dca8ca5f8..1a509272b3a80c88ca9408485d64ac0046da33ca 100644 (file)
@@ -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 */
index 22e3e8ef284f6f6980a52e34e691c8edb340ad73..c81e72455563f8694f840abf072c5ccf0643f954 100644 (file)
@@ -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 */
index c97603928e8a26c796850e3924d2f93f87a09300..931ec69c640c47e96e12ab88826afe4e6b79d4c4 100644 (file)
@@ -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 */
index 355c926338cd5ee1ee9f60e9a88cc50241206c67..ab3121587f4dbc4a38011bc9081b6a906785dbae 100644 (file)
@@ -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 */
index 9864cb9c87525933e63e32466b456dc25a62f8aa..5d4226291883e4693e3ec9a83dfa09fb25cec7e9 100644 (file)
@@ -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 */
index 3200d162fecc06fb1ce428d5e3f6823ff7d0f384..157bfe3ae8897570b1413f336b3e9be5de121448 100644 (file)
@@ -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 */
index a6ca181f5b2debbd0fa79757c00f9cc426d8773e..3495f0dcfc6ba67ab4a220ac05251f70fd446c3e 100644 (file)
@@ -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 (file)
index 0000000..568c263
--- /dev/null
@@ -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
+
index 0ddcaf86bc59e556fa7d3e2cb5127a95dfdf1b00..0289e77c826bf662c45d95ec4b12e0952515e0f1 100644 (file)
@@ -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;
        
        
index 51fda30021cea41edcbe2bad23bcd87ee88a3898..fc5a3191fb38ce206fba405d98450bd414e15952 100644 (file)
@@ -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
index 8520edd7f14de21054545009f09705ce4d5f1c6b..9323b8c8e3b7a4430244b7b6c12354b92466c6df 100644 (file)
@@ -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 */
index dba5b131500c0390a09b4fb55f0da6c45b46d107..7db00613b6fae9ea28530bb5b610335a3df922a3 100644 (file)
@@ -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 ||
index 2a4e7e464b9fe84706f122940058a94f32ba2f41..8e79244e542dbebed1661275af89e0f52ca07397 100644 (file)
@@ -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;
index 44d60d8a202da1f2a574ee6014e68b83d3d4b6a3..f60e6645e4b57844c9ed96b9dc23ff6f8ba67fbe 100644 (file)
@@ -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 ] = &mid;
-       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 ] = &mid;
-       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 );
+                               }
+                       }
+               }
+       }
+}
index 62977ddfab7b6e65d08a0f4d21dca141d7fa770c..13f5c533bccd40a312e392cf2dc65a9a091b351d 100644 (file)
@@ -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 );
-}
 
 
 
index 8ae0d75addeca924a73c4b746136eed3bbb62b43..080f26ec5002441991c97388ecb5028fc577fa08 100644 (file)
@@ -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;
index 86d4d4988d1218c6f15a51c833bc98e15a1a40aa..074a4a437732d5621022af0037d2b15c074687ca 100644 (file)
@@ -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] <mapname>\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 <value> [-v] <mapname>\n" );
+               Sys_Printf( "Usage: q3map [-v] -scale [-tex] [-spawn_ref <value>] <value> <mapname>\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 <value> [-v] <mapname>\n" );
+               Sys_Printf( "Usage: q3map [-v] -scale [-tex] [-spawn_ref <value>] <value> <mapname>\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 <value> [-v] <mapname>\n" );
+               Sys_Printf( "Usage: q3map -convert -format <ase|obj|map_bp|map> [-shadesasbitmap|-lightmapsastexcoord|-deluxemapsastexcoord] [-readbsp|-readmap [-meta|-patchmeta]] <mapname>\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 );
index 4ec5a3818cdd09e5d9774e0ebbb9b05a7a4bac15..95bb3d1f74141968c369d8fe3ccd34b72fc45afc 100644 (file)
@@ -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 )
index ef0a04892f576ea2ce43a4c7b6d94218eaca4223..a56134c82777066c33851d4a8e33f60e6ad6c22a 100644 (file)
@@ -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 )
index 58b8ea207940edf63e281570eeecced407e05187..9cd707e224284fb3f2770bafb4e07e0847c77f07 100644 (file)
@@ -227,7 +227,6 @@ void ParsePatch( qboolean onlyLights )
        float                   longestCurve;
        int                             maxIterations;
        
-       
        MatchToken( "{" );
        
        /* get texture */
index 927ba76ae99fad7f191a48fa191a9d9c53973e09..83383e2287ba3cdae523ab375748b7cb2387b046 100644 (file)
@@ -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 )
index 02209d542bfa17a633fce97be609b24fbaeaa9e8..2efc1db47c0ea1bcad12fa27bcae6d214038cf92 100644 (file)
@@ -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;
index 6f36f7582cb554000541e5b6b4579199df6d86d9..2f10c7c0b5b620e279a1370903b8af026198439e 100644 (file)
@@ -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 );
index 78b2f7c1b631886f8ab322f658407905a649cb11..e912d15b26865f6b98d6ad01ddf6d6f1838606bd 100644 (file)
@@ -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 <stdlib.h>
 
 
@@ -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
index 78cf7b3a8620aa8a46d875f1524799dc10eef636..bc12037506f726d44a4150ba969b36477a2b36e8 100644 (file)
@@ -1 +1 @@
-101                     ICON    DISCARDABLE     "q3map2.ico"\r
+101                     ICON    DISCARDABLE     "q3map2.ico"
index 321a527bca09af8b016e93a28acc5ed95e6d55bb..3bf6cbe1ea4d1eb401954dfe9bf61d99eece5ce3 100644 (file)
@@ -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 <r> <g> <b> <diste> <intensity> <light_direction_power> */
+                               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 <value> */
                                else if( !Q_stricmp( token, "q3map_lightmapSampleSize" ) )
@@ -1470,7 +1537,7 @@ static void ParseShaderFile( const char *filename )
                                        si->lightmapSampleSize = atoi( token );
                                }
                                
-                               /* q3map_lightmapSampleSffset <value> */
+                               /* q3map_lightmapSampleOffset <value> */
                                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 <shader> */
+                               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 <value> */
                                else if( !Q_stricmp( token, "q3map_offset" ) )
@@ -1595,7 +1674,7 @@ static void ParseShaderFile( const char *filename )
                                        si->offset = atof( token );
                                }
                                
-                               /* ydnar: q3map_textureSize <width> <height> (substitute for q3map_lightimage derivation for terrain) */
+                               /* ydnar: q3map_fur <numlayers> <offset> <fade> */
                                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_<surfaceparm> */
-                               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
                        }
                        
                        
index 5415ae105d8f89e65f935b386bb5bc3fd8780626..ca4f5fa6ebd28138f4978040c365524d4d7d292a 100644 (file)
@@ -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++ )
index 440fd94694b217209405962b74d87290debf79c7..5cadc1d9df99d708bf8233392fef3f8723639fe0 100644 (file)
@@ -346,7 +346,7 @@ void LoadSurfaceExtraFile( const char *path )
        }
        
        /* parse the file */
-       ParseFromMemory( buffer, size );
+       ParseFromMemory( (char *) buffer, size );
        
        /* tokenize it */
        while( 1 )
index e9a8ec71f91f4466b88712b32b40a958f0c704b8..cc5452aec5fed549352595233dcb56010a3ccbf4 100644 (file)
@@ -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++ )
index 9191ac146ed8ca47d76dea44716a4316134754fd..0e300dde069625a8547b19dcfdaad38a7b19bdfe 100644 (file)
@@ -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 ] )
index d728c185b2611ad93b7f4fda7008eb860680139e..cde7ece495bdb6fffcec38192ae4579401b75221 100644 (file)
@@ -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 );
index 4ee843a0b96800a08c89f28b36fb124f7149a430..b92919226af604a9089019940bcb33f8410c3a5c 100644 (file)
@@ -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<portalclusters ; i++)
                ClusterMerge (i);
-
-  Sys_Printf( "Total visible clusters: %i\n", totalvis );
-  Sys_Printf( "Average clusters visible: %i\n", totalvis / portalclusters );
+       
+       totalvis = 0;
+       totalvis2 = 0;
+       minvis = -1;
+       maxvis = -1;
+       for(i = 0; i < MAX_MAP_LEAFS; ++i)
+               if(clustersizehistogram[i])
+               {
+                       if(debugCluster)
+                               Sys_FPrintf(SYS_VRB, "%4i clusters have exactly %4i visible clusters\n", clustersizehistogram[i], i);
+                       /* cast is to prevent integer overflow */
+                       totalvis  += ((double) i)                * ((double) clustersizehistogram[i]);
+                       totalvis2 += ((double) i) * ((double) i) * ((double) clustersizehistogram[i]);
+
+                       if(minvis < 0)
+                               minvis = i;
+                       maxvis = i;
+               }
+       
+       mu = totalvis / portalclusters;
+       sigma = sqrt(totalvis2 / portalclusters - mu * mu);
+       
+  Sys_Printf( "Total clusters: %i\n", portalclusters );
+  Sys_Printf( "Total visible clusters: %.0f\n", totalvis );
+  Sys_Printf( "Average clusters visible: %.2f (%.3f%%/total)\n", mu, mu / portalclusters * 100.0);
+  Sys_Printf( "  Standard deviation: %.2f (%.3f%%/total, %.3f%%/avg)\n", sigma, sigma / portalclusters * 100.0, sigma / mu * 100.0);
+  Sys_Printf( "  Minimum: %i (%.3f%%/total, %.3f%%/avg)\n", minvis, minvis / (double) portalclusters * 100.0, minvis / mu * 100.0);
+  Sys_Printf( "  Maximum: %i (%.3f%%/total, %.3f%%/avg)\n", maxvis, maxvis / (double) portalclusters * 100.0, maxvis / mu * 100.0);
 }
 
 /*
@@ -871,6 +897,9 @@ void LoadPortals (char *name)
        Sys_Printf ("%6i portalclusters\n", portalclusters);
        Sys_Printf ("%6i numportals\n", numportals);
        Sys_Printf ("%6i numfaces\n", numfaces);
+
+       if(numportals > 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" );*/
index 4cdd3a99e7b7c31a3c7c1d982cfbf7a14db73cd0..2e6e67a0e73d06857089a7477d63c186229812c2 100644 (file)
@@ -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 ];