/tools/quake2/extra/bsp/qbsp3/qbsp3.c
C | 537 lines | 392 code | 70 blank | 75 comment | 85 complexity | 50377f32c7fec1526b182fb464c172b6 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0
- /*
- ===========================================================================
- Copyright (C) 1997-2006 Id Software, Inc.
- This file is part of Quake 2 Tools source code.
- Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- ===========================================================================
- */
- #include "qbsp.h"
- extern float subdivide_size;
- char source[1024];
- char name[1024];
- vec_t microvolume = 1.0;
- qboolean noprune;
- qboolean glview;
- qboolean nodetail;
- qboolean fulldetail;
- qboolean onlyents;
- qboolean nomerge;
- qboolean nowater;
- qboolean nofill;
- qboolean nocsg;
- qboolean noweld;
- qboolean noshare;
- qboolean nosubdiv;
- qboolean notjunc;
- qboolean noopt;
- qboolean leaktest;
- qboolean verboseentities;
- char outbase[32];
- int block_xl = -8, block_xh = 7, block_yl = -8, block_yh = 7;
- int entity_num;
- node_t *block_nodes[10][10];
- /*
- ============
- BlockTree
- ============
- */
- node_t *BlockTree (int xl, int yl, int xh, int yh)
- {
- node_t *node;
- vec3_t normal;
- float dist;
- int mid;
- if (xl == xh && yl == yh)
- {
- node = block_nodes[xl+5][yl+5];
- if (!node)
- { // return an empty leaf
- node = AllocNode ();
- node->planenum = PLANENUM_LEAF;
- node->contents = 0; //CONTENTS_SOLID;
- return node;
- }
- return node;
- }
- // create a seperator along the largest axis
- node = AllocNode ();
- if (xh - xl > yh - yl)
- { // split x axis
- mid = xl + (xh-xl)/2 + 1;
- normal[0] = 1;
- normal[1] = 0;
- normal[2] = 0;
- dist = mid*1024;
- node->planenum = FindFloatPlane (normal, dist);
- node->children[0] = BlockTree ( mid, yl, xh, yh);
- node->children[1] = BlockTree ( xl, yl, mid-1, yh);
- }
- else
- {
- mid = yl + (yh-yl)/2 + 1;
- normal[0] = 0;
- normal[1] = 1;
- normal[2] = 0;
- dist = mid*1024;
- node->planenum = FindFloatPlane (normal, dist);
- node->children[0] = BlockTree ( xl, mid, xh, yh);
- node->children[1] = BlockTree ( xl, yl, xh, mid-1);
- }
- return node;
- }
- /*
- ============
- ProcessBlock_Thread
- ============
- */
- int brush_start, brush_end;
- void ProcessBlock_Thread (int blocknum)
- {
- int xblock, yblock;
- vec3_t mins, maxs;
- bspbrush_t *brushes;
- tree_t *tree;
- node_t *node;
- yblock = block_yl + blocknum / (block_xh-block_xl+1);
- xblock = block_xl + blocknum % (block_xh-block_xl+1);
- qprintf ("############### block %2i,%2i ###############\n", xblock, yblock);
- mins[0] = xblock*1024;
- mins[1] = yblock*1024;
- mins[2] = -4096;
- maxs[0] = (xblock+1)*1024;
- maxs[1] = (yblock+1)*1024;
- maxs[2] = 4096;
- // the makelist and chopbrushes could be cached between the passes...
- brushes = MakeBspBrushList (brush_start, brush_end, mins, maxs);
- if (!brushes)
- {
- node = AllocNode ();
- node->planenum = PLANENUM_LEAF;
- node->contents = CONTENTS_SOLID;
- block_nodes[xblock+5][yblock+5] = node;
- return;
- }
- if (!nocsg)
- brushes = ChopBrushes (brushes);
- tree = BrushBSP (brushes, mins, maxs);
- block_nodes[xblock+5][yblock+5] = tree->headnode;
- }
- /*
- ============
- ProcessWorldModel
- ============
- */
- void ProcessWorldModel (void)
- {
- entity_t *e;
- tree_t *tree;
- qboolean leaked;
- qboolean optimize;
- e = &entities[entity_num];
- brush_start = e->firstbrush;
- brush_end = brush_start + e->numbrushes;
- leaked = false;
- //
- // perform per-block operations
- //
- if (block_xh * 1024 > map_maxs[0])
- block_xh = floor(map_maxs[0]/1024.0);
- if ( (block_xl+1) * 1024 < map_mins[0])
- block_xl = floor(map_mins[0]/1024.0);
- if (block_yh * 1024 > map_maxs[1])
- block_yh = floor(map_maxs[1]/1024.0);
- if ( (block_yl+1) * 1024 < map_mins[1])
- block_yl = floor(map_mins[1]/1024.0);
- if (block_xl <-4)
- block_xl = -4;
- if (block_yl <-4)
- block_yl = -4;
- if (block_xh > 3)
- block_xh = 3;
- if (block_yh > 3)
- block_yh = 3;
- for (optimize = false ; optimize <= true ; optimize++)
- {
- qprintf ("--------------------------------------------\n");
- RunThreadsOnIndividual ((block_xh-block_xl+1)*(block_yh-block_yl+1),
- !verbose, ProcessBlock_Thread);
- //
- // build the division tree
- // oversizing the blocks guarantees that all the boundaries
- // will also get nodes.
- //
- qprintf ("--------------------------------------------\n");
- tree = AllocTree ();
- tree->headnode = BlockTree (block_xl-1, block_yl-1, block_xh+1, block_yh+1);
- tree->mins[0] = (block_xl)*1024;
- tree->mins[1] = (block_yl)*1024;
- tree->mins[2] = map_mins[2] - 8;
- tree->maxs[0] = (block_xh+1)*1024;
- tree->maxs[1] = (block_yh+1)*1024;
- tree->maxs[2] = map_maxs[2] + 8;
- //
- // perform the global operations
- //
- MakeTreePortals (tree);
- if (FloodEntities (tree))
- FillOutside (tree->headnode);
- else
- {
- printf ("**** leaked ****\n");
- leaked = true;
- LeakFile (tree);
- if (leaktest)
- {
- printf ("--- MAP LEAKED ---\n");
- exit (0);
- }
- }
- MarkVisibleSides (tree, brush_start, brush_end);
- if (noopt || leaked)
- break;
- if (!optimize)
- {
- FreeTree (tree);
- }
- }
- FloodAreas (tree);
- if (glview)
- WriteGLView (tree, source);
- MakeFaces (tree->headnode);
- FixTjuncs (tree->headnode);
- if (!noprune)
- PruneNodes (tree->headnode);
- WriteBSP (tree->headnode);
- if (!leaked)
- WritePortalFile (tree);
- FreeTree (tree);
- }
- /*
- ============
- ProcessSubModel
- ============
- */
- void ProcessSubModel (void)
- {
- entity_t *e;
- int start, end;
- tree_t *tree;
- bspbrush_t *list;
- vec3_t mins, maxs;
- e = &entities[entity_num];
- start = e->firstbrush;
- end = start + e->numbrushes;
- mins[0] = mins[1] = mins[2] = -4096;
- maxs[0] = maxs[1] = maxs[2] = 4096;
- list = MakeBspBrushList (start, end, mins, maxs);
- if (!nocsg)
- list = ChopBrushes (list);
- tree = BrushBSP (list, mins, maxs);
- MakeTreePortals (tree);
- MarkVisibleSides (tree, start, end);
- MakeFaces (tree->headnode);
- FixTjuncs (tree->headnode);
- WriteBSP (tree->headnode);
- FreeTree (tree);
- }
- /*
- ============
- ProcessModels
- ============
- */
- void ProcessModels (void)
- {
- BeginBSPFile ();
- for (entity_num=0 ; entity_num< num_entities ; entity_num++)
- {
- if (!entities[entity_num].numbrushes)
- continue;
- qprintf ("############### model %i ###############\n", nummodels);
- BeginModel ();
- if (entity_num == 0)
- ProcessWorldModel ();
- else
- ProcessSubModel ();
- EndModel ();
- if (!verboseentities)
- verbose = false; // don't bother printing submodels
- }
- EndBSPFile ();
- }
- /*
- ============
- main
- ============
- */
- int main (int argc, char **argv)
- {
- int i;
- double start, end;
- char path[1024];
- printf ("---- qbsp3 ----\n");
- for (i=1 ; i<argc ; i++)
- {
- if (!strcmp(argv[i],"-threads"))
- {
- numthreads = atoi (argv[i+1]);
- i++;
- }
- else if (!strcmp(argv[i],"-glview"))
- {
- glview = true;
- }
- else if (!strcmp(argv[i], "-v"))
- {
- printf ("verbose = true\n");
- verbose = true;
- }
- else if (!strcmp(argv[i], "-draw"))
- {
- printf ("drawflag = true\n");
- drawflag = true;
- }
- else if (!strcmp(argv[i], "-noweld"))
- {
- printf ("noweld = true\n");
- noweld = true;
- }
- else if (!strcmp(argv[i], "-nocsg"))
- {
- printf ("nocsg = true\n");
- nocsg = true;
- }
- else if (!strcmp(argv[i], "-noshare"))
- {
- printf ("noshare = true\n");
- noshare = true;
- }
- else if (!strcmp(argv[i], "-notjunc"))
- {
- printf ("notjunc = true\n");
- notjunc = true;
- }
- else if (!strcmp(argv[i], "-nowater"))
- {
- printf ("nowater = true\n");
- nowater = true;
- }
- else if (!strcmp(argv[i], "-noopt"))
- {
- printf ("noopt = true\n");
- noopt = true;
- }
- else if (!strcmp(argv[i], "-noprune"))
- {
- printf ("noprune = true\n");
- noprune = true;
- }
- else if (!strcmp(argv[i], "-nofill"))
- {
- printf ("nofill = true\n");
- nofill = true;
- }
- else if (!strcmp(argv[i], "-nomerge"))
- {
- printf ("nomerge = true\n");
- nomerge = true;
- }
- else if (!strcmp(argv[i], "-nosubdiv"))
- {
- printf ("nosubdiv = true\n");
- nosubdiv = true;
- }
- else if (!strcmp(argv[i], "-nodetail"))
- {
- printf ("nodetail = true\n");
- nodetail = true;
- }
- else if (!strcmp(argv[i], "-fulldetail"))
- {
- printf ("fulldetail = true\n");
- fulldetail = true;
- }
- else if (!strcmp(argv[i], "-onlyents"))
- {
- printf ("onlyents = true\n");
- onlyents = true;
- }
- else if (!strcmp(argv[i], "-micro"))
- {
- microvolume = atof(argv[i+1]);
- printf ("microvolume = %f\n", microvolume);
- i++;
- }
- else if (!strcmp(argv[i], "-leaktest"))
- {
- printf ("leaktest = true\n");
- leaktest = true;
- }
- else if (!strcmp(argv[i], "-verboseentities"))
- {
- printf ("verboseentities = true\n");
- verboseentities = true;
- }
- else if (!strcmp(argv[i], "-chop"))
- {
- subdivide_size = atof(argv[i+1]);
- printf ("subdivide_size = %f\n", subdivide_size);
- i++;
- }
- else if (!strcmp(argv[i], "-block"))
- {
- block_xl = block_xh = atoi(argv[i+1]);
- block_yl = block_yh = atoi(argv[i+2]);
- printf ("block: %i,%i\n", block_xl, block_yl);
- i+=2;
- }
- else if (!strcmp(argv[i], "-blocks"))
- {
- block_xl = atoi(argv[i+1]);
- block_yl = atoi(argv[i+2]);
- block_xh = atoi(argv[i+3]);
- block_yh = atoi(argv[i+4]);
- printf ("blocks: %i,%i to %i,%i\n",
- block_xl, block_yl, block_xh, block_yh);
- i+=4;
- }
- else if (!strcmp (argv[i],"-tmpout"))
- {
- strcpy (outbase, "/tmp");
- }
- else if (argv[i][0] == '-')
- Error ("Unknown option \"%s\"", argv[i]);
- else
- break;
- }
- if (i != argc - 1)
- Error ("usage: qbsp3 [options] mapfile");
- start = I_FloatTime ();
- ThreadSetDefault ();
- numthreads = 1; // multiple threads aren't helping...
- SetQdirFromPath (argv[i]);
- strcpy (source, ExpandArg (argv[i]));
- StripExtension (source);
- // delete portal and line files
- sprintf (path, "%s.prt", source);
- remove (path);
- sprintf (path, "%s.lin", source);
- remove (path);
- strcpy (name, ExpandArg (argv[i]));
- DefaultExtension (name, ".map"); // might be .reg
- //
- // if onlyents, just grab the entites and resave
- //
- if (onlyents)
- {
- char out[1024];
- sprintf (out, "%s.bsp", source);
- LoadBSPFile (out);
- num_entities = 0;
- LoadMapFile (name);
- SetModelNumbers ();
- SetLightStyles ();
- UnparseEntities ();
- WriteBSPFile (out);
- }
- else
- {
- //
- // start from scratch
- //
- LoadMapFile (name);
- SetModelNumbers ();
- SetLightStyles ();
- ProcessModels ();
- }
- end = I_FloatTime ();
- printf ("%5.0f seconds elapsed\n", end-start);
- return 0;
- }