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