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