/* Copyright (C) 1999-2006 Id Software, Inc. and contributors. For a list of contributors, see the accompanying CONTRIBUTORS file. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // csg4.c #include "qbsp.h" extern float subdivide_size; char source[1024]; char name[1024]; vec_t microvolume = 1.0; qboolean noprune; qboolean glview; qboolean nodetail; qboolean fulldetail; qboolean onlyents; qboolean nomerge; qboolean nowater; qboolean nofill; qboolean nocsg; qboolean noweld; qboolean noshare; qboolean nosubdiv; qboolean notjunc; qboolean noopt; qboolean leaktest; qboolean verboseentities; char outbase[32]; int block_xl = -8, block_xh = 7, block_yl = -8, block_yh = 7; int entity_num; node_t *block_nodes[10][10]; /* ============ BlockTree ============ */ node_t *BlockTree( int xl, int yl, int xh, int yh ){ node_t *node; vec3_t normal; float dist; int mid; if ( xl == xh && yl == yh ) { node = block_nodes[xl + 5][yl + 5]; if ( !node ) { // return an empty leaf node = AllocNode(); node->planenum = PLANENUM_LEAF; node->contents = 0; //CONTENTS_SOLID; return node; } return node; } // create a seperator along the largest axis node = AllocNode(); if ( xh - xl > yh - yl ) { // split x axis mid = xl + ( xh - xl ) / 2 + 1; normal[0] = 1; normal[1] = 0; normal[2] = 0; dist = mid * 1024; node->planenum = FindFloatPlane( normal, dist ); node->children[0] = BlockTree( mid, yl, xh, yh ); node->children[1] = BlockTree( xl, yl, mid - 1, yh ); } else { mid = yl + ( yh - yl ) / 2 + 1; normal[0] = 0; normal[1] = 1; normal[2] = 0; dist = mid * 1024; node->planenum = FindFloatPlane( normal, dist ); node->children[0] = BlockTree( xl, mid, xh, yh ); node->children[1] = BlockTree( xl, yl, xh, mid - 1 ); } return node; } /* ============ ProcessBlock_Thread ============ */ int brush_start, brush_end; void ProcessBlock_Thread( int blocknum ){ int xblock, yblock; vec3_t mins, maxs; bspbrush_t *brushes; tree_t *tree; node_t *node; yblock = block_yl + blocknum / ( block_xh - block_xl + 1 ); xblock = block_xl + blocknum % ( block_xh - block_xl + 1 ); Sys_FPrintf( SYS_VRB, "############### block %2i,%2i ###############\n", xblock, yblock ); mins[0] = xblock * 1024; mins[1] = yblock * 1024; mins[2] = -4096; maxs[0] = ( xblock + 1 ) * 1024; maxs[1] = ( yblock + 1 ) * 1024; maxs[2] = 4096; // the makelist and chopbrushes could be cached between the passes... brushes = MakeBspBrushList( brush_start, brush_end, mins, maxs ); if ( !brushes ) { node = AllocNode(); node->planenum = PLANENUM_LEAF; node->contents = CONTENTS_SOLID; block_nodes[xblock + 5][yblock + 5] = node; return; } if ( !nocsg ) { brushes = ChopBrushes( brushes ); } tree = BrushBSP( brushes, mins, maxs ); block_nodes[xblock + 5][yblock + 5] = tree->headnode; } /* ============ ProcessWorldModel ============ */ void ProcessWorldModel( void ){ entity_t *e; tree_t *tree; qboolean leaked; qboolean optimize; xmlNodePtr polyline, leaknode; char level[ 2 ]; e = &entities[entity_num]; brush_start = e->firstbrush; brush_end = brush_start + e->numbrushes; leaked = false; // // perform per-block operations // if ( block_xh * 1024 > map_maxs[0] ) { block_xh = floor( map_maxs[0] / 1024.0 ); } if ( ( block_xl + 1 ) * 1024 < map_mins[0] ) { block_xl = floor( map_mins[0] / 1024.0 ); } if ( block_yh * 1024 > map_maxs[1] ) { block_yh = floor( map_maxs[1] / 1024.0 ); } if ( ( block_yl + 1 ) * 1024 < map_mins[1] ) { block_yl = floor( map_mins[1] / 1024.0 ); } if ( block_xl < -4 ) { block_xl = -4; } if ( block_yl < -4 ) { block_yl = -4; } if ( block_xh > 3 ) { block_xh = 3; } if ( block_yh > 3 ) { block_yh = 3; } for ( optimize = false ; optimize <= true ; optimize++ ) { Sys_FPrintf( SYS_VRB, "--------------------------------------------\n" ); RunThreadsOnIndividual( ( block_xh - block_xl + 1 ) * ( block_yh - block_yl + 1 ), !verbose, ProcessBlock_Thread ); // // build the division tree // oversizing the blocks guarantees that all the boundaries // will also get nodes. // Sys_FPrintf( SYS_VRB, "--------------------------------------------\n" ); tree = AllocTree(); tree->headnode = BlockTree( block_xl - 1, block_yl - 1, block_xh + 1, block_yh + 1 ); tree->mins[0] = ( block_xl ) * 1024; tree->mins[1] = ( block_yl ) * 1024; tree->mins[2] = map_mins[2] - 8; tree->maxs[0] = ( block_xh + 1 ) * 1024; tree->maxs[1] = ( block_yh + 1 ) * 1024; tree->maxs[2] = map_maxs[2] + 8; // // perform the global operations // MakeTreePortals( tree ); if ( FloodEntities( tree ) ) { FillOutside( tree->headnode ); } else { Sys_FPrintf( SYS_NOXML, "**********************\n" ); Sys_FPrintf( SYS_NOXML, "******* leaked *******\n" ); Sys_FPrintf( SYS_NOXML, "**********************\n" ); polyline = LeakFile( tree ); leaknode = xmlNewNode( NULL, "message" ); xmlNodeSetContent( leaknode, "MAP LEAKED\n" ); xmlAddChild( leaknode, polyline ); level[0] = (int) '0' + SYS_ERR; level[1] = 0; xmlSetProp( leaknode, "level", (char*) &level ); xml_SendNode( leaknode ); if ( leaktest ) { Sys_Printf( "--- MAP LEAKED, ABORTING LEAKTEST ---\n" ); exit( 0 ); } leaked = true; /* Sys_Printf ("**** leaked ****\n"); leaked = true; LeakFile (tree); if (leaktest) { Sys_Printf ("--- MAP LEAKED ---\n"); exit (0); } */ } MarkVisibleSides( tree, brush_start, brush_end ); if ( noopt || leaked ) { break; } if ( !optimize ) { FreeTree( tree ); } } FloodAreas( tree ); if ( glview ) { WriteGLView( tree, source ); } MakeFaces( tree->headnode ); FixTjuncs( tree->headnode ); if ( !noprune ) { PruneNodes( tree->headnode ); } WriteBSP( tree->headnode ); if ( !leaked ) { WritePortalFile( tree ); } FreeTree( tree ); } /* ============ ProcessSubModel ============ */ void ProcessSubModel( void ){ entity_t *e; int start, end; tree_t *tree; bspbrush_t *list; vec3_t mins, maxs; e = &entities[entity_num]; start = e->firstbrush; end = start + e->numbrushes; mins[0] = mins[1] = mins[2] = -4096; maxs[0] = maxs[1] = maxs[2] = 4096; list = MakeBspBrushList( start, end, mins, maxs ); if ( !nocsg ) { list = ChopBrushes( list ); } tree = BrushBSP( list, mins, maxs ); MakeTreePortals( tree ); MarkVisibleSides( tree, start, end ); MakeFaces( tree->headnode ); FixTjuncs( tree->headnode ); WriteBSP( tree->headnode ); FreeTree( tree ); } /* ============ ProcessModels ============ */ void ProcessModels( void ){ BeginBSPFile(); for ( entity_num = 0 ; entity_num < num_entities ; entity_num++ ) { if ( !entities[entity_num].numbrushes ) { continue; } Sys_FPrintf( SYS_VRB, "############### model %i ###############\n", nummodels ); BeginModel(); if ( entity_num == 0 ) { ProcessWorldModel(); } else{ ProcessSubModel(); } EndModel(); //if (!verboseentities) // verbose = false; // don't bother printing submodels } EndBSPFile(); } /* ============ main ============ */ int BSP_Main(){ double start, end; char path[1024]; int total_bsp_time; Sys_Printf( "\n----- BSP ----\n\n" ); start = I_FloatTime(); ThreadSetDefault(); SetQdirFromPath( mapname ); strcpy( source, ExpandArg( mapname ) ); StripExtension( source ); // delete portal and line files sprintf( path, "%s.prt", source ); remove( path ); sprintf( path, "%s.lin", source ); remove( path ); strcpy( name, ExpandArg( mapname ) ); DefaultExtension( name, ".map" ); // might be .reg // // if onlyents, just grab the entites and resave // if ( onlyents ) { char out[1024]; sprintf( out, "%s.bsp", source ); LoadBSPFile( out ); num_entities = 0; LoadMapFile( name ); SetModelNumbers(); SetLightStyles(); UnparseEntities(); WriteBSPFile( out ); } else { // // start from scratch // LoadMapFile( name ); SetModelNumbers(); SetLightStyles(); ProcessModels(); } end = I_FloatTime(); total_bsp_time = (int) ( end - start ); Sys_Printf( "\nBSP Time: " ); if ( total_bsp_time > 59 ) { Sys_Printf( "%d Minutes ", total_bsp_time / 60 ); } Sys_Printf( "%d Seconds\n", total_bsp_time % 60 ); return 0; }