]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/q2map/qbsp.c
tools: reduce diff noise
[xonotic/netradiant.git] / tools / quake2 / q2map / qbsp.c
1 /*
2    Copyright (C) 1999-2007 id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    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 GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 // csg4.c
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    ============
60    BlockTree
61
62    ============
63  */
64 node_t  *BlockTree( int xl, int yl, int xh, int yh ){
65         node_t  *node;
66         vec3_t normal;
67         float dist;
68         int mid;
69
70         if ( xl == xh && yl == yh ) {
71                 node = block_nodes[xl + 5][yl + 5];
72                 if ( !node ) { // return an empty leaf
73                         node = AllocNode();
74                         node->planenum = PLANENUM_LEAF;
75                         node->contents = 0; //CONTENTS_SOLID;
76                         return node;
77                 }
78                 return node;
79         }
80
81         // create a seperator along the largest axis
82         node = AllocNode();
83
84         if ( xh - xl > yh - yl ) { // split x axis
85                 mid = xl + ( xh - xl ) / 2 + 1;
86                 normal[0] = 1;
87                 normal[1] = 0;
88                 normal[2] = 0;
89                 dist = mid * 1024;
90                 node->planenum = FindFloatPlane( normal, dist );
91                 node->children[0] = BlockTree( mid, yl, xh, yh );
92                 node->children[1] = BlockTree( xl, yl, mid - 1, yh );
93         }
94         else
95         {
96                 mid = yl + ( yh - yl ) / 2 + 1;
97                 normal[0] = 0;
98                 normal[1] = 1;
99                 normal[2] = 0;
100                 dist = mid * 1024;
101                 node->planenum = FindFloatPlane( normal, dist );
102                 node->children[0] = BlockTree( xl, mid, xh, yh );
103                 node->children[1] = BlockTree( xl, yl, xh, mid - 1 );
104         }
105
106         return node;
107 }
108
109 /*
110    ============
111    ProcessBlock_Thread
112
113    ============
114  */
115 int brush_start, brush_end;
116 void ProcessBlock_Thread( int blocknum ){
117         int xblock, yblock;
118         vec3_t mins, maxs;
119         bspbrush_t  *brushes;
120         tree_t      *tree;
121         node_t      *node;
122
123         yblock = block_yl + blocknum / ( block_xh - block_xl + 1 );
124         xblock = block_xl + blocknum % ( block_xh - block_xl + 1 );
125
126         Sys_FPrintf( SYS_VRB, "############### block %2i,%2i ###############\n", xblock, yblock );
127
128         mins[0] = xblock * 1024;
129         mins[1] = yblock * 1024;
130         mins[2] = -4096;
131         maxs[0] = ( xblock + 1 ) * 1024;
132         maxs[1] = ( yblock + 1 ) * 1024;
133         maxs[2] = 4096;
134
135         // the makelist and chopbrushes could be cached between the passes...
136         brushes = MakeBspBrushList( brush_start, brush_end, mins, maxs );
137         if ( !brushes ) {
138                 node = AllocNode();
139                 node->planenum = PLANENUM_LEAF;
140                 node->contents = CONTENTS_SOLID;
141                 block_nodes[xblock + 5][yblock + 5] = node;
142                 return;
143         }
144
145         if ( !nocsg ) {
146                 brushes = ChopBrushes( brushes );
147         }
148
149         tree = BrushBSP( brushes, mins, maxs );
150
151         block_nodes[xblock + 5][yblock + 5] = tree->headnode;
152 }
153
154 /*
155    ============
156    ProcessWorldModel
157
158    ============
159  */
160 void ProcessWorldModel( void ){
161         entity_t    *e;
162         tree_t      *tree;
163         qboolean leaked;
164         qboolean optimize;
165         xmlNodePtr polyline, leaknode;
166         char level[ 2 ];
167
168         e = &entities[entity_num];
169
170         brush_start = e->firstbrush;
171         brush_end = brush_start + e->numbrushes;
172         leaked = false;
173
174         //
175         // perform per-block operations
176         //
177         if ( block_xh * 1024 > map_maxs[0] ) {
178                 block_xh = floor( map_maxs[0] / 1024.0 );
179         }
180         if ( ( block_xl + 1 ) * 1024 < map_mins[0] ) {
181                 block_xl = floor( map_mins[0] / 1024.0 );
182         }
183         if ( block_yh * 1024 > map_maxs[1] ) {
184                 block_yh = floor( map_maxs[1] / 1024.0 );
185         }
186         if ( ( block_yl + 1 ) * 1024 < map_mins[1] ) {
187                 block_yl = floor( map_mins[1] / 1024.0 );
188         }
189
190         if ( block_xl < -4 ) {
191                 block_xl = -4;
192         }
193         if ( block_yl < -4 ) {
194                 block_yl = -4;
195         }
196         if ( block_xh > 3 ) {
197                 block_xh = 3;
198         }
199         if ( block_yh > 3 ) {
200                 block_yh = 3;
201         }
202
203         for ( optimize = false ; optimize <= true ; optimize++ )
204         {
205                 Sys_FPrintf( SYS_VRB, "--------------------------------------------\n" );
206
207                 RunThreadsOnIndividual( ( block_xh - block_xl + 1 ) * ( block_yh - block_yl + 1 ),
208                                                                 !verbose, ProcessBlock_Thread );
209
210                 //
211                 // build the division tree
212                 // oversizing the blocks guarantees that all the boundaries
213                 // will also get nodes.
214                 //
215
216                 Sys_FPrintf( SYS_VRB, "--------------------------------------------\n" );
217
218                 tree = AllocTree();
219                 tree->headnode = BlockTree( block_xl - 1, block_yl - 1, block_xh + 1, block_yh + 1 );
220
221                 tree->mins[0] = ( block_xl ) * 1024;
222                 tree->mins[1] = ( block_yl ) * 1024;
223                 tree->mins[2] = map_mins[2] - 8;
224
225                 tree->maxs[0] = ( block_xh + 1 ) * 1024;
226                 tree->maxs[1] = ( block_yh + 1 ) * 1024;
227                 tree->maxs[2] = map_maxs[2] + 8;
228
229                 //
230                 // perform the global operations
231                 //
232                 MakeTreePortals( tree );
233
234                 if ( FloodEntities( tree ) ) {
235                         FillOutside( tree->headnode );
236                 }
237                 else
238                 {
239
240                         Sys_FPrintf( SYS_NOXML, "**********************\n" );
241                         Sys_FPrintf( SYS_NOXML, "******* leaked *******\n" );
242                         Sys_FPrintf( SYS_NOXML, "**********************\n" );
243                         polyline = LeakFile( tree );
244                         leaknode = xmlNewNode( NULL, "message" );
245                         xmlNodeSetContent( leaknode, "MAP LEAKED\n" );
246                         xmlAddChild( leaknode, polyline );
247                         level[0] = (int) '0' + SYS_ERR;
248                         level[1] = 0;
249                         xmlSetProp( leaknode, "level", (char*) &level );
250                         xml_SendNode( leaknode );
251                         if ( leaktest ) {
252                                 Sys_Printf( "--- MAP LEAKED, ABORTING LEAKTEST ---\n" );
253                                 exit( 0 );
254                         }
255                         leaked = true;
256 /*
257             Sys_Printf ("**** leaked ****\n");
258             leaked = true;
259             LeakFile (tree);
260             if (leaktest)
261             {
262                 Sys_Printf ("--- MAP LEAKED ---\n");
263                 exit (0);
264             } */
265                 }
266
267                 MarkVisibleSides( tree, brush_start, brush_end );
268                 if ( noopt || leaked ) {
269                         break;
270                 }
271                 if ( !optimize ) {
272                         FreeTree( tree );
273                 }
274         }
275
276         FloodAreas( tree );
277         if ( glview ) {
278                 WriteGLView( tree, source );
279         }
280         MakeFaces( tree->headnode );
281         FixTjuncs( tree->headnode );
282
283         if ( !noprune ) {
284                 PruneNodes( tree->headnode );
285         }
286
287         WriteBSP( tree->headnode );
288
289         if ( !leaked ) {
290                 WritePortalFile( tree );
291         }
292
293         FreeTree( tree );
294 }
295
296 /*
297    ============
298    ProcessSubModel
299
300    ============
301  */
302 void ProcessSubModel( void ){
303         entity_t    *e;
304         int start, end;
305         tree_t      *tree;
306         bspbrush_t  *list;
307         vec3_t mins, maxs;
308
309         e = &entities[entity_num];
310
311         start = e->firstbrush;
312         end = start + e->numbrushes;
313
314         mins[0] = mins[1] = mins[2] = -4096;
315         maxs[0] = maxs[1] = maxs[2] = 4096;
316         list = MakeBspBrushList( start, end, mins, maxs );
317         if ( !nocsg ) {
318                 list = ChopBrushes( list );
319         }
320         tree = BrushBSP( list, mins, maxs );
321         MakeTreePortals( tree );
322         MarkVisibleSides( tree, start, end );
323         MakeFaces( tree->headnode );
324         FixTjuncs( tree->headnode );
325         WriteBSP( tree->headnode );
326         FreeTree( tree );
327 }
328
329 /*
330    ============
331    ProcessModels
332    ============
333  */
334 void ProcessModels( void ){
335         BeginBSPFile();
336
337         for ( entity_num = 0 ; entity_num < num_entities ; entity_num++ )
338         {
339                 if ( !entities[entity_num].numbrushes ) {
340                         continue;
341                 }
342
343                 Sys_FPrintf( SYS_VRB, "############### model %i ###############\n", nummodels );
344                 BeginModel();
345                 if ( entity_num == 0 ) {
346                         ProcessWorldModel();
347                 }
348                 else{
349                         ProcessSubModel();
350                 }
351                 EndModel();
352
353                 //if (!verboseentities)
354                 //      verbose = false;        // don't bother printing submodels
355         }
356
357         EndBSPFile();
358 }
359
360
361 /*
362    ============
363    main
364    ============
365  */
366 int BSP_Main(){
367         double start, end;
368         char path[1024];
369         int total_bsp_time;
370
371         Sys_Printf( "\n----- BSP ----\n\n" );
372
373
374         start = I_FloatTime();
375
376         ThreadSetDefault();
377         SetQdirFromPath( mapname );
378
379         strcpy( source, ExpandArg( mapname ) );
380         StripExtension( source );
381
382         // delete portal and line files
383         sprintf( path, "%s.prt", source );
384         remove( path );
385         sprintf( path, "%s.lin", source );
386         remove( path );
387
388         strcpy( name, ExpandArg( mapname ) );
389         DefaultExtension( name, ".map" );    // might be .reg
390
391         //
392         // if onlyents, just grab the entites and resave
393         //
394         if ( onlyents ) {
395                 char out[1024];
396
397                 sprintf( out, "%s.bsp", source );
398                 LoadBSPFile( out );
399                 num_entities = 0;
400
401                 LoadMapFile( name );
402                 SetModelNumbers();
403                 SetLightStyles();
404
405                 UnparseEntities();
406
407                 WriteBSPFile( out );
408         }
409         else
410         {
411                 //
412                 // start from scratch
413                 //
414                 LoadMapFile( name );
415                 SetModelNumbers();
416                 SetLightStyles();
417
418                 ProcessModels();
419         }
420
421         end = I_FloatTime();
422         total_bsp_time = (int) ( end - start );
423         Sys_Printf( "\nBSP Time: " );
424         if ( total_bsp_time > 59 ) {
425                 Sys_Printf( "%d Minutes ", total_bsp_time / 60 );
426         }
427         Sys_Printf( "%d Seconds\n", total_bsp_time % 60 );
428
429
430         return 0;
431 }