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