Example #1
0
/*
============
ProcessSubModel

============
*/
void ProcessSubModel( )
{
	entity_t	*e;
	int			start, end;
	tree_t		*tree;
	bspbrush_t	*list;
	Vector		mins, maxs;

	e = &entities[entity_num];

	start = e->firstbrush;
	end = start + e->numbrushes;

	mins[0] = mins[1] = mins[2] = MIN_COORD_INTEGER;
	maxs[0] = maxs[1] = maxs[2] = MAX_COORD_INTEGER;
	list = MakeBspBrushList (start, end, mins, maxs, FULL_DETAIL);

	if (!nocsg)
		list = ChopBrushes (list);
	tree = BrushBSP (list, mins, maxs);
	
	// This would wind up crashing the engine because we'd have a negative leaf index in dmodel_t::headnode.
	if ( tree->headnode->planenum == PLANENUM_LEAF )
	{
		const char *pClassName = ValueForKey( e, "classname" );
		const char *pTargetName = ValueForKey( e, "targetname" );
		Error( "bmodel %d has no head node (class '%s', targetname '%s')", entity_num, pClassName, pTargetName );
	}

	MakeTreePortals (tree);
	
#if DEBUG_BRUSHMODEL
	if ( entity_num == DEBUG_BRUSHMODEL )
		WriteGLView( tree, "tree_all" );
#endif

	MarkVisibleSides (tree, start, end, FULL_DETAIL);
	MakeFaces (tree->headnode);

	FixTjuncs( tree->headnode, NULL );
	WriteBSP( tree->headnode, NULL );
	
#if DEBUG_BRUSHMODEL
	if ( entity_num == DEBUG_BRUSHMODEL )
	{
		WriteGLView( tree, "tree_vis" );
		WriteGLViewFaces( tree, "tree_faces" );
	}
#endif

	FreeTree (tree);
}
Example #2
0
/*
============
ProcessWorldModel

============
*/
void ProcessWorldModel (void)
{
	entity_t	*e;
	tree_t		*tree;
	qboolean	leaked;
	qboolean	optimize;

	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++)
	{
		qprintf ("--------------------------------------------\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.
		//

		qprintf ("--------------------------------------------\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
		{
			printf ("**** leaked ****\n");
			leaked = true;
			LeakFile (tree);
			if (leaktest)
			{
				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);
}
Example #3
0
void ProcessWorldModel (void)
{
	entity_t	*e;
	tree_t		*tree = NULL;
	qboolean	leaked;
	int	optimize;
	int			start;

	e = &entities[entity_num];

	brush_start = e->firstbrush;
	brush_end = brush_start + e->numbrushes;
	leaked = false;

	//
	// perform per-block operations
	//
	if (block_xh * BLOCKS_SIZE > g_MainMap->map_maxs[0])
	{
		block_xh = floor(g_MainMap->map_maxs[0]/BLOCKS_SIZE);
	}
	if ( (block_xl+1) * BLOCKS_SIZE < g_MainMap->map_mins[0])
	{
		block_xl = floor(g_MainMap->map_mins[0]/BLOCKS_SIZE);
	}
	if (block_yh * BLOCKS_SIZE > g_MainMap->map_maxs[1])
	{
		block_yh = floor(g_MainMap->map_maxs[1]/BLOCKS_SIZE);
	}
	if ( (block_yl+1) * BLOCKS_SIZE < g_MainMap->map_mins[1])
	{
		block_yl = floor(g_MainMap->map_mins[1]/BLOCKS_SIZE);
	}

	// HLTOOLS: updated to +/- MAX_COORD_INTEGER ( new world size limits / worldsize.h )
	if (block_xl < BLOCKS_MIN)
	{
		block_xl = BLOCKS_MIN;
	}
	if (block_yl < BLOCKS_MIN)
	{
		block_yl = BLOCKS_MIN;
	}
	if (block_xh > BLOCKS_MAX)
	{
		block_xh = BLOCKS_MAX;
	}
	if (block_yh > BLOCKS_MAX)
	{
		block_yh = BLOCKS_MAX;
	}

	for (optimize = 0 ; optimize <= 1 ; optimize++)
	{
		qprintf ("--------------------------------------------\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.
		//

		qprintf ("--------------------------------------------\n");

		tree = AllocTree ();
		tree->headnode = BlockTree (block_xl-1, block_yl-1, block_xh+1, block_yh+1);

		tree->mins[0] = (block_xl)*BLOCKS_SIZE;
		tree->mins[1] = (block_yl)*BLOCKS_SIZE;
		tree->mins[2] = g_MainMap->map_mins[2] - 8;

		tree->maxs[0] = (block_xh+1)*BLOCKS_SIZE;
		tree->maxs[1] = (block_yh+1)*BLOCKS_SIZE;
		tree->maxs[2] = g_MainMap->map_maxs[2] + 8;

		//
		// perform the global operations
		//

		// make the portals/faces by traversing down to each empty leaf
		MakeTreePortals (tree);

		if (FloodEntities (tree))
		{
			// turns everthing outside into solid
			FillOutside (tree->headnode);
		}
		else
		{
			Warning( ("**** leaked ****\n") );
			leaked = true;
			LeakFile (tree);
			if (leaktest)
			{
				Warning( ("--- MAP LEAKED ---\n") );
				exit (0);
			}
		}

		// mark the brush sides that actually turned into faces
		MarkVisibleSides (tree, brush_start, brush_end, NO_DETAIL);
		if (noopt || leaked)
			break;
		if (!optimize)
		{
			// If we are optimizing, free the tree.  Next time we will construct it again, but
			// we'll use the information in MarkVisibleSides() so we'll only split with planes that
			// actually contribute renderable geometry
			FreeTree (tree);
		}
	}

	FloodAreas (tree);

	RemoveAreaPortalBrushes_R( tree->headnode );

	start = Plat_FloatTime();
	Msg("Building Faces...");
	// this turns portals with one solid side into faces
	// it also subdivides each face if necessary to fit max lightmap dimensions
	MakeFaces (tree->headnode);
	Msg("done (%d)\n", (int)(Plat_FloatTime() - start) );

	if (glview)
	{
		WriteGLView (tree, source);
	}

	AssignOccluderAreas( tree );
	Compute3DSkyboxAreas( tree->headnode, g_SkyAreas );
	face_t *pLeafFaceList = NULL;
	if ( !nodetail )
	{
		pLeafFaceList = MergeDetailTree( tree, brush_start, brush_end );
	}

	start = Plat_FloatTime();

	Msg("FixTjuncs...\n");
	
	// This unifies the vertex list for all edges (splits collinear edges to remove t-junctions)
	// It also welds the list of vertices out of each winding/portal and rounds nearly integer verts to integer
	pLeafFaceList = FixTjuncs (tree->headnode, pLeafFaceList);

	// this merges all of the solid nodes that have separating planes
	if (!noprune)
	{
		Msg("PruneNodes...\n");
		PruneNodes (tree->headnode);
	}

//	Msg( "SplitSubdividedFaces...\n" );
//	SplitSubdividedFaces( tree->headnode );

	Msg("WriteBSP...\n");
	WriteBSP (tree->headnode, pLeafFaceList);
	Msg("done (%d)\n", (int)(Plat_FloatTime() - start) );

	if (!leaked)
	{
		WritePortalFile (tree);
	}

	FreeTree( tree );
	FreeLeafFaces( pLeafFaceList );
}
Example #4
0
/*
============
ProcessWorldModel

============
*/
void ProcessWorldModel( void ) {
	entity_t	*e;
	tree_t		*tree;
	bspface_t	*faces;
	qboolean	leaked;

	BeginModel();

	e = &entities[0];
	e->firstDrawSurf = 0;//numMapDrawSurfs;

	// check for patches with adjacent edges that need to LOD together
	PatchMapDrawSurfs( e );

	// build an initial bsp tree using all of the sides
	// of all of the structural brushes
	faces = MakeStructuralBspFaceList ( entities[0].brushes );
	tree = FaceBSP( faces );
	MakeTreePortals (tree);
	FilterStructuralBrushesIntoTree( e, tree );

	// see if the bsp is completely enclosed
	if ( FloodEntities (tree) ) {
		// rebuild a better bsp tree using only the
		// sides that are visible from the inside
		FillOutside (tree->headnode);

		// chop the sides to the convex hull of
		// their visible fragments, giving us the smallest
		// polygons 
		ClipSidesIntoTree( e, tree );

		faces = MakeVisibleBspFaceList( entities[0].brushes );
		FreeTree (tree);
		tree = FaceBSP( faces );
		MakeTreePortals( tree );
		FilterStructuralBrushesIntoTree( e, tree );
		leaked = qfalse;
	} else {
		_printf ("**********************\n");
		_printf ("******* leaked *******\n");
		_printf ("**********************\n");
		LeakFile (tree);
		if ( leaktest ) {
			_printf ("--- MAP LEAKED, ABORTING LEAKTEST ---\n");
			exit (0);
		}
		leaked = qtrue;

		// chop the sides to the convex hull of
		// their visible fragments, giving us the smallest
		// polygons 
		ClipSidesIntoTree( e, tree );
	}

	// save out information for visibility processing
	NumberClusters( tree );
	if ( !leaked ) {
		WritePortalFile( tree );
	}
	if ( glview ) {
		// dump the portals for debugging
		WriteGLView( tree, source );
	}
	FloodAreas (tree);

	// add references to the detail brushes
	FilterDetailBrushesIntoTree( e, tree );

	// create drawsurfs for triangle models
	AddTriangleModels( tree );

	// drawsurfs that cross fog boundaries will need to
	// be split along the bound
	if ( !nofog ) {
		FogDrawSurfs();		// may fragment drawsurfs
	}

	// subdivide each drawsurf as required by shader tesselation
	if ( !nosubdivide ) {
		SubdivideDrawSurfs( e, tree );
	}

	// merge together all common shaders on the same plane and remove 
	// all colinear points, so extra tjunctions won't be generated
	if ( !nomerge ) {
		MergeSides( e, tree );		// !@# testing
	}

	// add in any vertexes required to fix tjunctions
	if ( !notjunc ) {
		FixTJunctions( e );
	}

	// allocate lightmaps for faces and patches
	AllocateLightmaps( e );

	// add references to the final drawsurfs in the apropriate clusters
	FilterDrawsurfsIntoTree( e, tree );

	EndModel( tree->headnode );

	FreeTree (tree);
}
Example #5
0
File: bsp.c Project: otty/cake3
/*
============
ProcessWorldModel
============
*/
void ProcessWorldModel(void)
{
	int             s;
	entity_t       *e;
	tree_t         *tree;
	bspFace_t      *faces;
	qboolean        leaked;
	xmlNodePtr      polyline, leaknode;
	char            level[2];
	const char     *value;

	e = &entities[0];
	e->firstDrawSurf = 0;		//numMapDrawSurfs;

	// sets integer blockSize from worldspawn "_blocksize" key if it exists
	value = ValueForKey(e, "_blocksize");
	if(value[0] == '\0')
		value = ValueForKey(e, "blocksize");
	if(value[0] == '\0')
		value = ValueForKey(e, "chopsize");	// sof2
	if(value[0] != '\0')
	{
		// scan 3 numbers
		s = sscanf(value, "%d %d %d", &blockSize[0], &blockSize[1], &blockSize[2]);

		// handle legacy case
		if(s == 1)
		{
			blockSize[1] = blockSize[0];
			blockSize[2] = blockSize[0];
		}
	}
	Sys_Printf("block size = { %d %d %d }\n", blockSize[0], blockSize[1], blockSize[2]);

	BeginModel(e);

	// check for patches with adjacent edges that need to LOD together
	PatchMapDrawSurfs(e);

	// build an initial bsp tree using all of the sides
	// of all of the structural brushes
	faces = MakeStructuralBspFaceList(entities[0].brushes);
	tree = FaceBSP(faces);
	MakeTreePortals(tree);
	FilterStructuralBrushesIntoTree(e, tree);

	if(drawFlag)
	{
		// draw unoptimized portals in new window
		drawTree = tree;
		Draw_Scene(DrawTree);
	}

	// see if the bsp is completely enclosed
	if(FloodEntities(tree))
	{
		// rebuild a better bsp tree using only the
		// sides that are visible from the inside
		FillOutside(tree->headnode);

		// chop the sides to the convex hull of
		// their visible fragments, giving us the smallest
		// polygons 
		ClipSidesIntoTree(e, tree);

		faces = MakeVisibleBspFaceList(entities[0].brushes);
		FreeTree(tree);
		tree = FaceBSP(faces);
		MakeTreePortals(tree);
		FilterStructuralBrushesIntoTree(e, tree);
		leaked = qfalse;
	}
	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 = qtrue;

		// chop the sides to the convex hull of
		// their visible fragments, giving us the smallest
		// polygons 
		ClipSidesIntoTree(e, tree);
	}

	// save out information for visibility processing
	NumberClusters(tree);

	if(!leaked)
	{
		WritePortalFile(tree);
	}

	if(glview)
	{
		// dump the portals for debugging
		WriteGLView(tree, source);
	}

	FloodAreas(tree);

	if(drawFlag)
	{
		// draw optimized portals in new window
		drawTree = tree;
		Draw_Scene(DrawTree);
	}

	// add references to the detail brushes
	FilterDetailBrushesIntoTree(e, tree);

	// create drawsurfs for triangle models
	AddTriangleModels();

	// drawsurfs that cross fog boundaries will need to
	// be split along the bound
	if(!nofog)
	{
		FogDrawSurfs();			// may fragment drawsurfs
	}

	// subdivide each drawsurf as required by shader tesselation
	if(!nosubdivide)
	{
		SubdivideDrawSurfs(e, tree);
	}

	// merge together all common shaders on the same plane and remove 
	// all colinear points, so extra tjunctions won't be generated
	if(!nomerge)
	{
		MergeSides(e, tree);	// !@# testing
	}

	// add in any vertexes required to fix tjunctions
	if(!notjunc)
	{
		FixTJunctions(e);
	}

	// allocate lightmaps for faces and patches
	AllocateLightmaps(e);

	// add references to the final drawsurfs in the apropriate clusters
	FilterDrawsurfsIntoTree(e, tree);

	EndModel(e, tree->headnode);

	FreeTree(tree);
}
Example #6
0
/*
============
ProcessModel
============
*/
bool ProcessModel( uEntity_t* e, bool floodFill )
{
	bspface_t*	faces;
	
	// build a bsp tree using all of the sides
	// of all of the structural brushes
	faces = MakeStructuralBspFaceList( e->primitives );
	
	// RB: dump BSP for debugging
	if( dmapGlobals.glview )
	{
		WriteGLView( faces, "facelist" );
	}
	// RB end
	
	e->tree = FaceBSP( faces );
	
	// create portals at every leaf intersection
	// to allow flood filling
	MakeTreePortals( e->tree );
	
	// RB: calculate node numbers for split plane analysis
	NumberNodes_r( e->tree->headnode, 0 );
	
	// classify the leafs as opaque or areaportal
	FilterBrushesIntoTree( e );
	
	// RB: use mapTri_t by MapPolygonMesh primitives in case we don't use brushes
	FilterMeshesIntoTree( e );
	
	// RB: dump BSP for debugging
	//if( dmapGlobals.glview )
	//{
	//WriteGLView( e->tree, "unclipped", dmapGlobals.entityNum );
	//}
	// RB end
	
	// see if the bsp is completely enclosed
	if( floodFill && !dmapGlobals.noFlood )
	{
		if( FloodEntities( e->tree ) )
		{
			// set the outside leafs to opaque
			FillOutside( e );
		}
		else
		{
			common->Printf( "**********************\n" );
			common->Warning( "******* leaked *******" );
			common->Printf( "**********************\n" );
			LeakFile( e->tree );
			// bail out here.  If someone really wants to
			// process a map that leaks, they should use
			// -noFlood
			return false;
		}
	}
	
	// get minimum convex hulls for each visible side
	// this must be done before creating area portals,
	// because the visible hull is used as the portal
	ClipSidesByTree( e );
	
	// determine areas before clipping tris into the
	// tree, so tris will never cross area boundaries
	FloodAreas( e );
	
	// RB: dump BSP for debugging
	if( dmapGlobals.glview )
	{
		WriteGLView( e->tree, "areas", dmapGlobals.entityNum );
	}
	// RB end
	
	// we now have a BSP tree with solid and non-solid leafs marked with areas
	// all primitives will now be clipped into this, throwing away
	// fragments in the solid areas
	PutPrimitivesInAreas( e );
	
	// now build shadow volumes for the lights and split
	// the optimize lists by the light beam trees
	// so there won't be unneeded overdraw in the static
	// case
	Prelight( e );
	
	// optimizing is a superset of fixing tjunctions
	if( !dmapGlobals.noOptimize )
	{
		OptimizeEntity( e );
	}
	else  if( !dmapGlobals.noTJunc )
	{
		FixEntityTjunctions( e );
	}
	
	// now fix t junctions across areas
	FixGlobalTjunctions( e );
	
	return true;
}
Example #7
0
/*
============
Dmap
============
*/
void Dmap( const idCmdArgs& args )
{
	int			i;
	int			start, end;
	char		path[1024];
	idStr		passedName;
	bool		leaked = false;
	bool		noCM = false;
	bool		noAAS = false;
	
	ResetDmapGlobals();
	
	if( args.Argc() < 2 )
	{
		DmapHelp();
		return;
	}
	
	common->Printf( "---- dmap ----\n" );
	
	dmapGlobals.fullCarve = true;
	dmapGlobals.shadowOptLevel = SO_MERGE_SURFACES;		// create shadows by merging all surfaces, but no super optimization
//	dmapGlobals.shadowOptLevel = SO_CLIP_OCCLUDERS;		// remove occluders that are completely covered
//	dmapGlobals.shadowOptLevel = SO_SIL_OPTIMIZE;
//	dmapGlobals.shadowOptLevel = SO_CULL_OCCLUDED;

	dmapGlobals.noLightCarve = true;
	
	for( i = 1 ; i < args.Argc() ; i++ )
	{
		const char* s;
		
		s = args.Argv( i );
		if( s[0] == '-' )
		{
			s++;
			if( s[0] == '\0' )
			{
				continue;
			}
		}
		
		if( !idStr::Icmp( s, "glview" ) )
		{
			dmapGlobals.glview = true;
		}
		else if( !idStr::Icmp( s, "v" ) )
		{
			common->Printf( "verbose = true\n" );
			dmapGlobals.verbose = true;
		}
		else if( !idStr::Icmp( s, "draw" ) )
		{
			common->Printf( "drawflag = true\n" );
			dmapGlobals.drawflag = true;
		}
		else if( !idStr::Icmp( s, "noFlood" ) )
		{
			common->Printf( "noFlood = true\n" );
			dmapGlobals.noFlood = true;
		}
		else if( !idStr::Icmp( s, "noLightCarve" ) )
		{
			common->Printf( "noLightCarve = true\n" );
			dmapGlobals.noLightCarve = true;
		}
		else if( !idStr::Icmp( s, "lightCarve" ) )
		{
			common->Printf( "noLightCarve = false\n" );
			dmapGlobals.noLightCarve = false;
		}
		else if( !idStr::Icmp( s, "noOpt" ) )
		{
			common->Printf( "noOptimize = true\n" );
			dmapGlobals.noOptimize = true;
		}
		else if( !idStr::Icmp( s, "verboseentities" ) )
		{
			common->Printf( "verboseentities = true\n" );
			dmapGlobals.verboseentities = true;
		}
		else if( !idStr::Icmp( s, "noCurves" ) )
		{
			common->Printf( "noCurves = true\n" );
			dmapGlobals.noCurves = true;
		}
		else if( !idStr::Icmp( s, "noModels" ) )
		{
			common->Printf( "noModels = true\n" );
			dmapGlobals.noModelBrushes = true;
		}
		else if( !idStr::Icmp( s, "noClipSides" ) )
		{
			common->Printf( "noClipSides = true\n" );
			dmapGlobals.noClipSides = true;
		}
		else if( !idStr::Icmp( s, "noCarve" ) )
		{
			common->Printf( "noCarve = true\n" );
			dmapGlobals.fullCarve = false;
		}
		else if( !idStr::Icmp( s, "shadowOpt" ) )
		{
			dmapGlobals.shadowOptLevel = ( shadowOptLevel_t )atoi( args.Argv( i + 1 ) );
			common->Printf( "shadowOpt = %i\n", dmapGlobals.shadowOptLevel );
			i += 1;
		}
		else if( !idStr::Icmp( s, "noTjunc" ) )
		{
			// triangle optimization won't work properly without tjunction fixing
			common->Printf( "noTJunc = true\n" );
			dmapGlobals.noTJunc = true;
			dmapGlobals.noOptimize = true;
			common->Printf( "forcing noOptimize = true\n" );
		}
		else if( !idStr::Icmp( s, "noCM" ) )
		{
			noCM = true;
			common->Printf( "noCM = true\n" );
		}
		else if( !idStr::Icmp( s, "noAAS" ) )
		{
			noAAS = true;
			common->Printf( "noAAS = true\n" );
		}
		else
		{
			break;
		}
	}
	
	if( i >= args.Argc() )
	{
		common->Error( "usage: dmap [options] mapfile" );
	}
	
	passedName = args.Argv( i );		// may have an extension
	passedName.BackSlashesToSlashes();
	if( passedName.Icmpn( "maps/", 4 ) != 0 )
	{
		passedName = "maps/" + passedName;
	}
	
	idStr stripped = passedName;
	stripped.StripFileExtension();
	idStr::Copynz( dmapGlobals.mapFileBase, stripped, sizeof( dmapGlobals.mapFileBase ) );
	
	bool region = false;
	// if this isn't a regioned map, delete the last saved region map
	if( passedName.Right( 4 ) != ".reg" )
	{
		sprintf( path, "%s.reg", dmapGlobals.mapFileBase );
		fileSystem->RemoveFile( path );
	}
	else
	{
		region = true;
	}
	
	
	passedName = stripped;
	
	// delete any old line leak files
	sprintf( path, "%s.lin", dmapGlobals.mapFileBase );
	fileSystem->RemoveFile( path );
	
	// delete any old generated binary proc files
	idStr generated = va( "generated/%s.bproc", dmapGlobals.mapFileBase );
	fileSystem->RemoveFile( generated.c_str() );
	
	//
	// start from scratch
	//
	start = Sys_Milliseconds();
	
	if( !LoadDMapFile( passedName ) )
	{
		return;
	}
	
	if( ProcessModels() )
	{
		WriteOutputFile();
		
		// RB: dump BSP after nodes being pruned and optimized
		if( dmapGlobals.glview )
		{
			uEntity_t* world = &dmapGlobals.uEntities[0];
			
			WriteGLView( world->tree, "pruned", 0, true );
		}
		// RB end
	}
	else
	{
		leaked = true;
	}
	
	FreeDMapFile();
	
	common->Printf( "%i total shadow triangles\n", dmapGlobals.totalShadowTriangles );
	common->Printf( "%i total shadow verts\n", dmapGlobals.totalShadowVerts );
	
	end = Sys_Milliseconds();
	common->Printf( "-----------------------\n" );
	common->Printf( "%5.0f seconds for dmap\n", ( end - start ) * 0.001f );
	
	if( !leaked )
	{
	
		if( !noCM )
		{
		
			// make sure the collision model manager is not used by the game
			cmdSystem->BufferCommandText( CMD_EXEC_NOW, "disconnect" );
			
			// create the collision map
			start = Sys_Milliseconds();
			
			collisionModelManager->LoadMap( dmapGlobals.dmapFile );
			collisionModelManager->FreeMap();
			
			end = Sys_Milliseconds();
			common->Printf( "-------------------------------------\n" );
			common->Printf( "%5.0f seconds to create collision map\n", ( end - start ) * 0.001f );
		}
		
		if( !noAAS && !region )
		{
			// create AAS files
			RunAAS_f( args );
		}
	}
	
	// free the common .map representation
	delete dmapGlobals.dmapFile;
	
	// clear the map plane list
	dmapGlobals.mapPlanes.Clear();
}