/* =========================================================================== Copyright (C) 1999-2005 Id Software, Inc. This file is part of Quake III Arena source code. Quake III Arena source code 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. Quake III Arena source code 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 Foobar; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ #include "qbsp.h" #ifdef _WIN32 #ifdef _TTIMOBUILD #include "pakstuff.h" #else #include "../libs/pakstuff.h" #endif extern HWND hwndOut; #endif char source[1024]; char tempsource[1024]; char name[1024]; vec_t microvolume = 1.0; qboolean glview; qboolean nodetail; qboolean fulldetail; qboolean onlyents; qboolean onlytextures; qboolean nowater; qboolean nofill; qboolean noopt; qboolean leaktest; qboolean verboseentities; qboolean noCurveBrushes; qboolean fakemap; qboolean notjunc; qboolean nomerge; qboolean nofog; qboolean nosubdivide; qboolean testExpand; qboolean showseams; char outbase[32]; int entity_num; /* ============ ProcessWorldModel ============ */ void ProcessWorldModel( void ) { entity_t *e; tree_t *tree; bspface_t *faces; qboolean leaked; BeginModel(); e = &entities[0]; e->firstDrawSurf = 0;//numMapDrawSurfs; // check for patches with adjacent edges that need to LOD together PatchMapDrawSurfs( e ); // build an initial bsp tree using all of the sides // of all of the structural brushes faces = MakeStructuralBspFaceList ( entities[0].brushes ); tree = FaceBSP( faces ); MakeTreePortals (tree); FilterStructuralBrushesIntoTree( e, tree ); // see if the bsp is completely enclosed if ( FloodEntities (tree) ) { // rebuild a better bsp tree using only the // sides that are visible from the inside FillOutside (tree->headnode); // chop the sides to the convex hull of // their visible fragments, giving us the smallest // polygons ClipSidesIntoTree( e, tree ); faces = MakeVisibleBspFaceList( entities[0].brushes ); FreeTree (tree); tree = FaceBSP( faces ); MakeTreePortals( tree ); FilterStructuralBrushesIntoTree( e, tree ); leaked = qfalse; } else { _printf ("**********************\n"); _printf ("******* leaked *******\n"); _printf ("**********************\n"); LeakFile (tree); if ( leaktest ) { _printf ("--- MAP LEAKED, ABORTING LEAKTEST ---\n"); exit (0); } leaked = qtrue; // chop the sides to the convex hull of // their visible fragments, giving us the smallest // polygons ClipSidesIntoTree( e, tree ); } // save out information for visibility processing NumberClusters( tree ); if ( !leaked ) { WritePortalFile( tree ); } if ( glview ) { // dump the portals for debugging WriteGLView( tree, source ); } FloodAreas (tree); // add references to the detail brushes FilterDetailBrushesIntoTree( e, tree ); // create drawsurfs for triangle models AddTriangleModels( tree ); // drawsurfs that cross fog boundaries will need to // be split along the bound if ( !nofog ) { FogDrawSurfs(); // may fragment drawsurfs } // subdivide each drawsurf as required by shader tesselation if ( !nosubdivide ) { SubdivideDrawSurfs( e, tree ); } // merge together all common shaders on the same plane and remove // all colinear points, so extra tjunctions won't be generated if ( !nomerge ) { MergeSides( e, tree ); // !@# testing } // add in any vertexes required to fix tjunctions if ( !notjunc ) { FixTJunctions( e ); } // allocate lightmaps for faces and patches AllocateLightmaps( e ); // add references to the final drawsurfs in the apropriate clusters FilterDrawsurfsIntoTree( e, tree ); EndModel( tree->headnode ); FreeTree (tree); } /* ============ ProcessSubModel ============ */ void ProcessSubModel( void ) { entity_t *e; tree_t *tree; bspbrush_t *b, *bc; node_t *node; BeginModel (); e = &entities[entity_num]; e->firstDrawSurf = numMapDrawSurfs; PatchMapDrawSurfs( e ); // just put all the brushes in an empty leaf // FIXME: patches? node = AllocNode(); node->planenum = PLANENUM_LEAF; for ( b = e->brushes ; b ; b = b->next ) { bc = CopyBrush( b ); bc->next = node->brushlist; node->brushlist = bc; } tree = AllocTree(); tree->headnode = node; ClipSidesIntoTree( e, tree ); // subdivide each drawsurf as required by shader tesselation or fog if ( !nosubdivide ) { SubdivideDrawSurfs( e, tree ); } // merge together all common shaders on the same plane and remove // all colinear points, so extra tjunctions won't be generated if ( !nomerge ) { MergeSides( e, tree ); // !@# testing } // add in any vertexes required to fix tjunctions if ( !notjunc ) { FixTJunctions( e ); } // allocate lightmaps for faces and patches AllocateLightmaps( e ); // add references to the final drawsurfs in the apropriate clusters FilterDrawsurfsIntoTree( e, tree ); EndModel ( node ); FreeTree( tree ); } /* ============ ProcessModels ============ */ void ProcessModels (void) { qboolean oldVerbose; entity_t *entity; oldVerbose = verbose; BeginBSPFile (); for ( entity_num=0 ; entity_num< num_entities ; entity_num++ ) { entity = &entities[entity_num]; if ( !entity->brushes && !entity->patches ) { continue; } qprintf ("############### model %i ###############\n", nummodels); if (entity_num == 0) ProcessWorldModel (); else ProcessSubModel (); if (!verboseentities) verbose = qfalse; // don't bother printing submodels } verbose = oldVerbose; } /* ============ Bspinfo ============ */ void Bspinfo( int count, char **fileNames ) { int i; char source[1024]; int size; FILE *f; if ( count < 1 ) { _printf( "No files to dump info for.\n"); return; } for ( i = 0 ; i < count ; i++ ) { _printf ("---------------------\n"); strcpy (source, fileNames[ i ] ); DefaultExtension (source, ".bsp"); f = fopen (source, "rb"); if (f) { size = Q_filelength (f); fclose (f); } else size = 0; _printf ("%s: %i\n", source, size); LoadBSPFile (source); PrintBSPFileSizes (); _printf ("---------------------\n"); } } /* ============ OnlyEnts ============ */ void OnlyEnts( void ) { char out[1024]; sprintf (out, "%s.bsp", source); LoadBSPFile (out); num_entities = 0; LoadMapFile (name); SetModelNumbers (); SetLightStyles (); UnparseEntities (); WriteBSPFile (out); } /* ============ OnlyTextures ============ */ void OnlyTextures( void ) { // FIXME!!! char out[1024]; int i; Error( "-onlytextures isn't working now..." ); sprintf (out, "%s.bsp", source); LoadMapFile (name); LoadBSPFile (out); // replace all the drawsurface shader names for ( i = 0 ; i < numDrawSurfaces ; i++ ) { } WriteBSPFile (out); } /* ============ main ============ */ int LightMain( int argc, char **argv ); int VLightMain (int argc, char **argv); int VSoundMain (int argc, char **argv); int VisMain( int argc, char **argv ); int main (int argc, char **argv) { int i; double start, end; char path[1024]; _printf ("Q3Map v1.0s (c) 1999 Id Software Inc.\n"); if ( argc < 2 ) { Error ("usage: q3map [options] mapfile"); } // check for general program options if (!strcmp(argv[1], "-info")) { Bspinfo( argc - 2, argv + 2 ); return 0; } if (!strcmp(argv[1], "-light")) { LightMain( argc - 1, argv + 1 ); return 0; } if (!strcmp(argv[1], "-vlight")) { VLightMain( argc - 1, argv + 1 ); return 0; } if (!strcmp(argv[1], "-vsound")) { VSoundMain( argc - 1, argv + 1 ); return 0; } if (!strcmp(argv[1], "-vis")) { VisMain( argc - 1, argv + 1 ); return 0; } // do a bsp if nothing else was specified _printf ("---- q3map ----\n"); tempsource[0] = '\0'; for (i=1 ; i 0) { LoadMapFile (tempsource); } else { LoadMapFile (name); } SetModelNumbers (); SetLightStyles (); ProcessModels (); EndBSPFile(); end = I_FloatTime (); _printf ("%5.0f seconds elapsed\n", end-start); // remove temp name if appropriate if (strlen(tempsource) > 0) { remove(tempsource); } return 0; }