2 ===========================================================================
3 Copyright (C) 1997-2006 Id Software, Inc.
5 This file is part of Quake 2 Tools source code.
7 Quake 2 Tools source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
12 Quake 2 Tools source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Quake 2 Tools source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 ===========================================================================
25 extern float subdivide_size;
30 vec_t microvolume = 1.0;
46 qboolean verboseentities;
50 int block_xl = -8, block_xh = 7, block_yl = -8, block_yh = 7;
55 node_t *block_nodes[10][10];
63 node_t *BlockTree (int xl, int yl, int xh, int yh)
70 if (xl == xh && yl == yh)
72 node = block_nodes[xl+5][yl+5];
74 { // return an empty leaf
76 node->planenum = PLANENUM_LEAF;
77 node->contents = 0; //CONTENTS_SOLID;
83 // create a seperator along the largest axis
86 if (xh - xl > yh - yl)
88 mid = xl + (xh-xl)/2 + 1;
93 node->planenum = FindFloatPlane (normal, dist);
94 node->children[0] = BlockTree ( mid, yl, xh, yh);
95 node->children[1] = BlockTree ( xl, yl, mid-1, yh);
99 mid = yl + (yh-yl)/2 + 1;
104 node->planenum = FindFloatPlane (normal, dist);
105 node->children[0] = BlockTree ( xl, mid, xh, yh);
106 node->children[1] = BlockTree ( xl, yl, xh, mid-1);
118 int brush_start, brush_end;
119 void ProcessBlock_Thread (int blocknum)
127 yblock = block_yl + blocknum / (block_xh-block_xl+1);
128 xblock = block_xl + blocknum % (block_xh-block_xl+1);
130 qprintf ("############### block %2i,%2i ###############\n", xblock, yblock);
132 mins[0] = xblock*1024;
133 mins[1] = yblock*1024;
135 maxs[0] = (xblock+1)*1024;
136 maxs[1] = (yblock+1)*1024;
139 // the makelist and chopbrushes could be cached between the passes...
140 brushes = MakeBspBrushList (brush_start, brush_end, mins, maxs);
144 node->planenum = PLANENUM_LEAF;
145 node->contents = CONTENTS_SOLID;
146 block_nodes[xblock+5][yblock+5] = node;
151 brushes = ChopBrushes (brushes);
153 tree = BrushBSP (brushes, mins, maxs);
155 block_nodes[xblock+5][yblock+5] = tree->headnode;
164 void ProcessWorldModel (void)
171 e = &entities[entity_num];
173 brush_start = e->firstbrush;
174 brush_end = brush_start + e->numbrushes;
178 // perform per-block operations
180 if (block_xh * 1024 > map_maxs[0])
181 block_xh = floor(map_maxs[0]/1024.0);
182 if ( (block_xl+1) * 1024 < map_mins[0])
183 block_xl = floor(map_mins[0]/1024.0);
184 if (block_yh * 1024 > map_maxs[1])
185 block_yh = floor(map_maxs[1]/1024.0);
186 if ( (block_yl+1) * 1024 < map_mins[1])
187 block_yl = floor(map_mins[1]/1024.0);
198 for (optimize = false ; optimize <= true ; optimize++)
200 qprintf ("--------------------------------------------\n");
202 RunThreadsOnIndividual ((block_xh-block_xl+1)*(block_yh-block_yl+1),
203 !verbose, ProcessBlock_Thread);
206 // build the division tree
207 // oversizing the blocks guarantees that all the boundaries
208 // will also get nodes.
211 qprintf ("--------------------------------------------\n");
214 tree->headnode = BlockTree (block_xl-1, block_yl-1, block_xh+1, block_yh+1);
216 tree->mins[0] = (block_xl)*1024;
217 tree->mins[1] = (block_yl)*1024;
218 tree->mins[2] = map_mins[2] - 8;
220 tree->maxs[0] = (block_xh+1)*1024;
221 tree->maxs[1] = (block_yh+1)*1024;
222 tree->maxs[2] = map_maxs[2] + 8;
225 // perform the global operations
227 MakeTreePortals (tree);
229 if (FloodEntities (tree))
230 FillOutside (tree->headnode);
233 printf ("**** leaked ****\n");
238 printf ("--- MAP LEAKED ---\n");
243 MarkVisibleSides (tree, brush_start, brush_end);
254 WriteGLView (tree, source);
255 MakeFaces (tree->headnode);
256 FixTjuncs (tree->headnode);
259 PruneNodes (tree->headnode);
261 WriteBSP (tree->headnode);
264 WritePortalFile (tree);
275 void ProcessSubModel (void)
283 e = &entities[entity_num];
285 start = e->firstbrush;
286 end = start + e->numbrushes;
288 mins[0] = mins[1] = mins[2] = -4096;
289 maxs[0] = maxs[1] = maxs[2] = 4096;
290 list = MakeBspBrushList (start, end, mins, maxs);
292 list = ChopBrushes (list);
293 tree = BrushBSP (list, mins, maxs);
294 MakeTreePortals (tree);
295 MarkVisibleSides (tree, start, end);
296 MakeFaces (tree->headnode);
297 FixTjuncs (tree->headnode);
298 WriteBSP (tree->headnode);
307 void ProcessModels (void)
311 for (entity_num=0 ; entity_num< num_entities ; entity_num++)
313 if (!entities[entity_num].numbrushes)
316 qprintf ("############### model %i ###############\n", nummodels);
319 ProcessWorldModel ();
324 if (!verboseentities)
325 verbose = false; // don't bother printing submodels
337 int main (int argc, char **argv)
343 printf ("---- qbsp3 ----\n");
345 for (i=1 ; i<argc ; i++)
347 if (!strcmp(argv[i],"-threads"))
349 numthreads = atoi (argv[i+1]);
352 else if (!strcmp(argv[i],"-glview"))
356 else if (!strcmp(argv[i], "-v"))
358 printf ("verbose = true\n");
361 else if (!strcmp(argv[i], "-draw"))
363 printf ("drawflag = true\n");
366 else if (!strcmp(argv[i], "-noweld"))
368 printf ("noweld = true\n");
371 else if (!strcmp(argv[i], "-nocsg"))
373 printf ("nocsg = true\n");
376 else if (!strcmp(argv[i], "-noshare"))
378 printf ("noshare = true\n");
381 else if (!strcmp(argv[i], "-notjunc"))
383 printf ("notjunc = true\n");
386 else if (!strcmp(argv[i], "-nowater"))
388 printf ("nowater = true\n");
391 else if (!strcmp(argv[i], "-noopt"))
393 printf ("noopt = true\n");
396 else if (!strcmp(argv[i], "-noprune"))
398 printf ("noprune = true\n");
401 else if (!strcmp(argv[i], "-nofill"))
403 printf ("nofill = true\n");
406 else if (!strcmp(argv[i], "-nomerge"))
408 printf ("nomerge = true\n");
411 else if (!strcmp(argv[i], "-nosubdiv"))
413 printf ("nosubdiv = true\n");
416 else if (!strcmp(argv[i], "-nodetail"))
418 printf ("nodetail = true\n");
421 else if (!strcmp(argv[i], "-fulldetail"))
423 printf ("fulldetail = true\n");
426 else if (!strcmp(argv[i], "-onlyents"))
428 printf ("onlyents = true\n");
431 else if (!strcmp(argv[i], "-micro"))
433 microvolume = atof(argv[i+1]);
434 printf ("microvolume = %f\n", microvolume);
437 else if (!strcmp(argv[i], "-leaktest"))
439 printf ("leaktest = true\n");
442 else if (!strcmp(argv[i], "-verboseentities"))
444 printf ("verboseentities = true\n");
445 verboseentities = true;
447 else if (!strcmp(argv[i], "-chop"))
449 subdivide_size = atof(argv[i+1]);
450 printf ("subdivide_size = %f\n", subdivide_size);
453 else if (!strcmp(argv[i], "-block"))
455 block_xl = block_xh = atoi(argv[i+1]);
456 block_yl = block_yh = atoi(argv[i+2]);
457 printf ("block: %i,%i\n", block_xl, block_yl);
460 else if (!strcmp(argv[i], "-blocks"))
462 block_xl = atoi(argv[i+1]);
463 block_yl = atoi(argv[i+2]);
464 block_xh = atoi(argv[i+3]);
465 block_yh = atoi(argv[i+4]);
466 printf ("blocks: %i,%i to %i,%i\n",
467 block_xl, block_yl, block_xh, block_yh);
470 else if (!strcmp (argv[i],"-tmpout"))
472 strcpy (outbase, "/tmp");
474 else if (argv[i][0] == '-')
475 Error ("Unknown option \"%s\"", argv[i]);
481 Error ("usage: qbsp3 [options] mapfile");
483 start = I_FloatTime ();
486 numthreads = 1; // multiple threads aren't helping...
487 SetQdirFromPath (argv[i]);
489 strcpy (source, ExpandArg (argv[i]));
490 StripExtension (source);
492 // delete portal and line files
493 sprintf (path, "%s.prt", source);
495 sprintf (path, "%s.lin", source);
498 strcpy (name, ExpandArg (argv[i]));
499 DefaultExtension (name, ".map"); // might be .reg
502 // if onlyents, just grab the entites and resave
508 sprintf (out, "%s.bsp", source);
523 // start from scratch
532 end = I_FloatTime ();
533 printf ("%5.0f seconds elapsed\n", end-start);