2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\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
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
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
25 extern float subdivide_size;
\r
30 vec_t microvolume = 1.0;
\r
34 qboolean fulldetail;
\r
46 qboolean verboseentities;
\r
50 int block_xl = -8, block_xh = 7, block_yl = -8, block_yh = 7;
\r
55 node_t *block_nodes[10][10];
\r
64 node_t *BlockTree (int xl, int yl, int xh, int yh)
\r
71 if (xl == xh && yl == yh)
\r
73 node = block_nodes[xl+5][yl+5];
\r
75 { // return an empty leaf
\r
76 node = AllocNode ();
\r
77 node->planenum = PLANENUM_LEAF;
\r
78 node->contents = 0; //CONTENTS_SOLID;
\r
84 // create a seperator along the largest axis
\r
85 node = AllocNode ();
\r
87 if (xh - xl > yh - yl)
\r
89 mid = xl + (xh-xl)/2 + 1;
\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
100 mid = yl + (yh-yl)/2 + 1;
\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
115 ProcessBlock_Thread
\r
119 int brush_start, brush_end;
\r
120 void ProcessBlock_Thread (int blocknum)
\r
122 int xblock, yblock;
\r
124 bspbrush_t *brushes;
\r
128 yblock = block_yl + blocknum / (block_xh-block_xl+1);
\r
129 xblock = block_xl + blocknum % (block_xh-block_xl+1);
\r
131 Sys_FPrintf( SYS_VRB, "############### block %2i,%2i ###############\n", xblock, yblock);
\r
133 mins[0] = xblock*1024;
\r
134 mins[1] = yblock*1024;
\r
136 maxs[0] = (xblock+1)*1024;
\r
137 maxs[1] = (yblock+1)*1024;
\r
140 // the makelist and chopbrushes could be cached between the passes...
\r
141 brushes = MakeBspBrushList (brush_start, brush_end, mins, maxs);
\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
152 brushes = ChopBrushes (brushes);
\r
154 tree = BrushBSP (brushes, mins, maxs);
\r
156 block_nodes[xblock+5][yblock+5] = tree->headnode;
\r
165 void ProcessWorldModel (void)
\r
171 xmlNodePtr polyline, leaknode;
\r
174 e = &entities[entity_num];
\r
176 brush_start = e->firstbrush;
\r
177 brush_end = brush_start + e->numbrushes;
\r
181 // perform per-block operations
\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
201 for (optimize = false ; optimize <= true ; optimize++)
\r
203 Sys_FPrintf( SYS_VRB, "--------------------------------------------\n");
\r
205 RunThreadsOnIndividual ((block_xh-block_xl+1)*(block_yh-block_yl+1),
\r
206 !verbose, ProcessBlock_Thread);
\r
209 // build the division tree
\r
210 // oversizing the blocks guarantees that all the boundaries
\r
211 // will also get nodes.
\r
214 Sys_FPrintf( SYS_VRB, "--------------------------------------------\n");
\r
216 tree = AllocTree ();
\r
217 tree->headnode = BlockTree (block_xl-1, block_yl-1, block_xh+1, block_yh+1);
\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
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
228 // perform the global operations
\r
230 MakeTreePortals (tree);
\r
232 if (FloodEntities (tree))
\r
233 FillOutside (tree->headnode);
\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
246 xmlSetProp( leaknode, "level", (char*) &level );
\r
247 xml_SendNode( leaknode );
\r
250 Sys_Printf ("--- MAP LEAKED, ABORTING LEAKTEST ---\n");
\r
255 Sys_Printf ("**** leaked ****\n");
\r
260 Sys_Printf ("--- MAP LEAKED ---\n");
\r
265 MarkVisibleSides (tree, brush_start, brush_end);
\r
266 if (noopt || leaked)
\r
276 WriteGLView (tree, source);
\r
277 MakeFaces (tree->headnode);
\r
278 FixTjuncs (tree->headnode);
\r
281 PruneNodes (tree->headnode);
\r
283 WriteBSP (tree->headnode);
\r
286 WritePortalFile (tree);
\r
297 void ProcessSubModel (void)
\r
305 e = &entities[entity_num];
\r
307 start = e->firstbrush;
\r
308 end = start + e->numbrushes;
\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
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
329 void ProcessModels (void)
\r
333 for (entity_num=0 ; entity_num< num_entities ; entity_num++)
\r
335 if (!entities[entity_num].numbrushes)
\r
338 Sys_FPrintf( SYS_VRB, "############### model %i ###############\n", nummodels);
\r
340 if (entity_num == 0)
\r
341 ProcessWorldModel ();
\r
343 ProcessSubModel ();
\r
346 //if (!verboseentities)
\r
347 // verbose = false; // don't bother printing submodels
\r
363 int total_bsp_time;
\r
365 Sys_Printf ("\n----- BSP ----\n\n");
\r
368 start = I_FloatTime ();
\r
370 ThreadSetDefault ();
\r
371 SetQdirFromPath (mapname);
\r
373 strcpy (source, ExpandArg (mapname));
\r
374 StripExtension (source);
\r
376 // delete portal and line files
\r
377 sprintf (path, "%s.prt", source);
\r
379 sprintf (path, "%s.lin", source);
\r
382 strcpy (name, ExpandArg (mapname));
\r
383 DefaultExtension (name, ".map"); // might be .reg
\r
386 // if onlyents, just grab the entites and resave
\r
392 sprintf (out, "%s.bsp", source);
\r
396 LoadMapFile (name);
\r
397 SetModelNumbers ();
\r
400 UnparseEntities ();
\r
402 WriteBSPFile (out);
\r
407 // start from scratch
\r
409 LoadMapFile (name);
\r
410 SetModelNumbers ();
\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