From 39ed87570bdb2f86969d4be821c94b722dc71179 Mon Sep 17 00:00:00 2001 From: Joe Ludwig Date: Wed, 26 Jun 2013 15:22:04 -0700 Subject: First version of the SOurce SDK 2013 --- mp/src/utils/vvis/vvis.cpp | 1240 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1240 insertions(+) create mode 100644 mp/src/utils/vvis/vvis.cpp (limited to 'mp/src/utils/vvis/vvis.cpp') diff --git a/mp/src/utils/vvis/vvis.cpp b/mp/src/utils/vvis/vvis.cpp new file mode 100644 index 00000000..577c1cc3 --- /dev/null +++ b/mp/src/utils/vvis/vvis.cpp @@ -0,0 +1,1240 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// vis.c + +#include +#include "vis.h" +#include "threads.h" +#include "stdlib.h" +#include "pacifier.h" +#include "vmpi.h" +#include "mpivis.h" +#include "tier1/strtools.h" +#include "collisionutils.h" +#include "tier0/icommandline.h" +#include "vmpi_tools_shared.h" +#include "ilaunchabledll.h" +#include "tools_minidump.h" +#include "loadcmdline.h" +#include "byteswap.h" + + +int g_numportals; +int portalclusters; + +char inbase[32]; + +portal_t *portals; +leaf_t *leafs; + +int c_portaltest, c_portalpass, c_portalcheck; + +byte *uncompressedvis; + +byte *vismap, *vismap_p, *vismap_end; // past visfile +int originalvismapsize; + +int leafbytes; // (portalclusters+63)>>3 +int leaflongs; + +int portalbytes, portallongs; + +bool fastvis; +bool nosort; + +int totalvis; + +portal_t *sorted_portals[MAX_MAP_PORTALS*2]; + +bool g_bUseRadius = false; +double g_VisRadius = 4096.0f * 4096.0f; + +bool g_bLowPriority = false; + +//============================================================================= + +void PlaneFromWinding (winding_t *w, plane_t *plane) +{ + Vector v1, v2; + +// calc plane + VectorSubtract (w->points[2], w->points[1], v1); + VectorSubtract (w->points[0], w->points[1], v2); + CrossProduct (v2, v1, plane->normal); + VectorNormalize (plane->normal); + plane->dist = DotProduct (w->points[0], plane->normal); +} + + +/* +================== +NewWinding +================== +*/ +winding_t *NewWinding (int points) +{ + winding_t *w; + int size; + + if (points > MAX_POINTS_ON_WINDING) + Error ("NewWinding: %i points, max %d", points, MAX_POINTS_ON_WINDING); + + size = (int)(&((winding_t *)0)->points[points]); + w = (winding_t*)malloc (size); + memset (w, 0, size); + + return w; +} + +void pw(winding_t *w) +{ + int i; + for (i=0 ; inumpoints ; i++) + Msg ("(%5.1f, %5.1f, %5.1f)\n",w->points[i][0], w->points[i][1],w->points[i][2]); +} + +void prl(leaf_t *l) +{ + int i; + portal_t *p; + plane_t pl; + + int count = l->portals.Count(); + for (i=0 ; iportals[i]; + pl = p->plane; + Msg ("portal %4i to leaf %4i : %7.1f : (%4.1f, %4.1f, %4.1f)\n",(int)(p-portals),p->leaf,pl.dist, pl.normal[0], pl.normal[1], pl.normal[2]); + } +} + + +//============================================================================= + +/* +============= +SortPortals + +Sorts the portals from the least complex, so the later ones can reuse +the earlier information. +============= +*/ +int PComp (const void *a, const void *b) +{ + if ( (*(portal_t **)a)->nummightsee == (*(portal_t **)b)->nummightsee) + return 0; + if ( (*(portal_t **)a)->nummightsee < (*(portal_t **)b)->nummightsee) + return -1; + + return 1; +} + +void BuildTracePortals( int clusterStart ) +{ + leaf_t *leaf = &leafs[g_TraceClusterStart]; + g_numportals = leaf->portals.Count(); + for ( int i = 0; i < g_numportals; i++ ) + { + sorted_portals[i] = leaf->portals[i]; + } +} + +void SortPortals (void) +{ + int i; + + for (i=0 ; ileaf ); + } + } + + c_leafs = CountBits (leafbits, portalclusters); + + return c_leafs; +} + + +/* +=============== +ClusterMerge + +Merges the portal visibility for a leaf +=============== +*/ +void ClusterMerge (int clusternum) +{ + leaf_t *leaf; +// byte portalvector[MAX_PORTALS/8]; + byte portalvector[MAX_PORTALS/4]; // 4 because portal bytes is * 2 + byte uncompressed[MAX_MAP_LEAFS/8]; + int i, j; + int numvis; + portal_t *p; + int pnum; + + // OR together all the portalvis bits + + memset (portalvector, 0, portalbytes); + leaf = &leafs[clusternum]; + for (i=0 ; i < leaf->portals.Count(); i++) + { + p = leaf->portals[i]; + if (p->status != stat_done) + Error ("portal not done %d %p %p\n", i, p, portals); + for (j=0 ; jportalvis)[j]; + pnum = p - portals; + SetBit( portalvector, pnum ); + } + + // convert portal bits to leaf bits + numvis = LeafVectorFromPortalVector (portalvector, uncompressed); + +#if 0 + // func_viscluster makes this happen all the time because it allows a non-convex set of portals + // My analysis says this is ok, but it does make this check for errors in vis kind of useless + if ( CheckBit( uncompressed, clusternum ) ) + Warning("WARNING: Cluster portals saw into cluster\n"); +#endif + + SetBit( uncompressed, clusternum ); + numvis++; // count the leaf itself + + // save uncompressed for PHS calculation + memcpy (uncompressedvis + clusternum*leafbytes, uncompressed, leafbytes); + + qprintf ("cluster %4i : %4i visible\n", clusternum, numvis); + totalvis += numvis; +} + +static int CompressAndCrosscheckClusterVis( int clusternum ) +{ + int optimized = 0; + byte compressed[MAX_MAP_LEAFS/8]; +// +// compress the bit string +// + byte *uncompressed = uncompressedvis + clusternum*leafbytes; + for ( int i = 0; i < portalclusters; i++ ) + { + if ( i == clusternum ) + continue; + + if ( CheckBit( uncompressed, i ) ) + { + byte *other = uncompressedvis + i*leafbytes; + if ( !CheckBit( other, clusternum ) ) + { + ClearBit( uncompressed, i ); + optimized++; + } + } + } + int numbytes = CompressVis( uncompressed, compressed ); + + byte *dest = vismap_p; + vismap_p += numbytes; + + if (vismap_p > vismap_end) + Error ("Vismap expansion overflow"); + + dvis->bitofs[clusternum][DVIS_PVS] = dest-vismap; + + memcpy( dest, compressed, numbytes ); + + // check vis data + DecompressVis( vismap + dvis->bitofs[clusternum][DVIS_PVS], compressed ); + + return optimized; +} + + +/* +================== +CalcPortalVis +================== +*/ +void CalcPortalVis (void) +{ + int i; + + // fastvis just uses mightsee for a very loose bound + if( fastvis ) + { + for (i=0 ; iwinding; + VectorCopy (vec3_origin, total); + for (i=0 ; inumpoints ; i++) + { + VectorAdd (total, w->points[i], total); + } + + for (i=0 ; i<3 ; i++) + total[i] /= w->numpoints; + + bestr = 0; + for (i=0 ; inumpoints ; i++) + { + VectorSubtract (w->points[i], total, dist); + r = VectorLength (dist); + if (r > bestr) + bestr = r; + } + VectorCopy (total, p->origin); + p->radius = bestr; +} + +/* +============ +LoadPortals +============ +*/ +void LoadPortals (char *name) +{ + int i, j; + portal_t *p; + leaf_t *l; + char magic[80]; + int numpoints; + winding_t *w; + int leafnums[2]; + plane_t plane; + + FILE *f; + + // Open the portal file. + if ( g_bUseMPI ) + { + // If we're using MPI, copy off the file to a temporary first. This will download the file + // from the MPI master, then we get to use nice functions like fscanf on it. + char tempPath[MAX_PATH], tempFile[MAX_PATH]; + if ( GetTempPath( sizeof( tempPath ), tempPath ) == 0 ) + { + Error( "LoadPortals: GetTempPath failed.\n" ); + } + + if ( GetTempFileName( tempPath, "vvis_portal_", 0, tempFile ) == 0 ) + { + Error( "LoadPortals: GetTempFileName failed.\n" ); + } + + // Read all the data from the network file into memory. + FileHandle_t hFile = g_pFileSystem->Open(name, "r"); + if ( hFile == FILESYSTEM_INVALID_HANDLE ) + Error( "LoadPortals( %s ): couldn't get file from master.\n", name ); + + CUtlVector data; + data.SetSize( g_pFileSystem->Size( hFile ) ); + g_pFileSystem->Read( data.Base(), data.Count(), hFile ); + g_pFileSystem->Close( hFile ); + + // Dump it into a temp file. + f = fopen( tempFile, "wt" ); + fwrite( data.Base(), 1, data.Count(), f ); + fclose( f ); + + // Open the temp file up. + f = fopen( tempFile, "rSTD" ); // read only, sequential, temporary, delete on close + } + else + { + f = fopen( name, "r" ); + } + + if ( !f ) + Error ("LoadPortals: couldn't read %s\n",name); + + if (fscanf (f,"%79s\n%i\n%i\n",magic, &portalclusters, &g_numportals) != 3) + Error ("LoadPortals %s: failed to read header", name); + if (stricmp(magic,PORTALFILE)) + Error ("LoadPortals %s: not a portal file", name); + + Msg ("%4i portalclusters\n", portalclusters); + Msg ("%4i numportals\n", g_numportals); + + if (g_numportals * 2 >= MAX_PORTALS) + { + Error("The map overflows the max portal count (%d of max %d)!\n", g_numportals, MAX_PORTALS / 2 ); + } + + // these counts should take advantage of 64 bit systems automatically + leafbytes = ((portalclusters+63)&~63)>>3; + leaflongs = leafbytes/sizeof(long); + + portalbytes = ((g_numportals*2+63)&~63)>>3; + portallongs = portalbytes/sizeof(long); + +// each file portal is split into two memory portals + portals = (portal_t*)malloc(2*g_numportals*sizeof(portal_t)); + memset (portals, 0, 2*g_numportals*sizeof(portal_t)); + + leafs = (leaf_t*)malloc(portalclusters*sizeof(leaf_t)); + memset (leafs, 0, portalclusters*sizeof(leaf_t)); + + originalvismapsize = portalclusters*leafbytes; + uncompressedvis = (byte*)malloc(originalvismapsize); + + vismap = vismap_p = dvisdata; + dvis->numclusters = portalclusters; + vismap_p = (byte *)&dvis->bitofs[portalclusters]; + + vismap_end = vismap + MAX_MAP_VISIBILITY; + + for (i=0, p=portals ; i MAX_POINTS_ON_WINDING) + Error ("LoadPortals: portal %i has too many points", i); + if ( (unsigned)leafnums[0] > portalclusters + || (unsigned)leafnums[1] > portalclusters) + Error ("LoadPortals: reading portal %i", i); + + w = p->winding = NewWinding (numpoints); + w->original = true; + w->numpoints = numpoints; + + for (j=0 ; jpoints[j][k] = v[k]; + } + fscanf (f, "\n"); + + // calc plane + PlaneFromWinding (w, &plane); + + // create forward portal + l = &leafs[leafnums[0]]; + l->portals.AddToTail(p); + + p->winding = w; + VectorSubtract (vec3_origin, plane.normal, p->plane.normal); + p->plane.dist = -plane.dist; + p->leaf = leafnums[1]; + SetPortalSphere (p); + p++; + + // create backwards portal + l = &leafs[leafnums[1]]; + l->portals.AddToTail(p); + + p->winding = NewWinding(w->numpoints); + p->winding->numpoints = w->numpoints; + for (j=0 ; jnumpoints ; j++) + { + VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]); + } + + p->plane = plane; + p->leaf = leafnums[0]; + SetPortalSphere (p); + p++; + + } + + fclose (f); +} + + +/* +================ +CalcPAS + +Calculate the PAS (Potentially Audible Set) +by ORing together all the PVS visible from a leaf +================ +*/ +void CalcPAS (void) +{ + int i, j, k, l, index; + int bitbyte; + long *dest, *src; + byte *scan; + int count; + byte uncompressed[MAX_MAP_LEAFS/8]; + byte compressed[MAX_MAP_LEAFS/8]; + + Msg ("Building PAS...\n"); + + count = 0; + for (i=0 ; i= portalclusters) + Error ("Bad bit in PVS"); // pad bits should be 0 + src = (long *)(uncompressedvis + index*leafbytes); + dest = (long *)uncompressed; + for (l=0 ; l vismap_end) + Error ("Vismap expansion overflow"); + + dvis->bitofs[i][DVIS_PAS] = (byte *)dest-vismap; + + memcpy (dest, compressed, j); + } + + Msg ("Average clusters audible: %i\n", count/portalclusters); +} + + + +static void GetBoundsForFace( int faceID, Vector &faceMin, Vector &faceMax ) +{ + ClearBounds( faceMin, faceMax ); + dface_t *pFace = &dfaces[faceID]; + int i; + for( i = pFace->firstedge; i < pFace->firstedge + pFace->numedges; i++ ) + { + int edgeID = dsurfedges[i]; + if( edgeID < 0 ) + { + edgeID = -edgeID; + } + dedge_t *pEdge = &dedges[edgeID]; + dvertex_t *pVert0 = &dvertexes[pEdge->v[0]]; + dvertex_t *pVert1 = &dvertexes[pEdge->v[1]]; + AddPointToBounds( pVert0->point, faceMin, faceMax ); + AddPointToBounds( pVert1->point, faceMin, faceMax ); + } +} + +// FIXME: should stick this in mathlib +static float GetMinDistanceBetweenBoundingBoxes( const Vector &min1, const Vector &max1, + const Vector &min2, const Vector &max2 ) +{ + if( IsBoxIntersectingBox( min1, max1, min2, max2 ) ) + { + return 0.0f; + } + + Vector axisDist; + int i; + for( i = 0; i < 3; i++ ) + { + if( min1[i] <= max2[i] && max1[i] >= min2[i] ) + { + // the intersection in this dimension. + axisDist[i] = 0.0f; + } + else + { + float dist1, dist2; + dist1 = min1[i] - max2[i]; + dist2 = min2[i] - max1[i]; + axisDist[i] = dist1 > dist2 ? dist1 : dist2; + Assert( axisDist[i] > 0.0f ); + } + } + + float mag = axisDist.Length(); + Assert( mag > 0.0f ); + return mag; +} + +static float CalcDistanceFromLeafToWater( int leafNum ) +{ + byte uncompressed[MAX_MAP_LEAFS/8]; + + int j, k; + + // If we know that this one doesn't see a water surface then don't bother doing anything. + if( ((dleafs[leafNum].contents & CONTENTS_TESTFOGVOLUME) == 0) && ( dleafs[leafNum].leafWaterDataID == -1 ) ) + return 65535; // FIXME: make a define for this. + + // First get the vis data.. + int cluster = dleafs[leafNum].cluster; + if (cluster < 0) + return 65535; // FIXME: make a define for this. + + DecompressVis( &dvisdata[dvis->bitofs[cluster][DVIS_PVS]], uncompressed ); + + float minDist = 65535.0f; // FIXME: make a define for this. + + Vector leafMin, leafMax; + + leafMin[0] = ( float )dleafs[leafNum].mins[0]; + leafMin[1] = ( float )dleafs[leafNum].mins[1]; + leafMin[2] = ( float )dleafs[leafNum].mins[2]; + leafMax[0] = ( float )dleafs[leafNum].maxs[0]; + leafMax[1] = ( float )dleafs[leafNum].maxs[1]; + leafMax[2] = ( float )dleafs[leafNum].maxs[2]; + +/* + CUtlVector temp; + + // build a convex solid out of the planes so that we can get at the triangles. + for( j = dleafs[i].firstleafbrush; j < dleafs[i].firstleafbrush + dleafs[i].numleafbrushes; j++ ) + { + dbrush_t *pBrush = &dbrushes[j]; + for( k = pBrush->firstside; k < pBrush->firstside + pBrush->numsides; k++ ) + { + dbrushside_t *pside = dbrushsides + k; + dplane_t *pplane = dplanes + pside->planenum; + AddListPlane( &temp, pplane->normal[0], pplane->normal[1], pplane->normal[2], pplane->dist ); + } + CPhysConvex *pConvex = physcollision->ConvexFromPlanes( (float *)temp.Base(), temp.Count(), VPHYSICS_MERGE ); + ConvertConvexToCollide( &pConvex, + temp.RemoveAll(); + } +*/ + + // Iterate over all potentially visible clusters from this leaf + for (j = 0; j < dvis->numclusters; ++j) + { + // Don't need to bother if this is the same as the current cluster + if (j == cluster) + continue; + + // If the cluster isn't in our current pvs, then get out of here. + if ( !CheckBit( uncompressed, j ) ) + continue; + + // Found a visible cluster, now iterate over all leaves + // inside that cluster + for (k = 0; k < g_ClusterLeaves[j].leafCount; ++k) + { + int nClusterLeaf = g_ClusterLeaves[j].leafs[k]; + + // Don't bother testing the ones that don't see a water boundary. + if( ((dleafs[nClusterLeaf].contents & CONTENTS_TESTFOGVOLUME) == 0) && ( dleafs[nClusterLeaf].leafWaterDataID == -1 ) ) + continue; + + // Find the minimum distance between each surface on the boundary of the leaf + // that we have the pvs for and each water surface in the leaf that we are testing. + int nFirstFaceID = dleafs[nClusterLeaf].firstleafface; + for( int leafFaceID = 0; leafFaceID < dleafs[nClusterLeaf].numleaffaces; ++leafFaceID ) + { + int faceID = dleaffaces[nFirstFaceID + leafFaceID]; + dface_t *pFace = &dfaces[faceID]; + if( pFace->texinfo == -1 ) + continue; + + texinfo_t *pTexInfo = &texinfo[pFace->texinfo]; + if( pTexInfo->flags & SURF_WARP ) + { + // Woo hoo!!! We found a water face. + // compare the bounding box of the face with the bounding + // box of the leaf that we are looking from and see + // what the closest distance is. + // FIXME: this could be a face/face distance between the water + // face and the bounding volume of the leaf. + + // Get the bounding box of the face + Vector faceMin, faceMax; + GetBoundsForFace( faceID, faceMin, faceMax ); + float dist = GetMinDistanceBetweenBoundingBoxes( leafMin, leafMax, faceMin, faceMax ); + if( dist < minDist ) + { + minDist = dist; + } + } + } + } + } + return minDist; +} + +static void CalcDistanceFromLeavesToWater( void ) +{ + int i; + for( i = 0; i < numleafs; i++ ) + { + g_LeafMinDistToWater[i] = ( unsigned short )CalcDistanceFromLeafToWater( i ); + } +} + +//----------------------------------------------------------------------------- +// Using the PVS, compute the visible fog volumes from each leaf +//----------------------------------------------------------------------------- +static void CalcVisibleFogVolumes() +{ + byte uncompressed[MAX_MAP_LEAFS/8]; + + int i, j, k; + + // Clear the contents flags for water testing + for (i = 0; i < numleafs; ++i) + { + dleafs[i].contents &= ~CONTENTS_TESTFOGVOLUME; + g_LeafMinDistToWater[i] = 65535; + } + + for (i = 0; i < numleafs; ++i) + { + // If we've already discovered that this leaf needs testing, + // no need to go through the work again... + if (dleafs[i].contents & CONTENTS_TESTFOGVOLUME) + { + Assert((dleafs[i].contents & (CONTENTS_SLIME | CONTENTS_WATER)) == 0); + continue; + } + + // Don't bother checking fog volumes from solid leaves + if (dleafs[i].contents & CONTENTS_SOLID) + continue; + + // Look only for leaves which are visible from leaves that have fluid in them. + if ( dleafs[i].leafWaterDataID == -1 ) + continue; + + // Don't bother about looking from CONTENTS_SLIME; we're not going to treat that as interesting. + // because slime is opaque + if ( dleafs[i].contents & CONTENTS_SLIME ) + continue; + + // First get the vis data.. + int cluster = dleafs[i].cluster; + if (cluster < 0) + continue; + + DecompressVis( &dvisdata[dvis->bitofs[cluster][DVIS_PVS]], uncompressed ); + + // Iterate over all potentially visible clusters from this leaf + for (j = 0; j < dvis->numclusters; ++j) + { + // Don't need to bother if this is the same as the current cluster + if (j == cluster) + continue; + + if ( !CheckBit( uncompressed, j ) ) + continue; + + // Found a visible cluster, now iterate over all leaves + // inside that cluster + for (k = 0; k < g_ClusterLeaves[j].leafCount; ++k) + { + int nClusterLeaf = g_ClusterLeaves[j].leafs[k]; + + // Don't bother checking fog volumes from solid leaves + if ( dleafs[nClusterLeaf].contents & CONTENTS_SOLID ) + continue; + + // Don't bother checking from any leaf that's got fluid in it + if ( dleafs[nClusterLeaf].leafWaterDataID != -1 ) + continue; + + // Here, we've found a case where a non-liquid leaf is visible from a liquid leaf + // So, in this case, we have to do the expensive test during rendering. + dleafs[nClusterLeaf].contents |= CONTENTS_TESTFOGVOLUME; + } + } + } +} + + +//----------------------------------------------------------------------------- +// Compute the bounding box, excluding 3D skybox + skybox, add it to keyvalues +//----------------------------------------------------------------------------- +float DetermineVisRadius( ) +{ + float flRadius = -1; + + // Check the max vis range to determine the vis radius + for (int i = 0; i < num_entities; ++i) + { + char* pEntity = ValueForKey(&entities[i], "classname"); + if (!stricmp(pEntity, "env_fog_controller")) + { + flRadius = FloatForKey (&entities[i], "farz"); + if (flRadius == 0.0f) + flRadius = -1.0f; + break; + } + } + + return flRadius; +} + +void MarkLeavesAsRadial() +{ + for ( int i = 0; i < numleafs; i++ ) + { + dleafs[i].flags |= LEAF_FLAGS_RADIAL; + } +} + + +int ParseCommandLine( int argc, char **argv ) +{ + int i; + for (i=1 ; i : Override the VPROJECT environment variable.\n" + " -game : Same as -vproject.\n" + "\n" + "Other options:\n" + " -novconfig : Don't bring up graphical UI on vproject errors.\n" + " -radius_override: Force a vis radius, regardless of whether an\n" + " -mpi_pw : Use a password to choose a specific set of VMPI workers.\n" + " -threads : Control the number of threads vbsp uses (defaults to the #\n" + " or processors on your machine).\n" + " -nosort : Don't sort portals (sorting is an optimization).\n" + " -tmpin : Make portals come from \\tmp\\.\n" + " -tmpout : Make portals come from \\tmp\\.\n" + " -trace : Writes a linefile that traces the vis from one cluster to another for debugging map vis.\n" + " -FullMinidumps : Write large minidumps on crash.\n" + " -x360 : Generate Xbox360 version of vsp\n" + " -nox360 : Disable generation Xbox360 version of vsp (default)\n" + "\n" +#if 1 // Disabled for the initial SDK release with VMPI so we can get feedback from selected users. + ); +#else + " -mpi_ListParams : Show a list of VMPI parameters.\n" + "\n" + ); + + // Show VMPI parameters? + for ( int i=1; i < argc; i++ ) + { + if ( V_stricmp( argv[i], "-mpi_ListParams" ) == 0 ) + { + Warning( "VMPI-specific options:\n\n" ); + + bool bIsSDKMode = VMPI_IsSDKMode(); + for ( int i=k_eVMPICmdLineParam_FirstParam+1; i < k_eVMPICmdLineParam_LastParam; i++ ) + { + if ( (VMPI_GetParamFlags( (EVMPICmdLineParam)i ) & VMPI_PARAM_SDK_HIDDEN) && bIsSDKMode ) + continue; + + Warning( "[%s]\n", VMPI_GetParamString( (EVMPICmdLineParam)i ) ); + Warning( VMPI_GetParamHelpString( (EVMPICmdLineParam)i ) ); + Warning( "\n\n" ); + } + break; + } + } +#endif +} + + +int RunVVis( int argc, char **argv ) +{ + char portalfile[1024]; + char source[1024]; + double start, end; + + + Msg( "Valve Software - vvis.exe (%s)\n", __DATE__ ); + + verbose = false; + + Q_StripExtension( argv[ argc - 1 ], source, sizeof( source ) ); + CmdLib_InitFileSystem( argv[ argc - 1 ] ); + + Q_FileBase( source, source, sizeof( source ) ); + + LoadCmdLineFromFile( argc, argv, source, "vvis" ); + int i = ParseCommandLine( argc, argv ); + + // This part is just for VMPI. VMPI's file system needs the basedir in front of all filenames, + // so we prepend qdir here. + strcpy( source, ExpandPath( source ) ); + + if (i != argc - 1) + { + PrintUsage( argc, argv ); + DeleteCmdLine( argc, argv ); + CmdLib_Exit( 1 ); + } + + start = Plat_FloatTime(); + + + if (!g_bUseMPI) + { + // Setup the logfile. + char logFile[512]; + _snprintf( logFile, sizeof(logFile), "%s.log", source ); + SetSpewFunctionLogFile( logFile ); + } + + // Run in the background? + if( g_bLowPriority ) + { + SetLowPriority(); + } + + ThreadSetDefault (); + + char targetPath[1024]; + GetPlatformMapPath( source, targetPath, 0, 1024 ); + Msg ("reading %s\n", targetPath); + LoadBSPFile (targetPath); + if (numnodes == 0 || numfaces == 0) + Error ("Empty map"); + ParseEntities (); + + // Check the VMF for a vis radius + if (!g_bUseRadius) + { + float flRadius = DetermineVisRadius( ); + if (flRadius > 0.0f) + { + g_bUseRadius = true; + g_VisRadius = flRadius * flRadius; + } + } + + if ( g_bUseRadius ) + { + MarkLeavesAsRadial(); + } + + if ( inbase[0] == 0 ) + { + strcpy( portalfile, source ); + } + else + { + sprintf ( portalfile, "%s%s", inbase, argv[i] ); + Q_StripExtension( portalfile, portalfile, sizeof( portalfile ) ); + } + strcat (portalfile, ".prt"); + + Msg ("reading %s\n", portalfile); + LoadPortals (portalfile); + + // don't write out results when simply doing a trace + if ( g_TraceClusterStart < 0 ) + { + CalcVis (); + CalcPAS (); + + // We need a mapping from cluster to leaves, since the PVS + // deals with clusters for both CalcVisibleFogVolumes and + BuildClusterTable(); + + CalcVisibleFogVolumes(); + CalcDistanceFromLeavesToWater(); + + visdatasize = vismap_p - dvisdata; + Msg ("visdatasize:%i compressed from %i\n", visdatasize, originalvismapsize*2); + + Msg ("writing %s\n", targetPath); + WriteBSPFile (targetPath); + } + else + { + if ( g_TraceClusterStart < 0 || g_TraceClusterStart >= portalclusters || g_TraceClusterStop < 0 || g_TraceClusterStop >= portalclusters ) + { + Error("Invalid cluster trace: %d to %d, valid range is 0 to %d\n", g_TraceClusterStart, g_TraceClusterStop, portalclusters-1 ); + } + if ( g_bUseMPI ) + { + Warning("Can't compile trace in MPI mode\n"); + } + CalcVisTrace (); + WritePortalTrace(source); + } + + end = Plat_FloatTime(); + + char str[512]; + GetHourMinuteSecondsString( (int)( end - start ), str, sizeof( str ) ); + Msg( "%s elapsed\n", str ); + + ReleasePakFileLumps(); + DeleteCmdLine( argc, argv ); + CmdLib_Cleanup(); + return 0; +} + + +/* +=========== +main +=========== +*/ +int main (int argc, char **argv) +{ + CommandLine()->CreateCmdLine( argc, argv ); + + MathLib_Init( 2.2f, 2.2f, 0.0f, 1.0f, false, false, false, false ); + InstallAllocationFunctions(); + InstallSpewFunction(); + + VVIS_SetupMPI( argc, argv ); + + // Install an exception handler. + if ( g_bUseMPI && !g_bMPIMaster ) + SetupToolsMinidumpHandler( VMPI_ExceptionFilter ); + else + SetupDefaultToolsMinidumpHandler(); + + return RunVVis( argc, argv ); +} + + +// When VVIS is used as a DLL (makes debugging vmpi vvis a lot easier), this is used to +// get it going. +class CVVisDLL : public ILaunchableDLL +{ +public: + virtual int main( int argc, char **argv ) + { + return ::main( argc, argv ); + } +}; + +EXPOSE_SINGLE_INTERFACE( CVVisDLL, ILaunchableDLL, LAUNCHABLE_DLL_INTERFACE_VERSION ); -- cgit v1.2.3