Beispiel #1
0
/*
   ==================
   CalcPortalVis
   ==================
 */
void CalcPortalVis( void ){
#ifdef MREDEBUG
	Sys_Printf( "%6d portals out of %d", 0, numportals * 2 );
	//get rid of the counter
	RunThreadsOnIndividual( numportals * 2, qfalse, PortalFlow );
#else
	RunThreadsOnIndividual( numportals * 2, qtrue, PortalFlow );
#endif

}
Beispiel #2
0
/*
=============
RadWorld
=============
*/
void RadWorld (void)
{
	int	i;

	MakeBackplanes ();
	MakeParents (0, -1);
	MakeTnodes (&dmodels[0]);

	// turn each face into a single patch
	MakePatches ();
	PairEdges ();

	// subdivide patches to a maximum dimension
	SubdividePatches ();

	do
	{
		// create directlights out of patches and lights
		CreateDirectLights ();

		// build initial facelights
		RunThreadsOnIndividual (numfaces, true, BuildFacelights);

		// free up the direct lights now that we have facelights
		DeleteDirectLights ();
	}
	while( numbounce != 0 && ProgressiveRefinement() );

	if (numbounce > 0)
	{
		// build transfer lists
		MakeAllScales ();

		// invert the transfers for gather vs scatter
		RunThreadsOnIndividual (num_patches, true, SwapTransfersTask);

		// spread light around
		BounceLight ();

		for( i=0; i < num_patches; i++ )
			if ( !VectorCompare( patches[i].directlight, vec3_origin ) )
				VectorSubtract( patches[i].totallight, patches[i].directlight, patches[i].totallight );
	}

	// blend bounced light into direct light and save
	PrecompLightmapOffsets();

	RunThreadsOnIndividual (numfaces, true, FinalLightFace);
}
void RadCreateDiffuseLights( void ){
	/* startup */
	Sys_FPrintf( SYS_VRB, "--- RadCreateDiffuseLights ---\n" );
	numDiffuseSurfaces = 0;
	numDiffuseLights = 0;
	numBrushDiffuseLights = 0;
	numTriangleDiffuseLights = 0;
	numPatchDiffuseLights = 0;
	numAreaLights = 0;

	/* hit every surface (threaded) */
	RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, RadLight );

	/* dump the lights generated to a file */
	if ( dump ) {
		char dumpName[ 1024 ], ext[ 64 ];
		FILE    *file;
		light_t *light;

		strcpy( dumpName, source );
		StripExtension( dumpName );
		sprintf( ext, "_bounce_%03d.map", iterations );
		strcat( dumpName, ext );
		file = fopen( dumpName, "wb" );
		Sys_Printf( "Writing %s...\n", dumpName );
		if ( file ) {
			for ( light = lights; light; light = light->next )
			{
				fprintf( file,
						 "{\n"
						 "\"classname\" \"light\"\n"
						 "\"light\" \"%d\"\n"
						 "\"origin\" \"%.0f %.0f %.0f\"\n"
						 "\"_color\" \"%.3f %.3f %.3f\"\n"
						 "}\n",

						 (int) light->add,

						 light->origin[ 0 ],
						 light->origin[ 1 ],
						 light->origin[ 2 ],

						 light->color[ 0 ],
						 light->color[ 1 ],
						 light->color[ 2 ] );
			}
			fclose( file );
		}
	}

	/* increment */
	iterations++;

	/* print counts */
	Sys_Printf( "%8d diffuse surfaces\n", numDiffuseSurfaces );
	Sys_FPrintf( SYS_VRB, "%8d total diffuse lights\n", numDiffuseLights );
	Sys_FPrintf( SYS_VRB, "%8d brush diffuse lights\n", numBrushDiffuseLights );
	Sys_FPrintf( SYS_VRB, "%8d patch diffuse lights\n", numPatchDiffuseLights );
	Sys_FPrintf( SYS_VRB, "%8d triangle diffuse lights\n", numTriangleDiffuseLights );
}
Beispiel #4
0
/*
==================
CalcPortalVis
==================
*/
void CalcPortalVis (void)
{
    int		i;

    // fastvis just uses mightsee for a very loose bound
    if( fastvis )
    {
        for (i=0 ; i<g_numportals*2 ; i++)
        {
            portals[i].portalvis = portals[i].portalflood;
            portals[i].status = stat_done;
        }
        return;
    }


    if (g_bUseMPI)
    {
        RunMPIPortalFlow();
    }
    else
    {
        RunThreadsOnIndividual (g_numportals*2, true, PortalFlow);
    }
}
Beispiel #5
0
/*
   ==================
   CalcPassagePortalVis
   ==================
 */
void CalcPassagePortalVis( void ){
	PassageMemory();

#ifdef MREDEBUG
	Sys_Printf( "%6d portals out of %d", 0, numportals * 2 );
	RunThreadsOnIndividual( numportals * 2, qfalse, CreatePassages );
	Sys_Printf( "\n" );
	Sys_Printf( "%6d portals out of %d", 0, numportals * 2 );
	RunThreadsOnIndividual( numportals * 2, qfalse, PassagePortalFlow );
	Sys_Printf( "\n" );
#else
	Sys_Printf( "\n--- CreatePassages (%d) ---\n", numportals * 2 );
	RunThreadsOnIndividual( numportals * 2, qtrue, CreatePassages );

	Sys_Printf( "\n--- PassagePortalFlow (%d) ---\n", numportals * 2 );
	RunThreadsOnIndividual( numportals * 2, qtrue, PassagePortalFlow );
#endif
}
Beispiel #6
0
/*
   ==================
   CalcVis
   ==================
 */
void CalcVis( void ){
	int i;
	const char  *value;


	/* ydnar: rr2do2's farplane code */
	farPlaneDist = 0.0f;
	value = ValueForKey( &entities[ 0 ], "_farplanedist" );     /* proper '_' prefixed key */
	if ( value[ 0 ] == '\0' ) {
		value = ValueForKey( &entities[ 0 ], "fogclip" );       /* wolf compatibility */
	}
	if ( value[ 0 ] == '\0' ) {
		value = ValueForKey( &entities[ 0 ], "distancecull" );  /* sof2 compatibility */
	}
	if ( value[ 0 ] != '\0' ) {
		farPlaneDist = atof( value );
		if ( farPlaneDist > 0.0f ) {
			Sys_Printf( "farplane distance = %.1f\n", farPlaneDist );
		}
		else{
			farPlaneDist = 0.0f;
		}
	}



	Sys_Printf( "\n--- BasePortalVis (%d) ---\n", numportals * 2 );
	RunThreadsOnIndividual( numportals * 2, qtrue, BasePortalVis );

//	RunThreadsOnIndividual (numportals*2, qtrue, BetterPortalVis);

	SortPortals();

	if ( fastvis ) {
		CalcFastVis();
	}
	else if ( noPassageVis ) {
		CalcPortalVis();
	}
	else if ( passageVisOnly ) {
		CalcPassageVis();
	}
	else {
		CalcPassagePortalVis();
	}
	//
	// assemble the leaf vis lists by oring and compressing the portal lists
	//
	Sys_Printf( "creating leaf vis...\n" );
	for ( i = 0 ; i < portalclusters ; i++ )
		ClusterMerge( i );

	Sys_Printf( "Total visible clusters: %i\n", totalvis );
	Sys_Printf( "Average clusters visible: %i\n", totalvis / portalclusters );
}
Beispiel #7
0
void ProcessModels (void)
{
	int		i, j, type;
	int		placed;
	int		first, contents;
	brush_t	temp;
	vec3_t	origin;

	for (i=0 ; i<num_entities ; i++)
	{
		if (!entities[i].numbrushes)
			continue;

		//
		// sort the contents down so stone bites water, etc
		//
		first = entities[i].firstbrush;
		placed = 0;
		for (type=0 ; type<4 ; type++)
		{
			contents = typecontents[type];
			for (j=placed+1 ; j< entities[i].numbrushes ; j++)
			{
				if (mapbrushes[first+j].contents == contents)
				{
					temp = mapbrushes[first+placed];
					mapbrushes[first+placed] = mapbrushes[j];
					mapbrushes[j] = temp;
					placed++;
				}
			}
		}

		//
		// csg them in order
		//
		if (i == 0)
		{
			RunThreadsOnIndividual (entities[i].numbrushes, 1 , CSGBrush);
		}
		else
		{
			for (j=0 ; j<entities[i].numbrushes ; j++)
				CSGBrush (first + j);
		}

		// write end of model marker
		if (!glview)
		{
			for (j=0 ; j<NUM_HULLS ; j++)
				fprintf (out[j], "-1 -1 -1 -1\n");
		}
	}
}
Beispiel #8
0
/*
=============
LightWorld
=============
*/
void LightWorld (void)
{
	filebase = file_p = dlightdata;
	file_end = filebase + MAX_MAP_LIGHTING;

	RunThreadsOnIndividual (numfaces, true, LightFace);

	lightdatasize = file_p - filebase;
	
	printf ("lightdatasize: %i\n", lightdatasize);
}
Beispiel #9
0
/*
   ==================
   CalcVis
   ==================
 */
void CalcVis( void ){
	int i;

	RunThreadsOnIndividual( numportals * 2, true, BasePortalVis );

//	RunThreadsOnIndividual (numportals*2, true, BetterPortalVis);

	SortPortals();

	CalcPortalVis();

//
// assemble the leaf vis lists by oring and compressing the portal lists
//
	for ( i = 0 ; i < portalclusters ; i++ )
		ClusterMerge( i );

	Sys_Printf( "Average clusters visible: %i\n", totalvis / portalclusters );
}
Beispiel #10
0
/*
==================
CalcVis
==================
*/
void CalcVis (void)
{
    int		i;

    if (g_bUseMPI)
    {
        RunMPIBasePortalVis();
    }
    else
    {
        RunThreadsOnIndividual (g_numportals*2, true, BasePortalVis);
    }

    SortPortals ();

    CalcPortalVis ();

    //
    // assemble the leaf vis lists by oring the portal lists
    //
    for ( i = 0; i < portalclusters; i++ )
    {
        ClusterMerge( i );
    }

    int count = 0;
    // Now crosscheck each leaf's vis and compress
    for ( i = 0; i < portalclusters; i++ )
    {
        count += CompressAndCrosscheckClusterVis( i );
    }


    Msg ("Optimized: %d visible clusters (%.2f%%)\n", count, totalvis, count*100/totalvis);
    Msg ("Total clusters visible: %i\n", totalvis);
    Msg ("Average clusters visible: %i\n", totalvis / portalclusters);
}
Beispiel #11
0
/*
==================
CalcVis
==================
*/
void CalcVis(void)
{
	int             i, minvis, maxvis;
	const char     *value;
	double          mu, sigma, totalvis, totalvis2;


	/* ydnar: rr2do2's farplane code */
	farPlaneDist = 0.0f;
	value = ValueForKey(&entities[0], "_farplanedist");	/* proper '_' prefixed key */
	if(value[0] == '\0')
		value = ValueForKey(&entities[0], "fogclip");	/* wolf compatibility */
	if(value[0] == '\0')
		value = ValueForKey(&entities[0], "distancecull");	/* sof2 compatibility */
	if(value[0] != '\0')
	{
		farPlaneDist = atof(value);
		if(farPlaneDist > 0.0f)
			Sys_Printf("farplane distance = %.1f\n", farPlaneDist);
		else
			farPlaneDist = 0.0f;
	}



	Sys_Printf("\n--- BasePortalVis (%d) ---\n", numportals * 2);
	RunThreadsOnIndividual(numportals * 2, qtrue, BasePortalVis);

//  RunThreadsOnIndividual (numportals*2, qtrue, BetterPortalVis);

	SortPortals();

	if(fastvis)
	{
		CalcFastVis();
	}
	else if(noPassageVis)
	{
		CalcPortalVis();
	}
	else if(passageVisOnly)
	{
		CalcPassageVis();
	}
	else
	{
		CalcPassagePortalVis();
	}
	//
	// assemble the leaf vis lists by oring and compressing the portal lists
	//
	Sys_Printf("creating leaf vis...\n");
	for(i = 0; i < portalclusters; i++)
		ClusterMerge(i);

	totalvis = 0;
	totalvis2 = 0;
	minvis = -1;
	maxvis = -1;
	for(i = 0; i < MAX_MAP_LEAFS; ++i)
		if(clustersizehistogram[i])
		{
			if(debugCluster)
				Sys_FPrintf(SYS_VRB, "%4i clusters have exactly %4i visible clusters\n", clustersizehistogram[i], i);
			/* cast is to prevent integer overflow */
			totalvis += ((double)i) * ((double)clustersizehistogram[i]);
			totalvis2 += ((double)i) * ((double)i) * ((double)clustersizehistogram[i]);

			if(minvis < 0)
				minvis = i;
			maxvis = i;
		}

	mu = totalvis / portalclusters;
	sigma = sqrt(totalvis2 / portalclusters - mu * mu);

	Sys_Printf("Total clusters: %i\n", portalclusters);
	Sys_Printf("Total visible clusters: %.0f\n", totalvis);
	Sys_Printf("Average clusters visible: %.2f (%.3f%%/total)\n", mu, mu / portalclusters * 100.0);
	Sys_Printf("  Standard deviation: %.2f (%.3f%%/total, %.3f%%/avg)\n", sigma, sigma / portalclusters * 100.0,
			   sigma / mu * 100.0);
	Sys_Printf("  Minimum: %i (%.3f%%/total, %.3f%%/avg)\n", minvis, minvis / (double)portalclusters * 100.0,
			   minvis / mu * 100.0);
	Sys_Printf("  Maximum: %i (%.3f%%/total, %.3f%%/avg)\n", maxvis, maxvis / (double)portalclusters * 100.0,
			   maxvis / mu * 100.0);
}
Beispiel #12
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);
}
Beispiel #13
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 );
}
Beispiel #14
0
int main (int argc, char **argv)
{
	int		i, j;
	int		hull;
	entity_t	*ent;
	char	source[1024];
	char	name[1024];
	double		start, end;

	printf( "qcsg.exe v2.8 (%s)\n", __DATE__ );
	printf ("---- qcsg ----\n" );

	for (i=1 ; i<argc ; i++)
	{
		if (!strcmp(argv[i],"-threads"))
		{
			numthreads = atoi (argv[i+1]);
			i++;
		}
		else if (!strcmp(argv[i],"-glview"))
		{
			glview = true;
		}
		else if (!strcmp(argv[i], "-v"))
		{
			printf ("verbose = true\n");
			verbose = true;
		}
		else if (!strcmp(argv[i], "-draw"))
		{
			printf ("drawflag = true\n");
			drawflag = true;
		}
		else if (!strcmp(argv[i], "-noclip"))
		{
			printf ("noclip = true\n");
			noclip = true;
		}
		else if (!strcmp(argv[i], "-onlyents"))
		{
			printf ("onlyents = true\n");
			onlyents = true;
		}
		else if (!strcmp(argv[i], "-nowadtextures"))
		{
			printf ("wadtextures = false\n");
			wadtextures = false;
		}
		else if (!strcmp(argv[i], "-wadinclude"))
		{
			pszWadInclude[nWadInclude++] = strdup( argv[i + 1] );
			i++;
		}
		else if( !strcmp( argv[ i ], "-proj" ) )
		{
			strcpy( qproject, argv[ i + 1 ] );
			i++;
		}
		else if (!strcmp(argv[i], "-hullfile"))
		{
			hullfile = true;
			strcpy( qhullfile, argv[i + 1] );
			i++;
		}
		else if (argv[i][0] == '-')
			Error ("Unknown option \"%s\"", argv[i]);
		else
			break;
	}

	if (i != argc - 1)
		Error ("usage: qcsg [-nowadtextures] [-wadinclude <name>] [-draw] [-glview] [-noclip] [-onlyents] [-proj <name>] [-threads #] [-v] [-hullfile <name>] mapfile");

	SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_ABOVE_NORMAL);
	start = I_FloatTime ();

	CheckHullFile( hullfile, qhullfile );

	ThreadSetDefault ();
	SetQdirFromPath (argv[i]);

	strcpy (source, ExpandArg (argv[i]));
	COM_FixSlashes(source);
	StripExtension (source);

	strcpy (name, ExpandArg (argv[i]));	
	DefaultExtension (name, ".map");	// might be .reg

	//
	// if onlyents, just grab the entites and resave
	//
	if (onlyents  && !glview)
	{
		char out[1024];
		int	old_entities;
		sprintf (out, "%s.bsp", source);
		LoadBSPFile (out);

		// Get the new entity data from the map file
		LoadMapFile (name);

		// Write it all back out again.
		WriteBSP (source);

		end = I_FloatTime ();
		printf ("%5.0f seconds elapsed\n", end-start);
		return 0;
	}

	//
	// start from scratch
	//
	LoadMapFile (name);

	RunThreadsOnIndividual (nummapbrushes, true, CreateBrush);

	BoundWorld ();

	qprintf ("%5i map planes\n", nummapplanes);

	for (i=0 ; i<NUM_HULLS ; i++)
	{
		char	name[1024];

		if (glview)
			sprintf (name, "%s.gl%i",source, i);
		else
			sprintf (name, "%s.p%i",source, i);
		out[i] = fopen (name, "w");
		if (!out[i])
			Error ("Couldn't open %s",name);
	}

	ProcessModels ();

	qprintf ("%5i csg faces\n", c_csgfaces);
	qprintf ("%5i used faces\n", c_outfaces);
	qprintf ("%5i tiny faces\n", c_tiny);
	qprintf ("%5i tiny clips\n", c_tiny_clip);

	for (i=0 ; i<NUM_HULLS ; i++)
		fclose (out[i]);

	if (!glview)
	{
		EmitPlanes ();
		WriteBSP (source);
	}

	end = I_FloatTime ();
	printf ("%5.0f seconds elapsed\n", end-start);

	return 0;
}