]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/extra/bsp/qbsp3/qbsp3.c
Merge branch 'NateEag-master-patch-12920' into 'master'
[xonotic/netradiant.git] / tools / quake2 / extra / bsp / qbsp3 / qbsp3.c
1 /*
2 ===========================================================================
3 Copyright (C) 1997-2006 Id Software, Inc.
4
5 This file is part of Quake 2 Tools source code.
6
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.
11
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.
16
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 ===========================================================================
21 */
22
23 #include "qbsp.h"
24
25 extern  float subdivide_size;
26
27 char            source[1024];
28 char            name[1024];
29
30 vec_t           microvolume = 1.0;
31 qboolean        noprune;
32 qboolean        glview;
33 qboolean        nodetail;
34 qboolean        fulldetail;
35 qboolean        onlyents;
36 qboolean        nomerge;
37 qboolean        nowater;
38 qboolean        nofill;
39 qboolean        nocsg;
40 qboolean        noweld;
41 qboolean        noshare;
42 qboolean        nosubdiv;
43 qboolean        notjunc;
44 qboolean        noopt;
45 qboolean        leaktest;
46 qboolean        verboseentities;
47
48 char            outbase[32];
49
50 int                     block_xl = -8, block_xh = 7, block_yl = -8, block_yh = 7;
51
52 int                     entity_num;
53
54
55 node_t          *block_nodes[10][10];
56
57 /*
58 ============
59 BlockTree
60
61 ============
62 */
63 node_t  *BlockTree (int xl, int yl, int xh, int yh)
64 {
65         node_t  *node;
66         vec3_t  normal;
67         float   dist;
68         int             mid;
69
70         if (xl == xh && yl == yh)
71         {
72                 node = block_nodes[xl+5][yl+5];
73                 if (!node)
74                 {       // return an empty leaf
75                         node = AllocNode ();
76                         node->planenum = PLANENUM_LEAF;
77                         node->contents = 0; //CONTENTS_SOLID;
78                         return node;
79                 }
80                 return node;
81         }
82
83         // create a seperator along the largest axis
84         node = AllocNode ();
85
86         if (xh - xl > yh - yl)
87         {       // split x axis
88                 mid = xl + (xh-xl)/2 + 1;
89                 normal[0] = 1;
90                 normal[1] = 0;
91                 normal[2] = 0;
92                 dist = mid*1024;
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);
96         }
97         else
98         {
99                 mid = yl + (yh-yl)/2 + 1;
100                 normal[0] = 0;
101                 normal[1] = 1;
102                 normal[2] = 0;
103                 dist = mid*1024;
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);
107         }
108
109         return node;
110 }
111
112 /*
113 ============
114 ProcessBlock_Thread
115
116 ============
117 */
118 int                     brush_start, brush_end;
119 void ProcessBlock_Thread (int blocknum)
120 {
121         int             xblock, yblock;
122         vec3_t          mins, maxs;
123         bspbrush_t      *brushes;
124         tree_t          *tree;
125         node_t          *node;
126
127         yblock = block_yl + blocknum / (block_xh-block_xl+1);
128         xblock = block_xl + blocknum % (block_xh-block_xl+1);
129
130         qprintf ("############### block %2i,%2i ###############\n", xblock, yblock);
131
132         mins[0] = xblock*1024;
133         mins[1] = yblock*1024;
134         mins[2] = -4096;
135         maxs[0] = (xblock+1)*1024;
136         maxs[1] = (yblock+1)*1024;
137         maxs[2] = 4096;
138
139         // the makelist and chopbrushes could be cached between the passes...
140         brushes = MakeBspBrushList (brush_start, brush_end, mins, maxs);
141         if (!brushes)
142         {
143                 node = AllocNode ();
144                 node->planenum = PLANENUM_LEAF;
145                 node->contents = CONTENTS_SOLID;
146                 block_nodes[xblock+5][yblock+5] = node;
147                 return;
148         }
149
150         if (!nocsg)
151                 brushes = ChopBrushes (brushes);
152
153         tree = BrushBSP (brushes, mins, maxs);
154
155         block_nodes[xblock+5][yblock+5] = tree->headnode;
156 }
157
158 /*
159 ============
160 ProcessWorldModel
161
162 ============
163 */
164 void ProcessWorldModel (void)
165 {
166         entity_t        *e;
167         tree_t          *tree;
168         qboolean        leaked;
169         qboolean        optimize;
170
171         e = &entities[entity_num];
172
173         brush_start = e->firstbrush;
174         brush_end = brush_start + e->numbrushes;
175         leaked = false;
176
177         //
178         // perform per-block operations
179         //
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);
188
189         if (block_xl <-4)
190                 block_xl = -4;
191         if (block_yl <-4)
192                 block_yl = -4;
193         if (block_xh > 3)
194                 block_xh = 3;
195         if (block_yh > 3)
196                 block_yh = 3;
197
198         for (optimize = false ; optimize <= true ; optimize++)
199         {
200                 qprintf ("--------------------------------------------\n");
201
202                 RunThreadsOnIndividual ((block_xh-block_xl+1)*(block_yh-block_yl+1),
203                         !verbose, ProcessBlock_Thread);
204
205                 //
206                 // build the division tree
207                 // oversizing the blocks guarantees that all the boundaries
208                 // will also get nodes.
209                 //
210
211                 qprintf ("--------------------------------------------\n");
212
213                 tree = AllocTree ();
214                 tree->headnode = BlockTree (block_xl-1, block_yl-1, block_xh+1, block_yh+1);
215
216                 tree->mins[0] = (block_xl)*1024;
217                 tree->mins[1] = (block_yl)*1024;
218                 tree->mins[2] = map_mins[2] - 8;
219
220                 tree->maxs[0] = (block_xh+1)*1024;
221                 tree->maxs[1] = (block_yh+1)*1024;
222                 tree->maxs[2] = map_maxs[2] + 8;
223
224                 //
225                 // perform the global operations
226                 //
227                 MakeTreePortals (tree);
228
229                 if (FloodEntities (tree))
230                         FillOutside (tree->headnode);
231                 else
232                 {
233                         printf ("**** leaked ****\n");
234                         leaked = true;
235                         LeakFile (tree);
236                         if (leaktest)
237                         {
238                                 printf ("--- MAP LEAKED ---\n");
239                                 exit (0);
240                         }
241                 }
242
243                 MarkVisibleSides (tree, brush_start, brush_end);
244                 if (noopt || leaked)
245                         break;
246                 if (!optimize)
247                 {
248                         FreeTree (tree);
249                 }
250         }
251
252         FloodAreas (tree);
253         if (glview)
254                 WriteGLView (tree, source);
255         MakeFaces (tree->headnode);
256         FixTjuncs (tree->headnode);
257
258         if (!noprune)
259                 PruneNodes (tree->headnode);
260
261         WriteBSP (tree->headnode);
262
263         if (!leaked)
264                 WritePortalFile (tree);
265
266         FreeTree (tree);
267 }
268
269 /*
270 ============
271 ProcessSubModel
272
273 ============
274 */
275 void ProcessSubModel (void)
276 {
277         entity_t        *e;
278         int                     start, end;
279         tree_t          *tree;
280         bspbrush_t      *list;
281         vec3_t          mins, maxs;
282
283         e = &entities[entity_num];
284
285         start = e->firstbrush;
286         end = start + e->numbrushes;
287
288         mins[0] = mins[1] = mins[2] = -4096;
289         maxs[0] = maxs[1] = maxs[2] = 4096;
290         list = MakeBspBrushList (start, end, mins, maxs);
291         if (!nocsg)
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);
299         FreeTree (tree);
300 }
301
302 /*
303 ============
304 ProcessModels
305 ============
306 */
307 void ProcessModels (void)
308 {
309         BeginBSPFile ();
310
311         for (entity_num=0 ; entity_num< num_entities ; entity_num++)
312         {
313                 if (!entities[entity_num].numbrushes)
314                         continue;
315
316                 qprintf ("############### model %i ###############\n", nummodels);
317                 BeginModel ();
318                 if (entity_num == 0)
319                         ProcessWorldModel ();
320                 else
321                         ProcessSubModel ();
322                 EndModel ();
323
324                 if (!verboseentities)
325                         verbose = false;        // don't bother printing submodels
326         }
327
328         EndBSPFile ();
329 }
330
331
332 /*
333 ============
334 main
335 ============
336 */
337 int main (int argc, char **argv)
338 {
339         int             i;
340         double          start, end;
341         char            path[1024];
342
343         printf ("---- qbsp3 ----\n");
344
345         for (i=1 ; i<argc ; i++)
346         {
347                 if (!strcmp(argv[i],"-threads"))
348                 {
349                         numthreads = atoi (argv[i+1]);
350                         i++;
351                 }
352                 else if (!strcmp(argv[i],"-glview"))
353                 {
354                         glview = true;
355                 }
356                 else if (!strcmp(argv[i], "-v"))
357                 {
358                         printf ("verbose = true\n");
359                         verbose = true;
360                 }
361                 else if (!strcmp(argv[i], "-draw"))
362                 {
363                         printf ("drawflag = true\n");
364                         drawflag = true;
365                 }
366                 else if (!strcmp(argv[i], "-noweld"))
367                 {
368                         printf ("noweld = true\n");
369                         noweld = true;
370                 }
371                 else if (!strcmp(argv[i], "-nocsg"))
372                 {
373                         printf ("nocsg = true\n");
374                         nocsg = true;
375                 }
376                 else if (!strcmp(argv[i], "-noshare"))
377                 {
378                         printf ("noshare = true\n");
379                         noshare = true;
380                 }
381                 else if (!strcmp(argv[i], "-notjunc"))
382                 {
383                         printf ("notjunc = true\n");
384                         notjunc = true;
385                 }
386                 else if (!strcmp(argv[i], "-nowater"))
387                 {
388                         printf ("nowater = true\n");
389                         nowater = true;
390                 }
391                 else if (!strcmp(argv[i], "-noopt"))
392                 {
393                         printf ("noopt = true\n");
394                         noopt = true;
395                 }
396                 else if (!strcmp(argv[i], "-noprune"))
397                 {
398                         printf ("noprune = true\n");
399                         noprune = true;
400                 }
401                 else if (!strcmp(argv[i], "-nofill"))
402                 {
403                         printf ("nofill = true\n");
404                         nofill = true;
405                 }
406                 else if (!strcmp(argv[i], "-nomerge"))
407                 {
408                         printf ("nomerge = true\n");
409                         nomerge = true;
410                 }
411                 else if (!strcmp(argv[i], "-nosubdiv"))
412                 {
413                         printf ("nosubdiv = true\n");
414                         nosubdiv = true;
415                 }
416                 else if (!strcmp(argv[i], "-nodetail"))
417                 {
418                         printf ("nodetail = true\n");
419                         nodetail = true;
420                 }
421                 else if (!strcmp(argv[i], "-fulldetail"))
422                 {
423                         printf ("fulldetail = true\n");
424                         fulldetail = true;
425                 }
426                 else if (!strcmp(argv[i], "-onlyents"))
427                 {
428                         printf ("onlyents = true\n");
429                         onlyents = true;
430                 }
431                 else if (!strcmp(argv[i], "-micro"))
432                 {
433                         microvolume = atof(argv[i+1]);
434                         printf ("microvolume = %f\n", microvolume);
435                         i++;
436                 }
437                 else if (!strcmp(argv[i], "-leaktest"))
438                 {
439                         printf ("leaktest = true\n");
440                         leaktest = true;
441                 }
442                 else if (!strcmp(argv[i], "-verboseentities"))
443                 {
444                         printf ("verboseentities = true\n");
445                         verboseentities = true;
446                 }
447                 else if (!strcmp(argv[i], "-chop"))
448                 {
449                         subdivide_size = atof(argv[i+1]);
450                         printf ("subdivide_size = %f\n", subdivide_size);
451                         i++;
452                 }
453                 else if (!strcmp(argv[i], "-block"))
454                 {
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);
458                         i+=2;
459                 }
460                 else if (!strcmp(argv[i], "-blocks"))
461                 {
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);
468                         i+=4;
469                 }
470                 else if (!strcmp (argv[i],"-tmpout"))
471                 {
472                         strcpy (outbase, "/tmp");
473                 }
474                 else if (argv[i][0] == '-')
475                         Error ("Unknown option \"%s\"", argv[i]);
476                 else
477                         break;
478         }
479
480         if (i != argc - 1)
481                 Error ("usage: qbsp3 [options] mapfile");
482
483         start = I_FloatTime ();
484
485         ThreadSetDefault ();
486 numthreads = 1;         // multiple threads aren't helping...
487         SetQdirFromPath (argv[i]);
488
489         strcpy (source, ExpandArg (argv[i]));
490         StripExtension (source);
491
492         // delete portal and line files
493         sprintf (path, "%s.prt", source);
494         remove (path);
495         sprintf (path, "%s.lin", source);
496         remove (path);
497
498         strcpy (name, ExpandArg (argv[i]));     
499         DefaultExtension (name, ".map");        // might be .reg
500
501         //
502         // if onlyents, just grab the entites and resave
503         //
504         if (onlyents)
505         {
506                 char out[1024];
507
508                 sprintf (out, "%s.bsp", source);
509                 LoadBSPFile (out);
510                 num_entities = 0;
511
512                 LoadMapFile (name);
513                 SetModelNumbers ();
514                 SetLightStyles ();
515
516                 UnparseEntities ();
517
518                 WriteBSPFile (out);
519         }
520         else
521         {
522                 //
523                 // start from scratch
524                 //
525                 LoadMapFile (name);
526                 SetModelNumbers ();
527                 SetLightStyles ();
528
529                 ProcessModels ();
530         }
531
532         end = I_FloatTime ();
533         printf ("%5.0f seconds elapsed\n", end-start);
534
535         return 0;
536 }
537