diff options
| author | Narendra Umate <[email protected]> | 2013-12-02 23:36:05 -0800 |
|---|---|---|
| committer | Narendra Umate <[email protected]> | 2013-12-02 23:36:05 -0800 |
| commit | 8737f191f3b59f001a77bf6c08091109211c1c9f (patch) | |
| tree | dbbf05c004d9b026f2c1f23f06600fe0add82c36 /mp/src/utils/vvis | |
| parent | Update .gitignore. (diff) | |
| parent | Make .xcconfigs text files too. (diff) | |
| download | source-sdk-2013-8737f191f3b59f001a77bf6c08091109211c1c9f.tar.xz source-sdk-2013-8737f191f3b59f001a77bf6c08091109211c1c9f.zip | |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'mp/src/utils/vvis')
| -rw-r--r-- | mp/src/utils/vvis/WaterDist.cpp | 60 | ||||
| -rw-r--r-- | mp/src/utils/vvis/flow.cpp | 1762 | ||||
| -rw-r--r-- | mp/src/utils/vvis/mpivis.cpp | 1280 | ||||
| -rw-r--r-- | mp/src/utils/vvis/mpivis.h | 42 | ||||
| -rw-r--r-- | mp/src/utils/vvis/vis.h | 250 | ||||
| -rw-r--r-- | mp/src/utils/vvis/vvis.cpp | 2480 | ||||
| -rw-r--r-- | mp/src/utils/vvis/vvis_dll.vpc | 202 |
7 files changed, 3038 insertions, 3038 deletions
diff --git a/mp/src/utils/vvis/WaterDist.cpp b/mp/src/utils/vvis/WaterDist.cpp index 5ed380c8..933e178f 100644 --- a/mp/src/utils/vvis/WaterDist.cpp +++ b/mp/src/utils/vvis/WaterDist.cpp @@ -1,30 +1,30 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//=============================================================================//
-
-#include "bsplib.h"
-
-// input:
-// from bsplib.h:
-// numleafs
-// dleafs
-
-void EmitDistanceToWaterInfo( void )
-{
- int leafID;
- for( leafID = 0; leafID < numleafs; leafID++ )
- {
- dleaf_t *pLeaf = &dleafs[leafID];
- if( pLeaf->leafWaterDataID == -1 )
- {
- // FIXME: set the distance to water to infinity here just in case.
- continue;
- }
-
- // Get the vis set for this leaf.
-
- }
-}
-
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "bsplib.h" + +// input: +// from bsplib.h: +// numleafs +// dleafs + +void EmitDistanceToWaterInfo( void ) +{ + int leafID; + for( leafID = 0; leafID < numleafs; leafID++ ) + { + dleaf_t *pLeaf = &dleafs[leafID]; + if( pLeaf->leafWaterDataID == -1 ) + { + // FIXME: set the distance to water to infinity here just in case. + continue; + } + + // Get the vis set for this leaf. + + } +} + diff --git a/mp/src/utils/vvis/flow.cpp b/mp/src/utils/vvis/flow.cpp index 7234e68a..716fc1ae 100644 --- a/mp/src/utils/vvis/flow.cpp +++ b/mp/src/utils/vvis/flow.cpp @@ -1,881 +1,881 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-#include "vis.h"
-#include "vmpi.h"
-
-int g_TraceClusterStart = -1;
-int g_TraceClusterStop = -1;
-/*
-
- each portal will have a list of all possible to see from first portal
-
- if (!thread->portalmightsee[portalnum])
-
- portal mightsee
-
- for p2 = all other portals in leaf
- get sperating planes
- for all portals that might be seen by p2
- mark as unseen if not present in seperating plane
- flood fill a new mightsee
- save as passagemightsee
-
-
- void CalcMightSee (leaf_t *leaf,
-*/
-
-int CountBits (byte *bits, int numbits)
-{
- int i;
- int c;
-
- c = 0;
- for (i=0 ; i<numbits ; i++)
- if ( CheckBit( bits, i ) )
- c++;
-
- return c;
-}
-
-int c_fullskip;
-int c_portalskip, c_leafskip;
-int c_vistest, c_mighttest;
-
-int c_chop, c_nochop;
-
-int active;
-
-extern bool g_bVMPIEarlyExit;
-
-
-void CheckStack (leaf_t *leaf, threaddata_t *thread)
-{
- pstack_t *p, *p2;
-
- for (p=thread->pstack_head.next ; p ; p=p->next)
- {
-// Msg ("=");
- if (p->leaf == leaf)
- Error ("CheckStack: leaf recursion");
- for (p2=thread->pstack_head.next ; p2 != p ; p2=p2->next)
- if (p2->leaf == p->leaf)
- Error ("CheckStack: late leaf recursion");
- }
-// Msg ("\n");
-}
-
-
-winding_t *AllocStackWinding (pstack_t *stack)
-{
- int i;
-
- for (i=0 ; i<3 ; i++)
- {
- if (stack->freewindings[i])
- {
- stack->freewindings[i] = 0;
- return &stack->windings[i];
- }
- }
-
- Error ("Out of memory. AllocStackWinding: failed");
-
- return NULL;
-}
-
-void FreeStackWinding (winding_t *w, pstack_t *stack)
-{
- int i;
-
- i = w - stack->windings;
-
- if (i<0 || i>2)
- return; // not from local
-
- if (stack->freewindings[i])
- Error ("FreeStackWinding: allready free");
- stack->freewindings[i] = 1;
-}
-
-/*
-==============
-ChopWinding
-
-==============
-*/
-
-#ifdef _WIN32
-#pragma warning (disable:4701)
-#endif
-
-winding_t *ChopWinding (winding_t *in, pstack_t *stack, plane_t *split)
-{
- vec_t dists[128];
- int sides[128];
- int counts[3];
- vec_t dot;
- int i, j;
- Vector mid;
- winding_t *neww;
-
- counts[0] = counts[1] = counts[2] = 0;
-
-// determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->points[i], split->normal);
- dot -= split->dist;
- dists[i] = dot;
- if (dot > ON_VIS_EPSILON)
- sides[i] = SIDE_FRONT;
- else if (dot < -ON_VIS_EPSILON)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
-
- if (!counts[1])
- return in; // completely on front side
-
- if (!counts[0])
- {
- FreeStackWinding (in, stack);
- return NULL;
- }
-
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- neww = AllocStackWinding (stack);
-
- neww->numpoints = 0;
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- Vector& p1 = in->points[i];
-
- if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
- {
- FreeStackWinding (neww, stack);
- return in; // can't chop -- fall back to original
- }
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
- {
- FreeStackWinding (neww, stack);
- return in; // can't chop -- fall back to original
- }
-
- // generate a split point
- Vector& p2 = in->points[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
-
-// free the original winding
- FreeStackWinding (in, stack);
-
- return neww;
-}
-
-#ifdef _WIN32
-#pragma warning (default:4701)
-#endif
-
-/*
-==============
-ClipToSeperators
-
-Source, pass, and target are an ordering of portals.
-
-Generates seperating planes canidates by taking two points from source and one
-point from pass, and clips target by them.
-
-If target is totally clipped away, that portal can not be seen through.
-
-Normal clip keeps target on the same side as pass, which is correct if the
-order goes source, pass, target. If the order goes pass, source, target then
-flipclip should be set.
-==============
-*/
-winding_t *ClipToSeperators (winding_t *source, winding_t *pass, winding_t *target, bool flipclip, pstack_t *stack)
-{
- int i, j, k, l;
- plane_t plane;
- Vector v1, v2;
- float d;
- vec_t length;
- int counts[3];
- bool fliptest;
-
-// check all combinations
- for (i=0 ; i<source->numpoints ; i++)
- {
- l = (i+1)%source->numpoints;
- VectorSubtract (source->points[l] , source->points[i], v1);
-
- // fing a vertex of pass that makes a plane that puts all of the
- // vertexes of pass on the front side and all of the vertexes of
- // source on the back side
- for (j=0 ; j<pass->numpoints ; j++)
- {
- VectorSubtract (pass->points[j], source->points[i], v2);
-
- plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
- plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
- plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
-
- // if points don't make a valid plane, skip it
-
- length = plane.normal[0] * plane.normal[0]
- + plane.normal[1] * plane.normal[1]
- + plane.normal[2] * plane.normal[2];
-
- if (length < ON_VIS_EPSILON)
- continue;
-
- length = 1/sqrt(length);
-
- plane.normal[0] *= length;
- plane.normal[1] *= length;
- plane.normal[2] *= length;
-
- plane.dist = DotProduct (pass->points[j], plane.normal);
-
- //
- // find out which side of the generated seperating plane has the
- // source portal
- //
-#if 1
- fliptest = false;
- for (k=0 ; k<source->numpoints ; k++)
- {
- if (k == i || k == l)
- continue;
- d = DotProduct (source->points[k], plane.normal) - plane.dist;
- if (d < -ON_VIS_EPSILON)
- { // source is on the negative side, so we want all
- // pass and target on the positive side
- fliptest = false;
- break;
- }
- else if (d > ON_VIS_EPSILON)
- { // source is on the positive side, so we want all
- // pass and target on the negative side
- fliptest = true;
- break;
- }
- }
- if (k == source->numpoints)
- continue; // planar with source portal
-#else
- fliptest = flipclip;
-#endif
- //
- // flip the normal if the source portal is backwards
- //
- if (fliptest)
- {
- VectorSubtract (vec3_origin, plane.normal, plane.normal);
- plane.dist = -plane.dist;
- }
-#if 1
- //
- // if all of the pass portal points are now on the positive side,
- // this is the seperating plane
- //
- counts[0] = counts[1] = counts[2] = 0;
- for (k=0 ; k<pass->numpoints ; k++)
- {
- if (k==j)
- continue;
- d = DotProduct (pass->points[k], plane.normal) - plane.dist;
- if (d < -ON_VIS_EPSILON)
- break;
- else if (d > ON_VIS_EPSILON)
- counts[0]++;
- else
- counts[2]++;
- }
- if (k != pass->numpoints)
- continue; // points on negative side, not a seperating plane
-
- if (!counts[0])
- continue; // planar with seperating plane
-#else
- k = (j+1)%pass->numpoints;
- d = DotProduct (pass->points[k], plane.normal) - plane.dist;
- if (d < -ON_VIS_EPSILON)
- continue;
- k = (j+pass->numpoints-1)%pass->numpoints;
- d = DotProduct (pass->points[k], plane.normal) - plane.dist;
- if (d < -ON_VIS_EPSILON)
- continue;
-#endif
- //
- // flip the normal if we want the back side
- //
- if (flipclip)
- {
- VectorSubtract (vec3_origin, plane.normal, plane.normal);
- plane.dist = -plane.dist;
- }
-
- //
- // clip target by the seperating plane
- //
- target = ChopWinding (target, stack, &plane);
- if (!target)
- return NULL; // target is not visible
-
- // JAY: End the loop, no need to find additional separators on this edge ?
-// j = pass->numpoints;
- }
- }
-
- return target;
-}
-
-
-class CPortalTrace
-{
-public:
- CUtlVector<Vector> m_list;
- CThreadFastMutex m_mutex;
-} g_PortalTrace;
-
-void WindingCenter (winding_t *w, Vector ¢er)
-{
- int i;
- float scale;
-
- VectorCopy (vec3_origin, center);
- for (i=0 ; i<w->numpoints ; i++)
- VectorAdd (w->points[i], center, center);
-
- scale = 1.0/w->numpoints;
- VectorScale (center, scale, center);
-}
-
-Vector ClusterCenter( int cluster )
-{
- Vector mins, maxs;
- ClearBounds(mins, maxs);
- int count = leafs[cluster].portals.Count();
- for ( int i = 0; i < count; i++ )
- {
- winding_t *w = leafs[cluster].portals[i]->winding;
- for ( int j = 0; j < w->numpoints; j++ )
- {
- AddPointToBounds( w->points[j], mins, maxs );
- }
- }
- return (mins + maxs) * 0.5f;
-}
-
-
-void DumpPortalTrace( pstack_t *pStack )
-{
- AUTO_LOCK_FM(g_PortalTrace.m_mutex);
- if ( g_PortalTrace.m_list.Count() )
- return;
-
- Warning("Dumped cluster trace!!!\n");
- Vector mid;
- mid = ClusterCenter( g_TraceClusterStart );
- g_PortalTrace.m_list.AddToTail(mid);
- for ( ; pStack != NULL; pStack = pStack->next )
- {
- winding_t *w = pStack->pass ? pStack->pass : pStack->portal->winding;
- WindingCenter (w, mid);
- g_PortalTrace.m_list.AddToTail(mid);
- for ( int i = 0; i < w->numpoints; i++ )
- {
- g_PortalTrace.m_list.AddToTail(w->points[i]);
- g_PortalTrace.m_list.AddToTail(mid);
- }
- for ( int i = 0; i < w->numpoints; i++ )
- {
- g_PortalTrace.m_list.AddToTail(w->points[i]);
- }
- g_PortalTrace.m_list.AddToTail(w->points[0]);
- g_PortalTrace.m_list.AddToTail(mid);
- }
- mid = ClusterCenter( g_TraceClusterStop );
- g_PortalTrace.m_list.AddToTail(mid);
-}
-
-void WritePortalTrace( const char *source )
-{
- Vector mid;
- FILE *linefile;
- char filename[1024];
-
- if ( !g_PortalTrace.m_list.Count() )
- {
- Warning("No trace generated from %d to %d\n", g_TraceClusterStart, g_TraceClusterStop );
- return;
- }
-
- sprintf (filename, "%s.lin", source);
- linefile = fopen (filename, "w");
- if (!linefile)
- Error ("Couldn't open %s\n", filename);
-
- for ( int i = 0; i < g_PortalTrace.m_list.Count(); i++ )
- {
- Vector p = g_PortalTrace.m_list[i];
- fprintf (linefile, "%f %f %f\n", p[0], p[1], p[2]);
- }
- fclose (linefile);
- Warning("Wrote %s!!!\n", filename);
-}
-
-/*
-==================
-RecursiveLeafFlow
-
-Flood fill through the leafs
-If src_portal is NULL, this is the originating leaf
-==================
-*/
-void RecursiveLeafFlow (int leafnum, threaddata_t *thread, pstack_t *prevstack)
-{
- pstack_t stack;
- portal_t *p;
- plane_t backplane;
- leaf_t *leaf;
- int i, j;
- long *test, *might, *vis, more;
- int pnum;
-
- // Early-out if we're a VMPI worker that's told to exit. If we don't do this here, then the
- // worker might spin its wheels for a while on an expensive work unit and not be available to the pool.
- // This is pretty common in vis.
- if ( g_bVMPIEarlyExit )
- return;
-
- if ( leafnum == g_TraceClusterStop )
- {
- DumpPortalTrace(&thread->pstack_head);
- return;
- }
- thread->c_chains++;
-
- leaf = &leafs[leafnum];
-
- prevstack->next = &stack;
-
- stack.next = NULL;
- stack.leaf = leaf;
- stack.portal = NULL;
-
- might = (long *)stack.mightsee;
- vis = (long *)thread->base->portalvis;
-
- // check all portals for flowing into other leafs
- for (i=0 ; i<leaf->portals.Count() ; i++)
- {
-
- p = leaf->portals[i];
- pnum = p - portals;
-
- if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) )
- {
- continue; // can't possibly see it
- }
-
- // if the portal can't see anything we haven't allready seen, skip it
- if (p->status == stat_done)
- {
- test = (long *)p->portalvis;
- }
- else
- {
- test = (long *)p->portalflood;
- }
-
- more = 0;
- for (j=0 ; j<portallongs ; j++)
- {
- might[j] = ((long *)prevstack->mightsee)[j] & test[j];
- more |= (might[j] & ~vis[j]);
- }
-
- if ( !more && CheckBit( thread->base->portalvis, pnum ) )
- { // can't see anything new
- continue;
- }
-
- // get plane of portal, point normal into the neighbor leaf
- stack.portalplane = p->plane;
- VectorSubtract (vec3_origin, p->plane.normal, backplane.normal);
- backplane.dist = -p->plane.dist;
-
- stack.portal = p;
- stack.next = NULL;
- stack.freewindings[0] = 1;
- stack.freewindings[1] = 1;
- stack.freewindings[2] = 1;
-
- float d = DotProduct (p->origin, thread->pstack_head.portalplane.normal);
- d -= thread->pstack_head.portalplane.dist;
- if (d < -p->radius)
- {
- continue;
- }
- else if (d > p->radius)
- {
- stack.pass = p->winding;
- }
- else
- {
- stack.pass = ChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
- if (!stack.pass)
- continue;
- }
-
-
- d = DotProduct (thread->base->origin, p->plane.normal);
- d -= p->plane.dist;
- if (d > thread->base->radius)
- {
- continue;
- }
- else if (d < -thread->base->radius)
- {
- stack.source = prevstack->source;
- }
- else
- {
- stack.source = ChopWinding (prevstack->source, &stack, &backplane);
- if (!stack.source)
- continue;
- }
-
-
- if (!prevstack->pass)
- { // the second leaf can only be blocked if coplanar
-
- // mark the portal as visible
- SetBit( thread->base->portalvis, pnum );
-
- RecursiveLeafFlow (p->leaf, thread, &stack);
- continue;
- }
-
- stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, false, &stack);
- if (!stack.pass)
- continue;
-
- stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, true, &stack);
- if (!stack.pass)
- continue;
-
- // mark the portal as visible
- SetBit( thread->base->portalvis, pnum );
-
- // flow through it for real
- RecursiveLeafFlow (p->leaf, thread, &stack);
- }
-}
-
-
-/*
-===============
-PortalFlow
-
-generates the portalvis bit vector
-===============
-*/
-void PortalFlow (int iThread, int portalnum)
-{
- threaddata_t data;
- int i;
- portal_t *p;
- int c_might, c_can;
-
- p = sorted_portals[portalnum];
- p->status = stat_working;
-
- c_might = CountBits (p->portalflood, g_numportals*2);
-
- memset (&data, 0, sizeof(data));
- data.base = p;
-
- data.pstack_head.portal = p;
- data.pstack_head.source = p->winding;
- data.pstack_head.portalplane = p->plane;
- for (i=0 ; i<portallongs ; i++)
- ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i];
-
- RecursiveLeafFlow (p->leaf, &data, &data.pstack_head);
-
-
- p->status = stat_done;
-
- c_can = CountBits (p->portalvis, g_numportals*2);
-
- qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n",
- (int)(p - portals), c_might, c_can, data.c_chains);
-}
-
-
-/*
-===============================================================================
-
-This is a rough first-order aproximation that is used to trivially reject some
-of the final calculations.
-
-
-Calculates portalfront and portalflood bit vectors
-
-===============================================================================
-*/
-
-int c_flood, c_vis;
-
-/*
-==================
-SimpleFlood
-
-==================
-*/
-void SimpleFlood (portal_t *srcportal, int leafnum)
-{
- int i;
- leaf_t *leaf;
- portal_t *p;
- int pnum;
-
- leaf = &leafs[leafnum];
-
- for (i=0 ; i<leaf->portals.Count(); i++)
- {
- p = leaf->portals[i];
- pnum = p - portals;
- if ( !CheckBit( srcportal->portalfront, pnum ) )
- continue;
-
- if ( CheckBit( srcportal->portalflood, pnum ) )
- continue;
-
- SetBit( srcportal->portalflood, pnum );
-
- SimpleFlood (srcportal, p->leaf);
- }
-}
-
-/*
-==============
-BasePortalVis
-==============
-*/
-void BasePortalVis (int iThread, int portalnum)
-{
- int j, k;
- portal_t *tp, *p;
- float d;
- winding_t *w;
- Vector segment;
- double dist2, minDist2;
-
- // get the portal
- p = portals+portalnum;
-
- //
- // allocate memory for bitwise vis solutions for this portal
- //
- p->portalfront = (byte*)malloc (portalbytes);
- memset (p->portalfront, 0, portalbytes);
-
- p->portalflood = (byte*)malloc (portalbytes);
- memset (p->portalflood, 0, portalbytes);
-
- p->portalvis = (byte*)malloc (portalbytes);
- memset (p->portalvis, 0, portalbytes);
-
- //
- // test the given portal against all of the portals in the map
- //
- for (j=0, tp = portals ; j<g_numportals*2 ; j++, tp++)
- {
- // don't test against itself
- if (j == portalnum)
- continue;
-
- //
- //
- //
- w = tp->winding;
- for (k=0 ; k<w->numpoints ; k++)
- {
- d = DotProduct (w->points[k], p->plane.normal) - p->plane.dist;
- if (d > ON_VIS_EPSILON)
- break;
- }
- if (k == w->numpoints)
- continue; // no points on front
-
- //
- //
- //
- w = p->winding;
- for (k=0 ; k<w->numpoints ; k++)
- {
- d = DotProduct (w->points[k], tp->plane.normal) - tp->plane.dist;
- if (d < -ON_VIS_EPSILON)
- break;
- }
- if (k == w->numpoints)
- continue; // no points on front
-
- //
- // if using radius visibility -- check to see if any portal points lie inside of the
- // radius given
- //
- if( g_bUseRadius )
- {
- w = tp->winding;
- minDist2 = 1024000000.0; // 32000^2
- for( k = 0; k < w->numpoints; k++ )
- {
- VectorSubtract( w->points[k], p->origin, segment );
- dist2 = ( segment[0] * segment[0] ) + ( segment[1] * segment[1] ) + ( segment[2] * segment[2] );
- if( dist2 < minDist2 )
- {
- minDist2 = dist2;
- }
- }
-
- if( minDist2 > g_VisRadius )
- continue;
- }
-
- // add current portal to given portal's list of visible portals
- SetBit( p->portalfront, j );
- }
-
- SimpleFlood (p, p->leaf);
-
- p->nummightsee = CountBits (p->portalflood, g_numportals*2);
-// Msg ("portal %i: %i mightsee\n", portalnum, p->nummightsee);
- c_flood += p->nummightsee;
-}
-
-
-
-
-
-/*
-===============================================================================
-
-This is a second order aproximation
-
-Calculates portalvis bit vector
-
-WAAAAAAY too slow.
-
-===============================================================================
-*/
-
-/*
-==================
-RecursiveLeafBitFlow
-
-==================
-*/
-void RecursiveLeafBitFlow (int leafnum, byte *mightsee, byte *cansee)
-{
- portal_t *p;
- leaf_t *leaf;
- int i, j;
- long more;
- int pnum;
- byte newmight[MAX_PORTALS/8];
-
- leaf = &leafs[leafnum];
-
-// check all portals for flowing into other leafs
- for (i=0 ; i<leaf->portals.Count(); i++)
- {
- p = leaf->portals[i];
- pnum = p - portals;
-
- // if some previous portal can't see it, skip
- if ( !CheckBit( mightsee, pnum ) )
- continue;
-
- // if this portal can see some portals we mightsee, recurse
- more = 0;
- for (j=0 ; j<portallongs ; j++)
- {
- ((long *)newmight)[j] = ((long *)mightsee)[j]
- & ((long *)p->portalflood)[j];
- more |= ((long *)newmight)[j] & ~((long *)cansee)[j];
- }
-
- if (!more)
- continue; // can't see anything new
-
- SetBit( cansee, pnum );
-
- RecursiveLeafBitFlow (p->leaf, newmight, cansee);
- }
-}
-
-/*
-==============
-BetterPortalVis
-==============
-*/
-void BetterPortalVis (int portalnum)
-{
- portal_t *p;
-
- p = portals+portalnum;
-
- RecursiveLeafBitFlow (p->leaf, p->portalflood, p->portalvis);
-
- // build leaf vis information
- p->nummightsee = CountBits (p->portalvis, g_numportals*2);
- c_vis += p->nummightsee;
-}
-
-
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#include "vis.h" +#include "vmpi.h" + +int g_TraceClusterStart = -1; +int g_TraceClusterStop = -1; +/* + + each portal will have a list of all possible to see from first portal + + if (!thread->portalmightsee[portalnum]) + + portal mightsee + + for p2 = all other portals in leaf + get sperating planes + for all portals that might be seen by p2 + mark as unseen if not present in seperating plane + flood fill a new mightsee + save as passagemightsee + + + void CalcMightSee (leaf_t *leaf, +*/ + +int CountBits (byte *bits, int numbits) +{ + int i; + int c; + + c = 0; + for (i=0 ; i<numbits ; i++) + if ( CheckBit( bits, i ) ) + c++; + + return c; +} + +int c_fullskip; +int c_portalskip, c_leafskip; +int c_vistest, c_mighttest; + +int c_chop, c_nochop; + +int active; + +extern bool g_bVMPIEarlyExit; + + +void CheckStack (leaf_t *leaf, threaddata_t *thread) +{ + pstack_t *p, *p2; + + for (p=thread->pstack_head.next ; p ; p=p->next) + { +// Msg ("="); + if (p->leaf == leaf) + Error ("CheckStack: leaf recursion"); + for (p2=thread->pstack_head.next ; p2 != p ; p2=p2->next) + if (p2->leaf == p->leaf) + Error ("CheckStack: late leaf recursion"); + } +// Msg ("\n"); +} + + +winding_t *AllocStackWinding (pstack_t *stack) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if (stack->freewindings[i]) + { + stack->freewindings[i] = 0; + return &stack->windings[i]; + } + } + + Error ("Out of memory. AllocStackWinding: failed"); + + return NULL; +} + +void FreeStackWinding (winding_t *w, pstack_t *stack) +{ + int i; + + i = w - stack->windings; + + if (i<0 || i>2) + return; // not from local + + if (stack->freewindings[i]) + Error ("FreeStackWinding: allready free"); + stack->freewindings[i] = 1; +} + +/* +============== +ChopWinding + +============== +*/ + +#ifdef _WIN32 +#pragma warning (disable:4701) +#endif + +winding_t *ChopWinding (winding_t *in, pstack_t *stack, plane_t *split) +{ + vec_t dists[128]; + int sides[128]; + int counts[3]; + vec_t dot; + int i, j; + Vector mid; + winding_t *neww; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; i<in->numpoints ; i++) + { + dot = DotProduct (in->points[i], split->normal); + dot -= split->dist; + dists[i] = dot; + if (dot > ON_VIS_EPSILON) + sides[i] = SIDE_FRONT; + else if (dot < -ON_VIS_EPSILON) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + + if (!counts[1]) + return in; // completely on front side + + if (!counts[0]) + { + FreeStackWinding (in, stack); + return NULL; + } + + sides[i] = sides[0]; + dists[i] = dists[0]; + + neww = AllocStackWinding (stack); + + neww->numpoints = 0; + + for (i=0 ; i<in->numpoints ; i++) + { + Vector& p1 = in->points[i]; + + if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING) + { + FreeStackWinding (neww, stack); + return in; // can't chop -- fall back to original + } + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING) + { + FreeStackWinding (neww, stack); + return in; // can't chop -- fall back to original + } + + // generate a split point + Vector& p2 = in->points[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (split->normal[j] == 1) + mid[j] = split->dist; + else if (split->normal[j] == -1) + mid[j] = -split->dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, neww->points[neww->numpoints]); + neww->numpoints++; + } + +// free the original winding + FreeStackWinding (in, stack); + + return neww; +} + +#ifdef _WIN32 +#pragma warning (default:4701) +#endif + +/* +============== +ClipToSeperators + +Source, pass, and target are an ordering of portals. + +Generates seperating planes canidates by taking two points from source and one +point from pass, and clips target by them. + +If target is totally clipped away, that portal can not be seen through. + +Normal clip keeps target on the same side as pass, which is correct if the +order goes source, pass, target. If the order goes pass, source, target then +flipclip should be set. +============== +*/ +winding_t *ClipToSeperators (winding_t *source, winding_t *pass, winding_t *target, bool flipclip, pstack_t *stack) +{ + int i, j, k, l; + plane_t plane; + Vector v1, v2; + float d; + vec_t length; + int counts[3]; + bool fliptest; + +// check all combinations + for (i=0 ; i<source->numpoints ; i++) + { + l = (i+1)%source->numpoints; + VectorSubtract (source->points[l] , source->points[i], v1); + + // fing a vertex of pass that makes a plane that puts all of the + // vertexes of pass on the front side and all of the vertexes of + // source on the back side + for (j=0 ; j<pass->numpoints ; j++) + { + VectorSubtract (pass->points[j], source->points[i], v2); + + plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1]; + plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2]; + plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0]; + + // if points don't make a valid plane, skip it + + length = plane.normal[0] * plane.normal[0] + + plane.normal[1] * plane.normal[1] + + plane.normal[2] * plane.normal[2]; + + if (length < ON_VIS_EPSILON) + continue; + + length = 1/sqrt(length); + + plane.normal[0] *= length; + plane.normal[1] *= length; + plane.normal[2] *= length; + + plane.dist = DotProduct (pass->points[j], plane.normal); + + // + // find out which side of the generated seperating plane has the + // source portal + // +#if 1 + fliptest = false; + for (k=0 ; k<source->numpoints ; k++) + { + if (k == i || k == l) + continue; + d = DotProduct (source->points[k], plane.normal) - plane.dist; + if (d < -ON_VIS_EPSILON) + { // source is on the negative side, so we want all + // pass and target on the positive side + fliptest = false; + break; + } + else if (d > ON_VIS_EPSILON) + { // source is on the positive side, so we want all + // pass and target on the negative side + fliptest = true; + break; + } + } + if (k == source->numpoints) + continue; // planar with source portal +#else + fliptest = flipclip; +#endif + // + // flip the normal if the source portal is backwards + // + if (fliptest) + { + VectorSubtract (vec3_origin, plane.normal, plane.normal); + plane.dist = -plane.dist; + } +#if 1 + // + // if all of the pass portal points are now on the positive side, + // this is the seperating plane + // + counts[0] = counts[1] = counts[2] = 0; + for (k=0 ; k<pass->numpoints ; k++) + { + if (k==j) + continue; + d = DotProduct (pass->points[k], plane.normal) - plane.dist; + if (d < -ON_VIS_EPSILON) + break; + else if (d > ON_VIS_EPSILON) + counts[0]++; + else + counts[2]++; + } + if (k != pass->numpoints) + continue; // points on negative side, not a seperating plane + + if (!counts[0]) + continue; // planar with seperating plane +#else + k = (j+1)%pass->numpoints; + d = DotProduct (pass->points[k], plane.normal) - plane.dist; + if (d < -ON_VIS_EPSILON) + continue; + k = (j+pass->numpoints-1)%pass->numpoints; + d = DotProduct (pass->points[k], plane.normal) - plane.dist; + if (d < -ON_VIS_EPSILON) + continue; +#endif + // + // flip the normal if we want the back side + // + if (flipclip) + { + VectorSubtract (vec3_origin, plane.normal, plane.normal); + plane.dist = -plane.dist; + } + + // + // clip target by the seperating plane + // + target = ChopWinding (target, stack, &plane); + if (!target) + return NULL; // target is not visible + + // JAY: End the loop, no need to find additional separators on this edge ? +// j = pass->numpoints; + } + } + + return target; +} + + +class CPortalTrace +{ +public: + CUtlVector<Vector> m_list; + CThreadFastMutex m_mutex; +} g_PortalTrace; + +void WindingCenter (winding_t *w, Vector ¢er) +{ + int i; + float scale; + + VectorCopy (vec3_origin, center); + for (i=0 ; i<w->numpoints ; i++) + VectorAdd (w->points[i], center, center); + + scale = 1.0/w->numpoints; + VectorScale (center, scale, center); +} + +Vector ClusterCenter( int cluster ) +{ + Vector mins, maxs; + ClearBounds(mins, maxs); + int count = leafs[cluster].portals.Count(); + for ( int i = 0; i < count; i++ ) + { + winding_t *w = leafs[cluster].portals[i]->winding; + for ( int j = 0; j < w->numpoints; j++ ) + { + AddPointToBounds( w->points[j], mins, maxs ); + } + } + return (mins + maxs) * 0.5f; +} + + +void DumpPortalTrace( pstack_t *pStack ) +{ + AUTO_LOCK_FM(g_PortalTrace.m_mutex); + if ( g_PortalTrace.m_list.Count() ) + return; + + Warning("Dumped cluster trace!!!\n"); + Vector mid; + mid = ClusterCenter( g_TraceClusterStart ); + g_PortalTrace.m_list.AddToTail(mid); + for ( ; pStack != NULL; pStack = pStack->next ) + { + winding_t *w = pStack->pass ? pStack->pass : pStack->portal->winding; + WindingCenter (w, mid); + g_PortalTrace.m_list.AddToTail(mid); + for ( int i = 0; i < w->numpoints; i++ ) + { + g_PortalTrace.m_list.AddToTail(w->points[i]); + g_PortalTrace.m_list.AddToTail(mid); + } + for ( int i = 0; i < w->numpoints; i++ ) + { + g_PortalTrace.m_list.AddToTail(w->points[i]); + } + g_PortalTrace.m_list.AddToTail(w->points[0]); + g_PortalTrace.m_list.AddToTail(mid); + } + mid = ClusterCenter( g_TraceClusterStop ); + g_PortalTrace.m_list.AddToTail(mid); +} + +void WritePortalTrace( const char *source ) +{ + Vector mid; + FILE *linefile; + char filename[1024]; + + if ( !g_PortalTrace.m_list.Count() ) + { + Warning("No trace generated from %d to %d\n", g_TraceClusterStart, g_TraceClusterStop ); + return; + } + + sprintf (filename, "%s.lin", source); + linefile = fopen (filename, "w"); + if (!linefile) + Error ("Couldn't open %s\n", filename); + + for ( int i = 0; i < g_PortalTrace.m_list.Count(); i++ ) + { + Vector p = g_PortalTrace.m_list[i]; + fprintf (linefile, "%f %f %f\n", p[0], p[1], p[2]); + } + fclose (linefile); + Warning("Wrote %s!!!\n", filename); +} + +/* +================== +RecursiveLeafFlow + +Flood fill through the leafs +If src_portal is NULL, this is the originating leaf +================== +*/ +void RecursiveLeafFlow (int leafnum, threaddata_t *thread, pstack_t *prevstack) +{ + pstack_t stack; + portal_t *p; + plane_t backplane; + leaf_t *leaf; + int i, j; + long *test, *might, *vis, more; + int pnum; + + // Early-out if we're a VMPI worker that's told to exit. If we don't do this here, then the + // worker might spin its wheels for a while on an expensive work unit and not be available to the pool. + // This is pretty common in vis. + if ( g_bVMPIEarlyExit ) + return; + + if ( leafnum == g_TraceClusterStop ) + { + DumpPortalTrace(&thread->pstack_head); + return; + } + thread->c_chains++; + + leaf = &leafs[leafnum]; + + prevstack->next = &stack; + + stack.next = NULL; + stack.leaf = leaf; + stack.portal = NULL; + + might = (long *)stack.mightsee; + vis = (long *)thread->base->portalvis; + + // check all portals for flowing into other leafs + for (i=0 ; i<leaf->portals.Count() ; i++) + { + + p = leaf->portals[i]; + pnum = p - portals; + + if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) ) + { + continue; // can't possibly see it + } + + // if the portal can't see anything we haven't allready seen, skip it + if (p->status == stat_done) + { + test = (long *)p->portalvis; + } + else + { + test = (long *)p->portalflood; + } + + more = 0; + for (j=0 ; j<portallongs ; j++) + { + might[j] = ((long *)prevstack->mightsee)[j] & test[j]; + more |= (might[j] & ~vis[j]); + } + + if ( !more && CheckBit( thread->base->portalvis, pnum ) ) + { // can't see anything new + continue; + } + + // get plane of portal, point normal into the neighbor leaf + stack.portalplane = p->plane; + VectorSubtract (vec3_origin, p->plane.normal, backplane.normal); + backplane.dist = -p->plane.dist; + + stack.portal = p; + stack.next = NULL; + stack.freewindings[0] = 1; + stack.freewindings[1] = 1; + stack.freewindings[2] = 1; + + float d = DotProduct (p->origin, thread->pstack_head.portalplane.normal); + d -= thread->pstack_head.portalplane.dist; + if (d < -p->radius) + { + continue; + } + else if (d > p->radius) + { + stack.pass = p->winding; + } + else + { + stack.pass = ChopWinding (p->winding, &stack, &thread->pstack_head.portalplane); + if (!stack.pass) + continue; + } + + + d = DotProduct (thread->base->origin, p->plane.normal); + d -= p->plane.dist; + if (d > thread->base->radius) + { + continue; + } + else if (d < -thread->base->radius) + { + stack.source = prevstack->source; + } + else + { + stack.source = ChopWinding (prevstack->source, &stack, &backplane); + if (!stack.source) + continue; + } + + + if (!prevstack->pass) + { // the second leaf can only be blocked if coplanar + + // mark the portal as visible + SetBit( thread->base->portalvis, pnum ); + + RecursiveLeafFlow (p->leaf, thread, &stack); + continue; + } + + stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, false, &stack); + if (!stack.pass) + continue; + + stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, true, &stack); + if (!stack.pass) + continue; + + // mark the portal as visible + SetBit( thread->base->portalvis, pnum ); + + // flow through it for real + RecursiveLeafFlow (p->leaf, thread, &stack); + } +} + + +/* +=============== +PortalFlow + +generates the portalvis bit vector +=============== +*/ +void PortalFlow (int iThread, int portalnum) +{ + threaddata_t data; + int i; + portal_t *p; + int c_might, c_can; + + p = sorted_portals[portalnum]; + p->status = stat_working; + + c_might = CountBits (p->portalflood, g_numportals*2); + + memset (&data, 0, sizeof(data)); + data.base = p; + + data.pstack_head.portal = p; + data.pstack_head.source = p->winding; + data.pstack_head.portalplane = p->plane; + for (i=0 ; i<portallongs ; i++) + ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i]; + + RecursiveLeafFlow (p->leaf, &data, &data.pstack_head); + + + p->status = stat_done; + + c_can = CountBits (p->portalvis, g_numportals*2); + + qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n", + (int)(p - portals), c_might, c_can, data.c_chains); +} + + +/* +=============================================================================== + +This is a rough first-order aproximation that is used to trivially reject some +of the final calculations. + + +Calculates portalfront and portalflood bit vectors + +=============================================================================== +*/ + +int c_flood, c_vis; + +/* +================== +SimpleFlood + +================== +*/ +void SimpleFlood (portal_t *srcportal, int leafnum) +{ + int i; + leaf_t *leaf; + portal_t *p; + int pnum; + + leaf = &leafs[leafnum]; + + for (i=0 ; i<leaf->portals.Count(); i++) + { + p = leaf->portals[i]; + pnum = p - portals; + if ( !CheckBit( srcportal->portalfront, pnum ) ) + continue; + + if ( CheckBit( srcportal->portalflood, pnum ) ) + continue; + + SetBit( srcportal->portalflood, pnum ); + + SimpleFlood (srcportal, p->leaf); + } +} + +/* +============== +BasePortalVis +============== +*/ +void BasePortalVis (int iThread, int portalnum) +{ + int j, k; + portal_t *tp, *p; + float d; + winding_t *w; + Vector segment; + double dist2, minDist2; + + // get the portal + p = portals+portalnum; + + // + // allocate memory for bitwise vis solutions for this portal + // + p->portalfront = (byte*)malloc (portalbytes); + memset (p->portalfront, 0, portalbytes); + + p->portalflood = (byte*)malloc (portalbytes); + memset (p->portalflood, 0, portalbytes); + + p->portalvis = (byte*)malloc (portalbytes); + memset (p->portalvis, 0, portalbytes); + + // + // test the given portal against all of the portals in the map + // + for (j=0, tp = portals ; j<g_numportals*2 ; j++, tp++) + { + // don't test against itself + if (j == portalnum) + continue; + + // + // + // + w = tp->winding; + for (k=0 ; k<w->numpoints ; k++) + { + d = DotProduct (w->points[k], p->plane.normal) - p->plane.dist; + if (d > ON_VIS_EPSILON) + break; + } + if (k == w->numpoints) + continue; // no points on front + + // + // + // + w = p->winding; + for (k=0 ; k<w->numpoints ; k++) + { + d = DotProduct (w->points[k], tp->plane.normal) - tp->plane.dist; + if (d < -ON_VIS_EPSILON) + break; + } + if (k == w->numpoints) + continue; // no points on front + + // + // if using radius visibility -- check to see if any portal points lie inside of the + // radius given + // + if( g_bUseRadius ) + { + w = tp->winding; + minDist2 = 1024000000.0; // 32000^2 + for( k = 0; k < w->numpoints; k++ ) + { + VectorSubtract( w->points[k], p->origin, segment ); + dist2 = ( segment[0] * segment[0] ) + ( segment[1] * segment[1] ) + ( segment[2] * segment[2] ); + if( dist2 < minDist2 ) + { + minDist2 = dist2; + } + } + + if( minDist2 > g_VisRadius ) + continue; + } + + // add current portal to given portal's list of visible portals + SetBit( p->portalfront, j ); + } + + SimpleFlood (p, p->leaf); + + p->nummightsee = CountBits (p->portalflood, g_numportals*2); +// Msg ("portal %i: %i mightsee\n", portalnum, p->nummightsee); + c_flood += p->nummightsee; +} + + + + + +/* +=============================================================================== + +This is a second order aproximation + +Calculates portalvis bit vector + +WAAAAAAY too slow. + +=============================================================================== +*/ + +/* +================== +RecursiveLeafBitFlow + +================== +*/ +void RecursiveLeafBitFlow (int leafnum, byte *mightsee, byte *cansee) +{ + portal_t *p; + leaf_t *leaf; + int i, j; + long more; + int pnum; + byte newmight[MAX_PORTALS/8]; + + leaf = &leafs[leafnum]; + +// check all portals for flowing into other leafs + for (i=0 ; i<leaf->portals.Count(); i++) + { + p = leaf->portals[i]; + pnum = p - portals; + + // if some previous portal can't see it, skip + if ( !CheckBit( mightsee, pnum ) ) + continue; + + // if this portal can see some portals we mightsee, recurse + more = 0; + for (j=0 ; j<portallongs ; j++) + { + ((long *)newmight)[j] = ((long *)mightsee)[j] + & ((long *)p->portalflood)[j]; + more |= ((long *)newmight)[j] & ~((long *)cansee)[j]; + } + + if (!more) + continue; // can't see anything new + + SetBit( cansee, pnum ); + + RecursiveLeafBitFlow (p->leaf, newmight, cansee); + } +} + +/* +============== +BetterPortalVis +============== +*/ +void BetterPortalVis (int portalnum) +{ + portal_t *p; + + p = portals+portalnum; + + RecursiveLeafBitFlow (p->leaf, p->portalflood, p->portalvis); + + // build leaf vis information + p->nummightsee = CountBits (p->portalvis, g_numportals*2); + c_vis += p->nummightsee; +} + + diff --git a/mp/src/utils/vvis/mpivis.cpp b/mp/src/utils/vvis/mpivis.cpp index 6da76ebc..58b76331 100644 --- a/mp/src/utils/vvis/mpivis.cpp +++ b/mp/src/utils/vvis/mpivis.cpp @@ -1,640 +1,640 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-
-#include <windows.h>
-#include "vis.h"
-#include "threads.h"
-#include "stdlib.h"
-#include "pacifier.h"
-#include "mpi_stats.h"
-#include "vmpi.h"
-#include "vmpi_dispatch.h"
-#include "vmpi_filesystem.h"
-#include "vmpi_distribute_work.h"
-#include "iphelpers.h"
-#include "threadhelpers.h"
-#include "vstdlib/random.h"
-#include "vmpi_tools_shared.h"
-#include <conio.h>
-#include "scratchpad_helpers.h"
-
-
-#define VMPI_VVIS_PACKET_ID 1
- // Sub packet IDs.
- #define VMPI_SUBPACKETID_DISCONNECT_NOTIFY 3 // We send ourselves this when there is a disconnect.
- #define VMPI_SUBPACKETID_BASEPORTALVIS 5
- #define VMPI_SUBPACKETID_PORTALFLOW 6
- #define VMPI_BASEPORTALVIS_RESULTS 7
- #define VMPI_BASEPORTALVIS_WORKER_DONE 8
- #define VMPI_PORTALFLOW_RESULTS 9
- #define VMPI_SUBPACKETID_BASEPORTALVIS_SYNC 11
- #define VMPI_SUBPACKETID_PORTALFLOW_SYNC 12
- #define VMPI_SUBPACKETID_MC_ADDR 13
-
-// DistributeWork owns this packet ID.
-#define VMPI_DISTRIBUTEWORK_PACKETID 2
-
-
-extern bool fastvis;
-
-// The worker waits until these are true.
-bool g_bBasePortalVisSync = false;
-bool g_bPortalFlowSync = false;
-
-CUtlVector<char> g_BasePortalVisResultsFilename;
-
-CCycleCount g_CPUTime;
-
-
-// This stuff is all for the multicast channel the master uses to send out the portal results.
-ISocket *g_pPortalMCSocket = NULL;
-CIPAddr g_PortalMCAddr;
-bool g_bGotMCAddr = false;
-HANDLE g_hMCThread = NULL;
-CEvent g_MCThreadExitEvent;
-unsigned long g_PortalMCThreadUniqueID = 0;
-int g_nMulticastPortalsReceived = 0;
-
-
-// Handle VVIS packets.
-bool VVIS_DispatchFn( MessageBuffer *pBuf, int iSource, int iPacketID )
-{
- switch ( pBuf->data[1] )
- {
- case VMPI_SUBPACKETID_MC_ADDR:
- {
- pBuf->setOffset( 2 );
- pBuf->read( &g_PortalMCAddr, sizeof( g_PortalMCAddr ) );
- g_bGotMCAddr = true;
- return true;
- }
-
- case VMPI_SUBPACKETID_DISCONNECT_NOTIFY:
- {
- // This is just used to cause nonblocking dispatches to jump out so loops like the one
- // in AppBarrier can handle the fact that there are disconnects.
- return true;
- }
-
- case VMPI_SUBPACKETID_BASEPORTALVIS_SYNC:
- {
- g_bBasePortalVisSync = true;
- return true;
- }
-
- case VMPI_SUBPACKETID_PORTALFLOW_SYNC:
- {
- g_bPortalFlowSync = true;
- return true;
- }
-
- case VMPI_BASEPORTALVIS_RESULTS:
- {
- const char *pFilename = &pBuf->data[2];
- g_BasePortalVisResultsFilename.CopyArray( pFilename, strlen( pFilename ) + 1 );
- return true;
- }
-
- default:
- {
- return false;
- }
- }
-}
-CDispatchReg g_VVISDispatchReg( VMPI_VVIS_PACKET_ID, VVIS_DispatchFn ); // register to handle the messages we want
-CDispatchReg g_DistributeWorkReg( VMPI_DISTRIBUTEWORK_PACKETID, DistributeWorkDispatch );
-
-
-
-void VMPI_DeletePortalMCSocket()
-{
- // Stop the thread if it exists.
- if ( g_hMCThread )
- {
- g_MCThreadExitEvent.SetEvent();
- WaitForSingleObject( g_hMCThread, INFINITE );
- CloseHandle( g_hMCThread );
- g_hMCThread = NULL;
- }
-
- if ( g_pPortalMCSocket )
- {
- g_pPortalMCSocket->Release();
- g_pPortalMCSocket = NULL;
- }
-}
-
-
-void VVIS_SetupMPI( int &argc, char **&argv )
-{
- if ( !VMPI_FindArg( argc, argv, "-mpi", "" ) && !VMPI_FindArg( argc, argv, VMPI_GetParamString( mpi_Worker ), "" ) )
- return;
-
- CmdLib_AtCleanup( VMPI_Stats_Term );
- CmdLib_AtCleanup( VMPI_DeletePortalMCSocket );
-
- VMPI_Stats_InstallSpewHook();
-
- // Force local mode?
- VMPIRunMode mode;
- if ( VMPI_FindArg( argc, argv, VMPI_GetParamString( mpi_Local ), "" ) )
- mode = VMPI_RUN_LOCAL;
- else
- mode = VMPI_RUN_NETWORKED;
-
- //
- // Extract mpi specific arguments
- //
- Msg( "Initializing VMPI...\n" );
- if ( !VMPI_Init( argc, argv, "dependency_info_vvis.txt", HandleMPIDisconnect, mode ) )
- {
- Error( "MPI_Init failed." );
- }
-
- StatsDB_InitStatsDatabase( argc, argv, "dbinfo_vvis.txt" );
-}
-
-
-void ProcessBasePortalVis( int iThread, uint64 iPortal, MessageBuffer *pBuf )
-{
- CTimeAdder adder( &g_CPUTime );
-
- BasePortalVis( iThread, iPortal );
-
- // Send my result to the master
- if ( pBuf )
- {
- portal_t * p = &portals[iPortal];
- pBuf->write( p->portalfront, portalbytes );
- pBuf->write( p->portalflood, portalbytes );
- }
-}
-
-
-void ReceiveBasePortalVis( uint64 iWorkUnit, MessageBuffer *pBuf, int iWorker )
-{
- portal_t * p = &portals[iWorkUnit];
- if ( p->portalflood != 0 || p->portalfront != 0 || p->portalvis != 0)
- {
- Msg("Duplicate portal %llu\n", iWorkUnit);
- }
-
- if ( pBuf->getLen() - pBuf->getOffset() != portalbytes*2 )
- Error( "Invalid packet in ReceiveBasePortalVis." );
-
- //
- // allocate memory for bitwise vis solutions for this portal
- //
- p->portalfront = (byte*)malloc (portalbytes);
- pBuf->read( p->portalfront, portalbytes );
-
- p->portalflood = (byte*)malloc (portalbytes);
- pBuf->read( p->portalflood, portalbytes );
-
- p->portalvis = (byte*)malloc (portalbytes);
- memset (p->portalvis, 0, portalbytes);
-
- p->nummightsee = CountBits( p->portalflood, g_numportals*2 );
-}
-
-
-//-----------------------------------------
-//
-// Run BasePortalVis across all available processing nodes
-// Then collect and redistribute the results.
-//
-void RunMPIBasePortalVis()
-{
- int i;
-
- Msg( "\n\nportalbytes: %d\nNum Work Units: %d\nTotal data size: %d\n", portalbytes, g_numportals*2, portalbytes*g_numportals*2 );
- Msg("%-20s ", "BasePortalVis:");
- if ( g_bMPIMaster )
- StartPacifier("");
-
-
- VMPI_SetCurrentStage( "RunMPIBasePortalVis" );
-
- // Note: we're aiming for about 1500 portals in a map, so about 3000 work units.
- g_CPUTime.Init();
- double elapsed = DistributeWork(
- g_numportals * 2, // # work units
- VMPI_DISTRIBUTEWORK_PACKETID, // packet ID
- ProcessBasePortalVis, // Worker function to process work units
- ReceiveBasePortalVis // Master function to receive work results
- );
-
- if ( g_bMPIMaster )
- {
- EndPacifier( false );
- Msg( " (%d)\n", (int)elapsed );
- }
-
- //
- // Distribute the results to all the workers.
- //
- if ( g_bMPIMaster )
- {
- if ( !fastvis )
- {
- VMPI_SetCurrentStage( "SendPortalResults" );
-
- // Store all the portal results in a temp file and multicast that to the workers.
- CUtlVector<char> allPortalData;
- allPortalData.SetSize( g_numportals * 2 * portalbytes * 2 );
-
- char *pOut = allPortalData.Base();
- for ( i=0; i < g_numportals * 2; i++)
- {
- portal_t *p = &portals[i];
-
- memcpy( pOut, p->portalfront, portalbytes );
- pOut += portalbytes;
-
- memcpy( pOut, p->portalflood, portalbytes );
- pOut += portalbytes;
- }
-
- const char *pVirtualFilename = "--portal-results--";
- VMPI_FileSystem_CreateVirtualFile( pVirtualFilename, allPortalData.Base(), allPortalData.Count() );
-
- char cPacketID[2] = { VMPI_VVIS_PACKET_ID, VMPI_BASEPORTALVIS_RESULTS };
- VMPI_Send2Chunks( cPacketID, sizeof( cPacketID ), pVirtualFilename, strlen( pVirtualFilename ) + 1, VMPI_PERSISTENT );
- }
- }
- else
- {
- VMPI_SetCurrentStage( "RecvPortalResults" );
-
- // Wait until we've received the filename from the master.
- while ( g_BasePortalVisResultsFilename.Count() == 0 )
- {
- VMPI_DispatchNextMessage();
- }
-
- // Open
- FileHandle_t fp = g_pFileSystem->Open( g_BasePortalVisResultsFilename.Base(), "rb", VMPI_VIRTUAL_FILES_PATH_ID );
- if ( !fp )
- Error( "Can't open '%s' to read portal info.", g_BasePortalVisResultsFilename.Base() );
-
- for ( i=0; i < g_numportals * 2; i++)
- {
- portal_t *p = &portals[i];
-
- p->portalfront = (byte*)malloc (portalbytes);
- g_pFileSystem->Read( p->portalfront, portalbytes, fp );
-
- p->portalflood = (byte*)malloc (portalbytes);
- g_pFileSystem->Read( p->portalflood, portalbytes, fp );
-
- p->portalvis = (byte*)malloc (portalbytes);
- memset (p->portalvis, 0, portalbytes);
-
- p->nummightsee = CountBits (p->portalflood, g_numportals*2);
- }
-
- g_pFileSystem->Close( fp );
- }
-
-
- if ( !g_bMPIMaster )
- {
- if ( g_iVMPIVerboseLevel >= 1 )
- Msg( "\n%% worker CPU utilization during BasePortalVis: %.1f\n", (g_CPUTime.GetSeconds() * 100.0f / elapsed) / numthreads );
- }
-}
-
-
-
-void ProcessPortalFlow( int iThread, uint64 iPortal, MessageBuffer *pBuf )
-{
- // Process Portal and distribute results
- CTimeAdder adder( &g_CPUTime );
-
- PortalFlow( iThread, iPortal );
-
- // Send my result to root and potentially the other slaves
- // The slave results are read in RecursiveLeafFlow
- //
- if ( pBuf )
- {
- portal_t * p = sorted_portals[iPortal];
- pBuf->write( p->portalvis, portalbytes );
- }
-}
-
-
-void ReceivePortalFlow( uint64 iWorkUnit, MessageBuffer *pBuf, int iWorker )
-{
- portal_t *p = sorted_portals[iWorkUnit];
-
- if ( p->status != stat_done )
- {
- pBuf->read( p->portalvis, portalbytes );
- p->status = stat_done;
-
-
- // Multicast the status of this portal out.
- if ( g_pPortalMCSocket )
- {
- char cPacketID[2] = { VMPI_VVIS_PACKET_ID, VMPI_PORTALFLOW_RESULTS };
- void *chunks[4] = { cPacketID, &g_PortalMCThreadUniqueID, &iWorkUnit, p->portalvis };
- int chunkLengths[4] = { sizeof( cPacketID ), sizeof( g_PortalMCThreadUniqueID ), sizeof( iWorkUnit ), portalbytes };
-
- g_pPortalMCSocket->SendChunksTo( &g_PortalMCAddr, chunks, chunkLengths, ARRAYSIZE( chunks ) );
- }
- }
-}
-
-
-DWORD WINAPI PortalMCThreadFn( LPVOID p )
-{
- CUtlVector<char> data;
- data.SetSize( portalbytes + 128 );
-
- DWORD waitTime = 0;
- while ( WaitForSingleObject( g_MCThreadExitEvent.GetEventHandle(), waitTime ) != WAIT_OBJECT_0 )
- {
- CIPAddr ipFrom;
- int len = g_pPortalMCSocket->RecvFrom( data.Base(), data.Count(), &ipFrom );
- if ( len == -1 )
- {
- waitTime = 20;
- }
- else
- {
- // These lengths must match exactly what is sent in ReceivePortalFlow.
- if ( len == 2 + sizeof( g_PortalMCThreadUniqueID ) + sizeof( int ) + portalbytes )
- {
- // Perform more validation...
- if ( data[0] == VMPI_VVIS_PACKET_ID && data[1] == VMPI_PORTALFLOW_RESULTS )
- {
- if ( *((unsigned long*)&data[2]) == g_PortalMCThreadUniqueID )
- {
- int iWorkUnit = *((int*)&data[6]);
- if ( iWorkUnit >= 0 && iWorkUnit < g_numportals*2 )
- {
- portal_t *p = sorted_portals[iWorkUnit];
- if ( p )
- {
- ++g_nMulticastPortalsReceived;
- memcpy( p->portalvis, &data[10], portalbytes );
- p->status = stat_done;
- waitTime = 0;
- }
- }
- }
- }
- }
- }
- }
-
- return 0;
-}
-
-
-void MCThreadCleanupFn()
-{
- g_MCThreadExitEvent.SetEvent();
-}
-
-
-// --------------------------------------------------------------------------------- //
-// Cheesy hack to let them stop the job early and keep the results of what has
-// been done so far.
-// --------------------------------------------------------------------------------- //
-
-class CVisDistributeWorkCallbacks : public IWorkUnitDistributorCallbacks
-{
-public:
- CVisDistributeWorkCallbacks()
- {
- m_bExitedEarly = false;
- m_iState = STATE_NONE;
- }
-
- virtual bool Update()
- {
- if ( kbhit() )
- {
- int key = toupper( getch() );
- if ( m_iState == STATE_NONE )
- {
- if ( key == 'M' )
- {
- m_iState = STATE_AT_MENU;
- Warning("\n\n"
- "----------------------\n"
- "1. Write scratchpad file.\n"
- "2. Exit early and use fast vis for remaining portals.\n"
- "\n"
- "0. Exit menu.\n"
- "----------------------\n"
- "\n"
- );
- }
- }
- else if ( m_iState == STATE_AT_MENU )
- {
- if ( key == '1' )
- {
- Warning(
- "\n"
- "\nWriting scratchpad file."
- "\nCommand line: scratchpad3dviewer -file scratch.pad\n"
- "\nRed portals are the portals that are fast vis'd."
- "\n"
- );
- m_iState = STATE_NONE;
- IScratchPad3D *pPad = ScratchPad3D_Create( "scratch.pad" );
- if ( pPad )
- {
- ScratchPad_DrawWorld( pPad, false );
-
- // Draw the portals that haven't been vis'd.
- for ( int i=0; i < g_numportals*2; i++ )
- {
- portal_t *p = sorted_portals[i];
- ScratchPad_DrawWinding( pPad, p->winding->numpoints, p->winding->points, Vector( 1, 0, 0 ), Vector( .3, .3, .3 ) );
- }
-
- pPad->Release();
- }
- }
- else if ( key == '2' )
- {
- // Exit the process early.
- m_bExitedEarly = true;
- return true;
- }
- else if ( key == '0' )
- {
- m_iState = STATE_NONE;
- Warning( "\n\nExited menu.\n\n" );
- }
- }
- }
-
- return false;
- }
-
-public:
- enum
- {
- STATE_NONE,
- STATE_AT_MENU
- };
-
- bool m_bExitedEarly;
- int m_iState; // STATE_ enum.
-};
-
-
-CVisDistributeWorkCallbacks g_VisDistributeWorkCallbacks;
-
-
-void CheckExitedEarly()
-{
- if ( g_VisDistributeWorkCallbacks.m_bExitedEarly )
- {
- Warning( "\nExited early, using fastvis results...\n" );
- Warning( "Exited early, using fastvis results...\n" );
-
- // Use the fastvis results for portals that we didn't get results for.
- for ( int i=0; i < g_numportals*2; i++ )
- {
- if ( sorted_portals[i]->status != stat_done )
- {
- sorted_portals[i]->portalvis = sorted_portals[i]->portalflood;
- sorted_portals[i]->status = stat_done;
- }
- }
- }
-}
-
-
-//-----------------------------------------
-//
-// Run PortalFlow across all available processing nodes
-//
-void RunMPIPortalFlow()
-{
- Msg( "%-20s ", "MPIPortalFlow:" );
- if ( g_bMPIMaster )
- StartPacifier("");
-
- // Workers wait until we get the MC socket address.
- g_PortalMCThreadUniqueID = StatsDB_GetUniqueJobID();
- if ( g_bMPIMaster )
- {
- CCycleCount cnt;
- cnt.Sample();
- CUniformRandomStream randomStream;
- randomStream.SetSeed( cnt.GetMicroseconds() );
-
- g_PortalMCAddr.port = randomStream.RandomInt( 22000, 25000 ); // Pulled out of something else.
- g_PortalMCAddr.ip[0] = (unsigned char)RandomInt( 225, 238 );
- g_PortalMCAddr.ip[1] = (unsigned char)RandomInt( 0, 255 );
- g_PortalMCAddr.ip[2] = (unsigned char)RandomInt( 0, 255 );
- g_PortalMCAddr.ip[3] = (unsigned char)RandomInt( 3, 255 );
-
- g_pPortalMCSocket = CreateIPSocket();
- int i=0;
- for ( i; i < 5; i++ )
- {
- if ( g_pPortalMCSocket->BindToAny( randomStream.RandomInt( 20000, 30000 ) ) )
- break;
- }
- if ( i == 5 )
- {
- Error( "RunMPIPortalFlow: can't open a socket to multicast on." );
- }
-
- char cPacketID[2] = { VMPI_VVIS_PACKET_ID, VMPI_SUBPACKETID_MC_ADDR };
- VMPI_Send2Chunks( cPacketID, sizeof( cPacketID ), &g_PortalMCAddr, sizeof( g_PortalMCAddr ), VMPI_PERSISTENT );
- }
- else
- {
- VMPI_SetCurrentStage( "wait for MC address" );
-
- while ( !g_bGotMCAddr )
- {
- VMPI_DispatchNextMessage();
- }
-
- // Open our multicast receive socket.
- g_pPortalMCSocket = CreateMulticastListenSocket( g_PortalMCAddr );
- if ( !g_pPortalMCSocket )
- {
- char err[512];
- IP_GetLastErrorString( err, sizeof( err ) );
- Error( "RunMPIPortalFlow: CreateMulticastListenSocket failed. (%s).", err );
- }
-
- // Make a thread to listen for the data on the multicast socket.
- DWORD dwDummy = 0;
- g_MCThreadExitEvent.Init( false, false );
-
- // Make sure we kill the MC thread if the app exits ungracefully.
- CmdLib_AtCleanup( MCThreadCleanupFn );
-
- g_hMCThread = CreateThread(
- NULL,
- 0,
- PortalMCThreadFn,
- NULL,
- 0,
- &dwDummy );
-
- if ( !g_hMCThread )
- {
- Error( "RunMPIPortalFlow: CreateThread failed for multicast receive thread." );
- }
- }
-
- VMPI_SetCurrentStage( "RunMPIBasePortalFlow" );
-
-
- g_pDistributeWorkCallbacks = &g_VisDistributeWorkCallbacks;
-
- g_CPUTime.Init();
- double elapsed = DistributeWork(
- g_numportals * 2, // # work units
- VMPI_DISTRIBUTEWORK_PACKETID, // packet ID
- ProcessPortalFlow, // Worker function to process work units
- ReceivePortalFlow // Master function to receive work results
- );
-
- g_pDistributeWorkCallbacks = NULL;
-
- CheckExitedEarly();
-
- // Stop the multicast stuff.
- VMPI_DeletePortalMCSocket();
-
- if( !g_bMPIMaster )
- {
- if ( g_iVMPIVerboseLevel >= 1 )
- {
- Msg( "Received %d (out of %d) portals from multicast.\n", g_nMulticastPortalsReceived, g_numportals * 2 );
- Msg( "%.1f%% CPU utilization during PortalFlow\n", (g_CPUTime.GetSeconds() * 100.0f / elapsed) / numthreads );
- }
-
- Msg( "VVIS worker finished. Over and out.\n" );
- VMPI_SetCurrentStage( "worker done" );
-
- CmdLib_Exit( 0 );
- }
-
- if ( g_bMPIMaster )
- {
- EndPacifier( false );
- Msg( " (%d)\n", (int)elapsed );
- }
-}
-
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include <windows.h> +#include "vis.h" +#include "threads.h" +#include "stdlib.h" +#include "pacifier.h" +#include "mpi_stats.h" +#include "vmpi.h" +#include "vmpi_dispatch.h" +#include "vmpi_filesystem.h" +#include "vmpi_distribute_work.h" +#include "iphelpers.h" +#include "threadhelpers.h" +#include "vstdlib/random.h" +#include "vmpi_tools_shared.h" +#include <conio.h> +#include "scratchpad_helpers.h" + + +#define VMPI_VVIS_PACKET_ID 1 + // Sub packet IDs. + #define VMPI_SUBPACKETID_DISCONNECT_NOTIFY 3 // We send ourselves this when there is a disconnect. + #define VMPI_SUBPACKETID_BASEPORTALVIS 5 + #define VMPI_SUBPACKETID_PORTALFLOW 6 + #define VMPI_BASEPORTALVIS_RESULTS 7 + #define VMPI_BASEPORTALVIS_WORKER_DONE 8 + #define VMPI_PORTALFLOW_RESULTS 9 + #define VMPI_SUBPACKETID_BASEPORTALVIS_SYNC 11 + #define VMPI_SUBPACKETID_PORTALFLOW_SYNC 12 + #define VMPI_SUBPACKETID_MC_ADDR 13 + +// DistributeWork owns this packet ID. +#define VMPI_DISTRIBUTEWORK_PACKETID 2 + + +extern bool fastvis; + +// The worker waits until these are true. +bool g_bBasePortalVisSync = false; +bool g_bPortalFlowSync = false; + +CUtlVector<char> g_BasePortalVisResultsFilename; + +CCycleCount g_CPUTime; + + +// This stuff is all for the multicast channel the master uses to send out the portal results. +ISocket *g_pPortalMCSocket = NULL; +CIPAddr g_PortalMCAddr; +bool g_bGotMCAddr = false; +HANDLE g_hMCThread = NULL; +CEvent g_MCThreadExitEvent; +unsigned long g_PortalMCThreadUniqueID = 0; +int g_nMulticastPortalsReceived = 0; + + +// Handle VVIS packets. +bool VVIS_DispatchFn( MessageBuffer *pBuf, int iSource, int iPacketID ) +{ + switch ( pBuf->data[1] ) + { + case VMPI_SUBPACKETID_MC_ADDR: + { + pBuf->setOffset( 2 ); + pBuf->read( &g_PortalMCAddr, sizeof( g_PortalMCAddr ) ); + g_bGotMCAddr = true; + return true; + } + + case VMPI_SUBPACKETID_DISCONNECT_NOTIFY: + { + // This is just used to cause nonblocking dispatches to jump out so loops like the one + // in AppBarrier can handle the fact that there are disconnects. + return true; + } + + case VMPI_SUBPACKETID_BASEPORTALVIS_SYNC: + { + g_bBasePortalVisSync = true; + return true; + } + + case VMPI_SUBPACKETID_PORTALFLOW_SYNC: + { + g_bPortalFlowSync = true; + return true; + } + + case VMPI_BASEPORTALVIS_RESULTS: + { + const char *pFilename = &pBuf->data[2]; + g_BasePortalVisResultsFilename.CopyArray( pFilename, strlen( pFilename ) + 1 ); + return true; + } + + default: + { + return false; + } + } +} +CDispatchReg g_VVISDispatchReg( VMPI_VVIS_PACKET_ID, VVIS_DispatchFn ); // register to handle the messages we want +CDispatchReg g_DistributeWorkReg( VMPI_DISTRIBUTEWORK_PACKETID, DistributeWorkDispatch ); + + + +void VMPI_DeletePortalMCSocket() +{ + // Stop the thread if it exists. + if ( g_hMCThread ) + { + g_MCThreadExitEvent.SetEvent(); + WaitForSingleObject( g_hMCThread, INFINITE ); + CloseHandle( g_hMCThread ); + g_hMCThread = NULL; + } + + if ( g_pPortalMCSocket ) + { + g_pPortalMCSocket->Release(); + g_pPortalMCSocket = NULL; + } +} + + +void VVIS_SetupMPI( int &argc, char **&argv ) +{ + if ( !VMPI_FindArg( argc, argv, "-mpi", "" ) && !VMPI_FindArg( argc, argv, VMPI_GetParamString( mpi_Worker ), "" ) ) + return; + + CmdLib_AtCleanup( VMPI_Stats_Term ); + CmdLib_AtCleanup( VMPI_DeletePortalMCSocket ); + + VMPI_Stats_InstallSpewHook(); + + // Force local mode? + VMPIRunMode mode; + if ( VMPI_FindArg( argc, argv, VMPI_GetParamString( mpi_Local ), "" ) ) + mode = VMPI_RUN_LOCAL; + else + mode = VMPI_RUN_NETWORKED; + + // + // Extract mpi specific arguments + // + Msg( "Initializing VMPI...\n" ); + if ( !VMPI_Init( argc, argv, "dependency_info_vvis.txt", HandleMPIDisconnect, mode ) ) + { + Error( "MPI_Init failed." ); + } + + StatsDB_InitStatsDatabase( argc, argv, "dbinfo_vvis.txt" ); +} + + +void ProcessBasePortalVis( int iThread, uint64 iPortal, MessageBuffer *pBuf ) +{ + CTimeAdder adder( &g_CPUTime ); + + BasePortalVis( iThread, iPortal ); + + // Send my result to the master + if ( pBuf ) + { + portal_t * p = &portals[iPortal]; + pBuf->write( p->portalfront, portalbytes ); + pBuf->write( p->portalflood, portalbytes ); + } +} + + +void ReceiveBasePortalVis( uint64 iWorkUnit, MessageBuffer *pBuf, int iWorker ) +{ + portal_t * p = &portals[iWorkUnit]; + if ( p->portalflood != 0 || p->portalfront != 0 || p->portalvis != 0) + { + Msg("Duplicate portal %llu\n", iWorkUnit); + } + + if ( pBuf->getLen() - pBuf->getOffset() != portalbytes*2 ) + Error( "Invalid packet in ReceiveBasePortalVis." ); + + // + // allocate memory for bitwise vis solutions for this portal + // + p->portalfront = (byte*)malloc (portalbytes); + pBuf->read( p->portalfront, portalbytes ); + + p->portalflood = (byte*)malloc (portalbytes); + pBuf->read( p->portalflood, portalbytes ); + + p->portalvis = (byte*)malloc (portalbytes); + memset (p->portalvis, 0, portalbytes); + + p->nummightsee = CountBits( p->portalflood, g_numportals*2 ); +} + + +//----------------------------------------- +// +// Run BasePortalVis across all available processing nodes +// Then collect and redistribute the results. +// +void RunMPIBasePortalVis() +{ + int i; + + Msg( "\n\nportalbytes: %d\nNum Work Units: %d\nTotal data size: %d\n", portalbytes, g_numportals*2, portalbytes*g_numportals*2 ); + Msg("%-20s ", "BasePortalVis:"); + if ( g_bMPIMaster ) + StartPacifier(""); + + + VMPI_SetCurrentStage( "RunMPIBasePortalVis" ); + + // Note: we're aiming for about 1500 portals in a map, so about 3000 work units. + g_CPUTime.Init(); + double elapsed = DistributeWork( + g_numportals * 2, // # work units + VMPI_DISTRIBUTEWORK_PACKETID, // packet ID + ProcessBasePortalVis, // Worker function to process work units + ReceiveBasePortalVis // Master function to receive work results + ); + + if ( g_bMPIMaster ) + { + EndPacifier( false ); + Msg( " (%d)\n", (int)elapsed ); + } + + // + // Distribute the results to all the workers. + // + if ( g_bMPIMaster ) + { + if ( !fastvis ) + { + VMPI_SetCurrentStage( "SendPortalResults" ); + + // Store all the portal results in a temp file and multicast that to the workers. + CUtlVector<char> allPortalData; + allPortalData.SetSize( g_numportals * 2 * portalbytes * 2 ); + + char *pOut = allPortalData.Base(); + for ( i=0; i < g_numportals * 2; i++) + { + portal_t *p = &portals[i]; + + memcpy( pOut, p->portalfront, portalbytes ); + pOut += portalbytes; + + memcpy( pOut, p->portalflood, portalbytes ); + pOut += portalbytes; + } + + const char *pVirtualFilename = "--portal-results--"; + VMPI_FileSystem_CreateVirtualFile( pVirtualFilename, allPortalData.Base(), allPortalData.Count() ); + + char cPacketID[2] = { VMPI_VVIS_PACKET_ID, VMPI_BASEPORTALVIS_RESULTS }; + VMPI_Send2Chunks( cPacketID, sizeof( cPacketID ), pVirtualFilename, strlen( pVirtualFilename ) + 1, VMPI_PERSISTENT ); + } + } + else + { + VMPI_SetCurrentStage( "RecvPortalResults" ); + + // Wait until we've received the filename from the master. + while ( g_BasePortalVisResultsFilename.Count() == 0 ) + { + VMPI_DispatchNextMessage(); + } + + // Open + FileHandle_t fp = g_pFileSystem->Open( g_BasePortalVisResultsFilename.Base(), "rb", VMPI_VIRTUAL_FILES_PATH_ID ); + if ( !fp ) + Error( "Can't open '%s' to read portal info.", g_BasePortalVisResultsFilename.Base() ); + + for ( i=0; i < g_numportals * 2; i++) + { + portal_t *p = &portals[i]; + + p->portalfront = (byte*)malloc (portalbytes); + g_pFileSystem->Read( p->portalfront, portalbytes, fp ); + + p->portalflood = (byte*)malloc (portalbytes); + g_pFileSystem->Read( p->portalflood, portalbytes, fp ); + + p->portalvis = (byte*)malloc (portalbytes); + memset (p->portalvis, 0, portalbytes); + + p->nummightsee = CountBits (p->portalflood, g_numportals*2); + } + + g_pFileSystem->Close( fp ); + } + + + if ( !g_bMPIMaster ) + { + if ( g_iVMPIVerboseLevel >= 1 ) + Msg( "\n%% worker CPU utilization during BasePortalVis: %.1f\n", (g_CPUTime.GetSeconds() * 100.0f / elapsed) / numthreads ); + } +} + + + +void ProcessPortalFlow( int iThread, uint64 iPortal, MessageBuffer *pBuf ) +{ + // Process Portal and distribute results + CTimeAdder adder( &g_CPUTime ); + + PortalFlow( iThread, iPortal ); + + // Send my result to root and potentially the other slaves + // The slave results are read in RecursiveLeafFlow + // + if ( pBuf ) + { + portal_t * p = sorted_portals[iPortal]; + pBuf->write( p->portalvis, portalbytes ); + } +} + + +void ReceivePortalFlow( uint64 iWorkUnit, MessageBuffer *pBuf, int iWorker ) +{ + portal_t *p = sorted_portals[iWorkUnit]; + + if ( p->status != stat_done ) + { + pBuf->read( p->portalvis, portalbytes ); + p->status = stat_done; + + + // Multicast the status of this portal out. + if ( g_pPortalMCSocket ) + { + char cPacketID[2] = { VMPI_VVIS_PACKET_ID, VMPI_PORTALFLOW_RESULTS }; + void *chunks[4] = { cPacketID, &g_PortalMCThreadUniqueID, &iWorkUnit, p->portalvis }; + int chunkLengths[4] = { sizeof( cPacketID ), sizeof( g_PortalMCThreadUniqueID ), sizeof( iWorkUnit ), portalbytes }; + + g_pPortalMCSocket->SendChunksTo( &g_PortalMCAddr, chunks, chunkLengths, ARRAYSIZE( chunks ) ); + } + } +} + + +DWORD WINAPI PortalMCThreadFn( LPVOID p ) +{ + CUtlVector<char> data; + data.SetSize( portalbytes + 128 ); + + DWORD waitTime = 0; + while ( WaitForSingleObject( g_MCThreadExitEvent.GetEventHandle(), waitTime ) != WAIT_OBJECT_0 ) + { + CIPAddr ipFrom; + int len = g_pPortalMCSocket->RecvFrom( data.Base(), data.Count(), &ipFrom ); + if ( len == -1 ) + { + waitTime = 20; + } + else + { + // These lengths must match exactly what is sent in ReceivePortalFlow. + if ( len == 2 + sizeof( g_PortalMCThreadUniqueID ) + sizeof( int ) + portalbytes ) + { + // Perform more validation... + if ( data[0] == VMPI_VVIS_PACKET_ID && data[1] == VMPI_PORTALFLOW_RESULTS ) + { + if ( *((unsigned long*)&data[2]) == g_PortalMCThreadUniqueID ) + { + int iWorkUnit = *((int*)&data[6]); + if ( iWorkUnit >= 0 && iWorkUnit < g_numportals*2 ) + { + portal_t *p = sorted_portals[iWorkUnit]; + if ( p ) + { + ++g_nMulticastPortalsReceived; + memcpy( p->portalvis, &data[10], portalbytes ); + p->status = stat_done; + waitTime = 0; + } + } + } + } + } + } + } + + return 0; +} + + +void MCThreadCleanupFn() +{ + g_MCThreadExitEvent.SetEvent(); +} + + +// --------------------------------------------------------------------------------- // +// Cheesy hack to let them stop the job early and keep the results of what has +// been done so far. +// --------------------------------------------------------------------------------- // + +class CVisDistributeWorkCallbacks : public IWorkUnitDistributorCallbacks +{ +public: + CVisDistributeWorkCallbacks() + { + m_bExitedEarly = false; + m_iState = STATE_NONE; + } + + virtual bool Update() + { + if ( kbhit() ) + { + int key = toupper( getch() ); + if ( m_iState == STATE_NONE ) + { + if ( key == 'M' ) + { + m_iState = STATE_AT_MENU; + Warning("\n\n" + "----------------------\n" + "1. Write scratchpad file.\n" + "2. Exit early and use fast vis for remaining portals.\n" + "\n" + "0. Exit menu.\n" + "----------------------\n" + "\n" + ); + } + } + else if ( m_iState == STATE_AT_MENU ) + { + if ( key == '1' ) + { + Warning( + "\n" + "\nWriting scratchpad file." + "\nCommand line: scratchpad3dviewer -file scratch.pad\n" + "\nRed portals are the portals that are fast vis'd." + "\n" + ); + m_iState = STATE_NONE; + IScratchPad3D *pPad = ScratchPad3D_Create( "scratch.pad" ); + if ( pPad ) + { + ScratchPad_DrawWorld( pPad, false ); + + // Draw the portals that haven't been vis'd. + for ( int i=0; i < g_numportals*2; i++ ) + { + portal_t *p = sorted_portals[i]; + ScratchPad_DrawWinding( pPad, p->winding->numpoints, p->winding->points, Vector( 1, 0, 0 ), Vector( .3, .3, .3 ) ); + } + + pPad->Release(); + } + } + else if ( key == '2' ) + { + // Exit the process early. + m_bExitedEarly = true; + return true; + } + else if ( key == '0' ) + { + m_iState = STATE_NONE; + Warning( "\n\nExited menu.\n\n" ); + } + } + } + + return false; + } + +public: + enum + { + STATE_NONE, + STATE_AT_MENU + }; + + bool m_bExitedEarly; + int m_iState; // STATE_ enum. +}; + + +CVisDistributeWorkCallbacks g_VisDistributeWorkCallbacks; + + +void CheckExitedEarly() +{ + if ( g_VisDistributeWorkCallbacks.m_bExitedEarly ) + { + Warning( "\nExited early, using fastvis results...\n" ); + Warning( "Exited early, using fastvis results...\n" ); + + // Use the fastvis results for portals that we didn't get results for. + for ( int i=0; i < g_numportals*2; i++ ) + { + if ( sorted_portals[i]->status != stat_done ) + { + sorted_portals[i]->portalvis = sorted_portals[i]->portalflood; + sorted_portals[i]->status = stat_done; + } + } + } +} + + +//----------------------------------------- +// +// Run PortalFlow across all available processing nodes +// +void RunMPIPortalFlow() +{ + Msg( "%-20s ", "MPIPortalFlow:" ); + if ( g_bMPIMaster ) + StartPacifier(""); + + // Workers wait until we get the MC socket address. + g_PortalMCThreadUniqueID = StatsDB_GetUniqueJobID(); + if ( g_bMPIMaster ) + { + CCycleCount cnt; + cnt.Sample(); + CUniformRandomStream randomStream; + randomStream.SetSeed( cnt.GetMicroseconds() ); + + g_PortalMCAddr.port = randomStream.RandomInt( 22000, 25000 ); // Pulled out of something else. + g_PortalMCAddr.ip[0] = (unsigned char)RandomInt( 225, 238 ); + g_PortalMCAddr.ip[1] = (unsigned char)RandomInt( 0, 255 ); + g_PortalMCAddr.ip[2] = (unsigned char)RandomInt( 0, 255 ); + g_PortalMCAddr.ip[3] = (unsigned char)RandomInt( 3, 255 ); + + g_pPortalMCSocket = CreateIPSocket(); + int i=0; + for ( i; i < 5; i++ ) + { + if ( g_pPortalMCSocket->BindToAny( randomStream.RandomInt( 20000, 30000 ) ) ) + break; + } + if ( i == 5 ) + { + Error( "RunMPIPortalFlow: can't open a socket to multicast on." ); + } + + char cPacketID[2] = { VMPI_VVIS_PACKET_ID, VMPI_SUBPACKETID_MC_ADDR }; + VMPI_Send2Chunks( cPacketID, sizeof( cPacketID ), &g_PortalMCAddr, sizeof( g_PortalMCAddr ), VMPI_PERSISTENT ); + } + else + { + VMPI_SetCurrentStage( "wait for MC address" ); + + while ( !g_bGotMCAddr ) + { + VMPI_DispatchNextMessage(); + } + + // Open our multicast receive socket. + g_pPortalMCSocket = CreateMulticastListenSocket( g_PortalMCAddr ); + if ( !g_pPortalMCSocket ) + { + char err[512]; + IP_GetLastErrorString( err, sizeof( err ) ); + Error( "RunMPIPortalFlow: CreateMulticastListenSocket failed. (%s).", err ); + } + + // Make a thread to listen for the data on the multicast socket. + DWORD dwDummy = 0; + g_MCThreadExitEvent.Init( false, false ); + + // Make sure we kill the MC thread if the app exits ungracefully. + CmdLib_AtCleanup( MCThreadCleanupFn ); + + g_hMCThread = CreateThread( + NULL, + 0, + PortalMCThreadFn, + NULL, + 0, + &dwDummy ); + + if ( !g_hMCThread ) + { + Error( "RunMPIPortalFlow: CreateThread failed for multicast receive thread." ); + } + } + + VMPI_SetCurrentStage( "RunMPIBasePortalFlow" ); + + + g_pDistributeWorkCallbacks = &g_VisDistributeWorkCallbacks; + + g_CPUTime.Init(); + double elapsed = DistributeWork( + g_numportals * 2, // # work units + VMPI_DISTRIBUTEWORK_PACKETID, // packet ID + ProcessPortalFlow, // Worker function to process work units + ReceivePortalFlow // Master function to receive work results + ); + + g_pDistributeWorkCallbacks = NULL; + + CheckExitedEarly(); + + // Stop the multicast stuff. + VMPI_DeletePortalMCSocket(); + + if( !g_bMPIMaster ) + { + if ( g_iVMPIVerboseLevel >= 1 ) + { + Msg( "Received %d (out of %d) portals from multicast.\n", g_nMulticastPortalsReceived, g_numportals * 2 ); + Msg( "%.1f%% CPU utilization during PortalFlow\n", (g_CPUTime.GetSeconds() * 100.0f / elapsed) / numthreads ); + } + + Msg( "VVIS worker finished. Over and out.\n" ); + VMPI_SetCurrentStage( "worker done" ); + + CmdLib_Exit( 0 ); + } + + if ( g_bMPIMaster ) + { + EndPacifier( false ); + Msg( " (%d)\n", (int)elapsed ); + } +} + diff --git a/mp/src/utils/vvis/mpivis.h b/mp/src/utils/vvis/mpivis.h index a6ee349e..ed44aa25 100644 --- a/mp/src/utils/vvis/mpivis.h +++ b/mp/src/utils/vvis/mpivis.h @@ -1,21 +1,21 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//=============================================================================//
-
-#ifndef MPIVIS_H
-#define MPIVIS_H
-#ifdef _WIN32
-#pragma once
-#endif
-
-
-void VVIS_SetupMPI( int &argc, char **&argv );
-
-
-void RunMPIBasePortalVis();
-void RunMPIPortalFlow();
-
-
-#endif // MPIVIS_H
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef MPIVIS_H +#define MPIVIS_H +#ifdef _WIN32 +#pragma once +#endif + + +void VVIS_SetupMPI( int &argc, char **&argv ); + + +void RunMPIBasePortalVis(); +void RunMPIPortalFlow(); + + +#endif // MPIVIS_H diff --git a/mp/src/utils/vvis/vis.h b/mp/src/utils/vvis/vis.h index c4b58414..0a4c314e 100644 --- a/mp/src/utils/vvis/vis.h +++ b/mp/src/utils/vvis/vis.h @@ -1,125 +1,125 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-// vis.h
-
-#include "cmdlib.h"
-#include "mathlib/mathlib.h"
-#include "bsplib.h"
-
-
-#define MAX_PORTALS 65536
-
-#define PORTALFILE "PRT1"
-
-extern bool g_bUseRadius; // prototyping TF2, "radius vis" solution
-extern double g_VisRadius; // the radius for the TF2 "radius vis"
-
-struct plane_t
-{
- Vector normal;
- float dist;
-};
-
-#define MAX_POINTS_ON_WINDING 64
-#define MAX_POINTS_ON_FIXED_WINDING 12
-
-struct winding_t
-{
- qboolean original; // don't free, it's part of the portal
- int numpoints;
- Vector points[MAX_POINTS_ON_FIXED_WINDING]; // variable sized
-};
-
-winding_t *NewWinding (int points);
-void FreeWinding (winding_t *w);
-winding_t *CopyWinding (winding_t *w);
-
-
-typedef enum {stat_none, stat_working, stat_done} vstatus_t;
-struct portal_t
-{
- plane_t plane; // normal pointing into neighbor
- int leaf; // neighbor
-
- Vector origin; // for fast clip testing
- float radius;
-
- winding_t *winding;
- vstatus_t status;
- byte *portalfront; // [portals], preliminary
- byte *portalflood; // [portals], intermediate
- byte *portalvis; // [portals], final
-
- int nummightsee; // bit count on portalflood for sort
-};
-
-struct leaf_t
-{
- CUtlVector<portal_t *> portals;
-};
-
-
-struct pstack_t
-{
- byte mightsee[MAX_PORTALS/8]; // bit string
- pstack_t *next;
- leaf_t *leaf;
- portal_t *portal; // portal exiting
- winding_t *source;
- winding_t *pass;
-
- winding_t windings[3]; // source, pass, temp in any order
- int freewindings[3];
-
- plane_t portalplane;
-};
-
-struct threaddata_t
-{
- portal_t *base;
- int c_chains;
- pstack_t pstack_head;
-};
-
-extern int g_numportals;
-extern int portalclusters;
-
-extern portal_t *portals;
-extern leaf_t *leafs;
-
-extern int c_portaltest, c_portalpass, c_portalcheck;
-extern int c_portalskip, c_leafskip;
-extern int c_vistest, c_mighttest;
-extern int c_chains;
-
-extern byte *vismap, *vismap_p, *vismap_end; // past visfile
-
-extern int testlevel;
-
-extern byte *uncompressed;
-
-extern int leafbytes, leaflongs;
-extern int portalbytes, portallongs;
-
-
-void LeafFlow (int leafnum);
-
-
-void BasePortalVis (int iThread, int portalnum);
-void BetterPortalVis (int portalnum);
-void PortalFlow (int iThread, int portalnum);
-void WritePortalTrace( const char *source );
-
-extern portal_t *sorted_portals[MAX_MAP_PORTALS*2];
-extern int g_TraceClusterStart, g_TraceClusterStop;
-
-int CountBits (byte *bits, int numbits);
-
-#define CheckBit( bitstring, bitNumber ) ( (bitstring)[ ((bitNumber) >> 3) ] & ( 1 << ( (bitNumber) & 7 ) ) )
-#define SetBit( bitstring, bitNumber ) ( (bitstring)[ ((bitNumber) >> 3) ] |= ( 1 << ( (bitNumber) & 7 ) ) )
-#define ClearBit( bitstring, bitNumber ) ( (bitstring)[ ((bitNumber) >> 3) ] &= ~( 1 << ( (bitNumber) & 7 ) ) )
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// vis.h + +#include "cmdlib.h" +#include "mathlib/mathlib.h" +#include "bsplib.h" + + +#define MAX_PORTALS 65536 + +#define PORTALFILE "PRT1" + +extern bool g_bUseRadius; // prototyping TF2, "radius vis" solution +extern double g_VisRadius; // the radius for the TF2 "radius vis" + +struct plane_t +{ + Vector normal; + float dist; +}; + +#define MAX_POINTS_ON_WINDING 64 +#define MAX_POINTS_ON_FIXED_WINDING 12 + +struct winding_t +{ + qboolean original; // don't free, it's part of the portal + int numpoints; + Vector points[MAX_POINTS_ON_FIXED_WINDING]; // variable sized +}; + +winding_t *NewWinding (int points); +void FreeWinding (winding_t *w); +winding_t *CopyWinding (winding_t *w); + + +typedef enum {stat_none, stat_working, stat_done} vstatus_t; +struct portal_t +{ + plane_t plane; // normal pointing into neighbor + int leaf; // neighbor + + Vector origin; // for fast clip testing + float radius; + + winding_t *winding; + vstatus_t status; + byte *portalfront; // [portals], preliminary + byte *portalflood; // [portals], intermediate + byte *portalvis; // [portals], final + + int nummightsee; // bit count on portalflood for sort +}; + +struct leaf_t +{ + CUtlVector<portal_t *> portals; +}; + + +struct pstack_t +{ + byte mightsee[MAX_PORTALS/8]; // bit string + pstack_t *next; + leaf_t *leaf; + portal_t *portal; // portal exiting + winding_t *source; + winding_t *pass; + + winding_t windings[3]; // source, pass, temp in any order + int freewindings[3]; + + plane_t portalplane; +}; + +struct threaddata_t +{ + portal_t *base; + int c_chains; + pstack_t pstack_head; +}; + +extern int g_numportals; +extern int portalclusters; + +extern portal_t *portals; +extern leaf_t *leafs; + +extern int c_portaltest, c_portalpass, c_portalcheck; +extern int c_portalskip, c_leafskip; +extern int c_vistest, c_mighttest; +extern int c_chains; + +extern byte *vismap, *vismap_p, *vismap_end; // past visfile + +extern int testlevel; + +extern byte *uncompressed; + +extern int leafbytes, leaflongs; +extern int portalbytes, portallongs; + + +void LeafFlow (int leafnum); + + +void BasePortalVis (int iThread, int portalnum); +void BetterPortalVis (int portalnum); +void PortalFlow (int iThread, int portalnum); +void WritePortalTrace( const char *source ); + +extern portal_t *sorted_portals[MAX_MAP_PORTALS*2]; +extern int g_TraceClusterStart, g_TraceClusterStop; + +int CountBits (byte *bits, int numbits); + +#define CheckBit( bitstring, bitNumber ) ( (bitstring)[ ((bitNumber) >> 3) ] & ( 1 << ( (bitNumber) & 7 ) ) ) +#define SetBit( bitstring, bitNumber ) ( (bitstring)[ ((bitNumber) >> 3) ] |= ( 1 << ( (bitNumber) & 7 ) ) ) +#define ClearBit( bitstring, bitNumber ) ( (bitstring)[ ((bitNumber) >> 3) ] &= ~( 1 << ( (bitNumber) & 7 ) ) ) diff --git a/mp/src/utils/vvis/vvis.cpp b/mp/src/utils/vvis/vvis.cpp index 577c1cc3..0fb61388 100644 --- a/mp/src/utils/vvis/vvis.cpp +++ b/mp/src/utils/vvis/vvis.cpp @@ -1,1240 +1,1240 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-// vis.c
-
-#include <windows.h>
-#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 ; i<w->numpoints ; 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 ; i<count ; i++)
- {
- p = l->portals[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 ; i<g_numportals*2 ; i++)
- sorted_portals[i] = &portals[i];
-
- if (nosort)
- return;
- qsort (sorted_portals, g_numportals*2, sizeof(sorted_portals[0]), PComp);
-}
-
-
-/*
-==============
-LeafVectorFromPortalVector
-==============
-*/
-int LeafVectorFromPortalVector (byte *portalbits, byte *leafbits)
-{
- int i;
- portal_t *p;
- int c_leafs;
-
-
- memset (leafbits, 0, leafbytes);
-
- for (i=0 ; i<g_numportals*2 ; i++)
- {
- if ( CheckBit( portalbits, i ) )
- {
- p = portals+i;
- SetBit( leafbits, p->leaf );
- }
- }
-
- 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 ; j<portallongs ; j++)
- ((long *)portalvector)[j] |= ((long *)p->portalvis)[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 ; 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);
- }
-}
-
-
-void CalcVisTrace (void)
-{
- RunThreadsOnIndividual (g_numportals*2, true, BasePortalVis);
- BuildTracePortals( g_TraceClusterStart );
- // NOTE: We only schedule the one-way portals out of the start cluster here
- // so don't run g_numportals*2 in this case
- RunThreadsOnIndividual (g_numportals, true, PortalFlow);
-}
-
-/*
-==================
-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, count*100.0/totalvis);
- Msg ("Total clusters visible: %i\n", totalvis);
- Msg ("Average clusters visible: %i\n", totalvis / portalclusters);
-}
-
-
-void SetPortalSphere (portal_t *p)
-{
- int i;
- Vector total, dist;
- winding_t *w;
- float r, bestr;
-
- w = p->winding;
- VectorCopy (vec3_origin, total);
- for (i=0 ; i<w->numpoints ; i++)
- {
- VectorAdd (total, w->points[i], total);
- }
-
- for (i=0 ; i<3 ; i++)
- total[i] /= w->numpoints;
-
- bestr = 0;
- for (i=0 ; i<w->numpoints ; 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<char> 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<g_numportals ; i++)
- {
- if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1])
- != 3)
- Error ("LoadPortals: reading portal %i", i);
- if (numpoints > 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 ; j<numpoints ; j++)
- {
- double v[3];
- int k;
-
- // scanf into double, then assign to vec_t
- // so we don't care what size vec_t is
- if (fscanf (f, "(%lf %lf %lf ) "
- , &v[0], &v[1], &v[2]) != 3)
- Error ("LoadPortals: reading portal %i", i);
- for (k=0 ; k<3 ; k++)
- w->points[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 ; j<w->numpoints ; 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 ; i++)
- {
- scan = uncompressedvis + i*leafbytes;
- memcpy (uncompressed, scan, leafbytes);
- for (j=0 ; j<leafbytes ; j++)
- {
- bitbyte = scan[j];
- if (!bitbyte)
- continue;
- for (k=0 ; k<8 ; k++)
- {
- if (! (bitbyte & (1<<k)) )
- continue;
- // OR this pvs row into the phs
- index = ((j<<3)+k);
- if (index >= portalclusters)
- Error ("Bad bit in PVS"); // pad bits should be 0
- src = (long *)(uncompressedvis + index*leafbytes);
- dest = (long *)uncompressed;
- for (l=0 ; l<leaflongs ; l++)
- ((long *)uncompressed)[l] |= src[l];
- }
- }
- for (j=0 ; j<portalclusters ; j++)
- {
- if ( CheckBit( uncompressed, j ) )
- {
- count++;
- }
- }
-
- //
- // compress the bit string
- //
- j = CompressVis (uncompressed, compressed);
-
- dest = (long *)vismap_p;
- vismap_p += j;
-
- if (vismap_p > 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<listplane_t> 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<argc ; i++)
- {
- if (!Q_stricmp(argv[i],"-threads"))
- {
- numthreads = atoi (argv[i+1]);
- i++;
- }
- else if (!Q_stricmp(argv[i], "-fast"))
- {
- Msg ("fastvis = true\n");
- fastvis = true;
- }
- else if (!Q_stricmp(argv[i], "-v") || !Q_stricmp(argv[i], "-verbose"))
- {
- Msg ("verbose = true\n");
- verbose = true;
- }
- else if( !Q_stricmp( argv[i], "-radius_override" ) )
- {
- g_bUseRadius = true;
- g_VisRadius = atof( argv[i+1] );
- i++;
- Msg( "Vis Radius = %4.2f\n", g_VisRadius );
- g_VisRadius = g_VisRadius * g_VisRadius; // so distance check can be squared
- }
- else if( !Q_stricmp( argv[i], "-trace" ) )
- {
- g_TraceClusterStart = atoi( argv[i+1] );
- i++;
- g_TraceClusterStop = atoi( argv[i+1] );
- i++;
- Msg( "Tracing vis from cluster %d to %d\n", g_TraceClusterStart, g_TraceClusterStop );
- }
- else if (!Q_stricmp (argv[i],"-nosort"))
- {
- Msg ("nosort = true\n");
- nosort = true;
- }
- else if (!Q_stricmp (argv[i],"-tmpin"))
- strcpy (inbase, "/tmp");
- else if( !Q_stricmp( argv[i], "-low" ) )
- {
- g_bLowPriority = true;
- }
- else if ( !Q_stricmp( argv[i], "-FullMinidumps" ) )
- {
- EnableFullMinidumps( true );
- }
- else if ( !Q_stricmp( argv[i], CMDLINEOPTION_NOVCONFIG ) )
- {
- }
- else if ( !Q_stricmp( argv[i], "-vproject" ) || !Q_stricmp( argv[i], "-game" ) )
- {
- ++i;
- }
- else if ( !Q_stricmp( argv[i], "-allowdebug" ) || !Q_stricmp( argv[i], "-steam" ) )
- {
- // nothing to do here, but don't bail on this option
- }
- // NOTE: the -mpi checks must come last here because they allow the previous argument
- // to be -mpi as well. If it game before something else like -game, then if the previous
- // argument was -mpi and the current argument was something valid like -game, it would skip it.
- else if ( !Q_strncasecmp( argv[i], "-mpi", 4 ) || !Q_strncasecmp( argv[i-1], "-mpi", 4 ) )
- {
- if ( stricmp( argv[i], "-mpi" ) == 0 )
- g_bUseMPI = true;
-
- // Any other args that start with -mpi are ok too.
- if ( i == argc - 1 )
- break;
- }
- else if (argv[i][0] == '-')
- {
- Warning("VBSP: Unknown option \"%s\"\n\n", argv[i]);
- i = 100000; // force it to print the usage
- break;
- }
- else
- break;
- }
- return i;
-}
-
-
-void PrintCommandLine( int argc, char **argv )
-{
- Warning( "Command line: " );
- for ( int z=0; z < argc; z++ )
- {
- Warning( "\"%s\" ", argv[z] );
- }
- Warning( "\n\n" );
-}
-
-
-void PrintUsage( int argc, char **argv )
-{
- PrintCommandLine( argc, argv );
-
- Warning(
- "usage : vvis [options...] bspfile\n"
- "example: vvis -fast c:\\hl2\\hl2\\maps\\test\n"
- "\n"
- "Common options:\n"
- "\n"
- " -v (or -verbose): Turn on verbose output (also shows more command\n"
- " -fast : Only do first quick pass on vis calculations.\n"
- " -mpi : Use VMPI to distribute computations.\n"
- " -low : Run as an idle-priority process.\n"
- " env_fog_controller specifies one.\n"
- "\n"
- " -vproject <directory> : Override the VPROJECT environment variable.\n"
- " -game <directory> : 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 <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\\<mapname>.\n"
- " -tmpout : Make portals come from \\tmp\\<mapname>.\n"
- " -trace <start cluster> <end cluster> : 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 );
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +// vis.c + +#include <windows.h> +#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 ; i<w->numpoints ; 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 ; i<count ; i++) + { + p = l->portals[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 ; i<g_numportals*2 ; i++) + sorted_portals[i] = &portals[i]; + + if (nosort) + return; + qsort (sorted_portals, g_numportals*2, sizeof(sorted_portals[0]), PComp); +} + + +/* +============== +LeafVectorFromPortalVector +============== +*/ +int LeafVectorFromPortalVector (byte *portalbits, byte *leafbits) +{ + int i; + portal_t *p; + int c_leafs; + + + memset (leafbits, 0, leafbytes); + + for (i=0 ; i<g_numportals*2 ; i++) + { + if ( CheckBit( portalbits, i ) ) + { + p = portals+i; + SetBit( leafbits, p->leaf ); + } + } + + 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 ; j<portallongs ; j++) + ((long *)portalvector)[j] |= ((long *)p->portalvis)[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 ; 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); + } +} + + +void CalcVisTrace (void) +{ + RunThreadsOnIndividual (g_numportals*2, true, BasePortalVis); + BuildTracePortals( g_TraceClusterStart ); + // NOTE: We only schedule the one-way portals out of the start cluster here + // so don't run g_numportals*2 in this case + RunThreadsOnIndividual (g_numportals, true, PortalFlow); +} + +/* +================== +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, count*100.0/totalvis); + Msg ("Total clusters visible: %i\n", totalvis); + Msg ("Average clusters visible: %i\n", totalvis / portalclusters); +} + + +void SetPortalSphere (portal_t *p) +{ + int i; + Vector total, dist; + winding_t *w; + float r, bestr; + + w = p->winding; + VectorCopy (vec3_origin, total); + for (i=0 ; i<w->numpoints ; i++) + { + VectorAdd (total, w->points[i], total); + } + + for (i=0 ; i<3 ; i++) + total[i] /= w->numpoints; + + bestr = 0; + for (i=0 ; i<w->numpoints ; 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<char> 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<g_numportals ; i++) + { + if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) + != 3) + Error ("LoadPortals: reading portal %i", i); + if (numpoints > 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 ; j<numpoints ; j++) + { + double v[3]; + int k; + + // scanf into double, then assign to vec_t + // so we don't care what size vec_t is + if (fscanf (f, "(%lf %lf %lf ) " + , &v[0], &v[1], &v[2]) != 3) + Error ("LoadPortals: reading portal %i", i); + for (k=0 ; k<3 ; k++) + w->points[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 ; j<w->numpoints ; 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 ; i++) + { + scan = uncompressedvis + i*leafbytes; + memcpy (uncompressed, scan, leafbytes); + for (j=0 ; j<leafbytes ; j++) + { + bitbyte = scan[j]; + if (!bitbyte) + continue; + for (k=0 ; k<8 ; k++) + { + if (! (bitbyte & (1<<k)) ) + continue; + // OR this pvs row into the phs + index = ((j<<3)+k); + if (index >= portalclusters) + Error ("Bad bit in PVS"); // pad bits should be 0 + src = (long *)(uncompressedvis + index*leafbytes); + dest = (long *)uncompressed; + for (l=0 ; l<leaflongs ; l++) + ((long *)uncompressed)[l] |= src[l]; + } + } + for (j=0 ; j<portalclusters ; j++) + { + if ( CheckBit( uncompressed, j ) ) + { + count++; + } + } + + // + // compress the bit string + // + j = CompressVis (uncompressed, compressed); + + dest = (long *)vismap_p; + vismap_p += j; + + if (vismap_p > 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<listplane_t> 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<argc ; i++) + { + if (!Q_stricmp(argv[i],"-threads")) + { + numthreads = atoi (argv[i+1]); + i++; + } + else if (!Q_stricmp(argv[i], "-fast")) + { + Msg ("fastvis = true\n"); + fastvis = true; + } + else if (!Q_stricmp(argv[i], "-v") || !Q_stricmp(argv[i], "-verbose")) + { + Msg ("verbose = true\n"); + verbose = true; + } + else if( !Q_stricmp( argv[i], "-radius_override" ) ) + { + g_bUseRadius = true; + g_VisRadius = atof( argv[i+1] ); + i++; + Msg( "Vis Radius = %4.2f\n", g_VisRadius ); + g_VisRadius = g_VisRadius * g_VisRadius; // so distance check can be squared + } + else if( !Q_stricmp( argv[i], "-trace" ) ) + { + g_TraceClusterStart = atoi( argv[i+1] ); + i++; + g_TraceClusterStop = atoi( argv[i+1] ); + i++; + Msg( "Tracing vis from cluster %d to %d\n", g_TraceClusterStart, g_TraceClusterStop ); + } + else if (!Q_stricmp (argv[i],"-nosort")) + { + Msg ("nosort = true\n"); + nosort = true; + } + else if (!Q_stricmp (argv[i],"-tmpin")) + strcpy (inbase, "/tmp"); + else if( !Q_stricmp( argv[i], "-low" ) ) + { + g_bLowPriority = true; + } + else if ( !Q_stricmp( argv[i], "-FullMinidumps" ) ) + { + EnableFullMinidumps( true ); + } + else if ( !Q_stricmp( argv[i], CMDLINEOPTION_NOVCONFIG ) ) + { + } + else if ( !Q_stricmp( argv[i], "-vproject" ) || !Q_stricmp( argv[i], "-game" ) ) + { + ++i; + } + else if ( !Q_stricmp( argv[i], "-allowdebug" ) || !Q_stricmp( argv[i], "-steam" ) ) + { + // nothing to do here, but don't bail on this option + } + // NOTE: the -mpi checks must come last here because they allow the previous argument + // to be -mpi as well. If it game before something else like -game, then if the previous + // argument was -mpi and the current argument was something valid like -game, it would skip it. + else if ( !Q_strncasecmp( argv[i], "-mpi", 4 ) || !Q_strncasecmp( argv[i-1], "-mpi", 4 ) ) + { + if ( stricmp( argv[i], "-mpi" ) == 0 ) + g_bUseMPI = true; + + // Any other args that start with -mpi are ok too. + if ( i == argc - 1 ) + break; + } + else if (argv[i][0] == '-') + { + Warning("VBSP: Unknown option \"%s\"\n\n", argv[i]); + i = 100000; // force it to print the usage + break; + } + else + break; + } + return i; +} + + +void PrintCommandLine( int argc, char **argv ) +{ + Warning( "Command line: " ); + for ( int z=0; z < argc; z++ ) + { + Warning( "\"%s\" ", argv[z] ); + } + Warning( "\n\n" ); +} + + +void PrintUsage( int argc, char **argv ) +{ + PrintCommandLine( argc, argv ); + + Warning( + "usage : vvis [options...] bspfile\n" + "example: vvis -fast c:\\hl2\\hl2\\maps\\test\n" + "\n" + "Common options:\n" + "\n" + " -v (or -verbose): Turn on verbose output (also shows more command\n" + " -fast : Only do first quick pass on vis calculations.\n" + " -mpi : Use VMPI to distribute computations.\n" + " -low : Run as an idle-priority process.\n" + " env_fog_controller specifies one.\n" + "\n" + " -vproject <directory> : Override the VPROJECT environment variable.\n" + " -game <directory> : 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 <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\\<mapname>.\n" + " -tmpout : Make portals come from \\tmp\\<mapname>.\n" + " -trace <start cluster> <end cluster> : 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 ); diff --git a/mp/src/utils/vvis/vvis_dll.vpc b/mp/src/utils/vvis/vvis_dll.vpc index 34ac8fcb..43001443 100644 --- a/mp/src/utils/vvis/vvis_dll.vpc +++ b/mp/src/utils/vvis/vvis_dll.vpc @@ -1,101 +1,101 @@ -//-----------------------------------------------------------------------------
-// VVIS_DLL.VPC
-//
-// Project Script
-//-----------------------------------------------------------------------------
-
-$Macro SRCDIR "..\.."
-$Macro OUTBINDIR "$SRCDIR\..\game\bin"
-
-$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
-
-$Configuration
-{
- $Compiler
- {
- $AdditionalIncludeDirectories "$BASE,..\common,..\vmpi,..\vmpi\mysql\include"
- $PreprocessorDefinitions "$BASE;MPI;PROTECTED_THINGS_DISABLE"
- }
-
- $Linker
- {
- $AdditionalDependencies "$BASE odbc32.lib odbccp32.lib ws2_32.lib"
- }
-}
-
-$Project "Vvis_dll"
-{
- $Folder "Source Files"
- {
- -$File "$SRCDIR\public\tier0\memoverride.cpp"
-
- $File "..\common\bsplib.cpp"
- $File "..\common\cmdlib.cpp"
- $File "$SRCDIR\public\collisionutils.cpp"
- $File "$SRCDIR\public\filesystem_helpers.cpp"
- $File "flow.cpp"
- $File "$SRCDIR\public\loadcmdline.cpp"
- $File "$SRCDIR\public\lumpfiles.cpp"
- $File "..\common\mpi_stats.cpp"
- $File "mpivis.cpp"
- $File "..\common\MySqlDatabase.cpp"
- $File "..\common\pacifier.cpp"
- $File "$SRCDIR\public\scratchpad3d.cpp"
- $File "..\common\scratchpad_helpers.cpp"
- $File "..\common\scriplib.cpp"
- $File "..\common\threads.cpp"
- $File "..\common\tools_minidump.cpp"
- $File "..\common\tools_minidump.h"
- $File "..\common\vmpi_tools_shared.cpp"
- $File "vvis.cpp"
- $File "WaterDist.cpp"
- $File "$SRCDIR\public\zip_utils.cpp"
- }
-
- $Folder "Header Files"
- {
- $File "$SRCDIR\public\mathlib\amd3dx.h"
- $File "$SRCDIR\public\tier0\basetypes.h"
- $File "$SRCDIR\public\BSPFILE.H"
- $File "$SRCDIR\public\bspflags.h"
- $File "..\common\bsplib.h"
- $File "$SRCDIR\public\BSPTreeData.h"
- $File "$SRCDIR\public\mathlib\bumpvects.h"
- $File "$SRCDIR\public\tier1\byteswap.h"
- $File "$SRCDIR\public\tier1\checksum_crc.h"
- $File "$SRCDIR\public\tier1\checksum_md5.h"
- $File "..\common\cmdlib.h"
- $File "$SRCDIR\public\cmodel.h"
- $File "$SRCDIR\public\tier0\commonmacros.h"
- $File "$SRCDIR\public\GameBSPFile.h"
- $File "..\common\ISQLDBReplyTarget.h"
- $File "$SRCDIR\public\mathlib\mathlib.h"
- $File "mpivis.h"
- $File "..\common\MySqlDatabase.h"
- $File "..\common\pacifier.h"
- $File "..\common\scriplib.h"
- $File "$SRCDIR\public\tier1\strtools.h"
- $File "..\common\threads.h"
- $File "$SRCDIR\public\tier1\utlbuffer.h"
- $File "$SRCDIR\public\tier1\utllinkedlist.h"
- $File "$SRCDIR\public\tier1\utlmemory.h"
- $File "$SRCDIR\public\tier1\utlrbtree.h"
- $File "$SRCDIR\public\tier1\utlsymbol.h"
- $File "$SRCDIR\public\tier1\utlvector.h"
- $File "$SRCDIR\public\vcollide.h"
- $File "$SRCDIR\public\mathlib\vector.h"
- $File "$SRCDIR\public\mathlib\vector2d.h"
- $File "vis.h"
- $File "..\vmpi\vmpi_distribute_work.h"
- $File "..\common\vmpi_tools_shared.h"
- $File "$SRCDIR\public\vstdlib\vstdlib.h"
- $File "$SRCDIR\public\wadtypes.h"
- }
-
- $Folder "Link Libraries"
- {
- $Lib mathlib
- $Lib tier2
- $Lib vmpi
- }
-}
+//----------------------------------------------------------------------------- +// VVIS_DLL.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin" + +$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc" + +$Configuration +{ + $Compiler + { + $AdditionalIncludeDirectories "$BASE,..\common,..\vmpi,..\vmpi\mysql\include" + $PreprocessorDefinitions "$BASE;MPI;PROTECTED_THINGS_DISABLE" + } + + $Linker + { + $AdditionalDependencies "$BASE odbc32.lib odbccp32.lib ws2_32.lib" + } +} + +$Project "Vvis_dll" +{ + $Folder "Source Files" + { + -$File "$SRCDIR\public\tier0\memoverride.cpp" + + $File "..\common\bsplib.cpp" + $File "..\common\cmdlib.cpp" + $File "$SRCDIR\public\collisionutils.cpp" + $File "$SRCDIR\public\filesystem_helpers.cpp" + $File "flow.cpp" + $File "$SRCDIR\public\loadcmdline.cpp" + $File "$SRCDIR\public\lumpfiles.cpp" + $File "..\common\mpi_stats.cpp" + $File "mpivis.cpp" + $File "..\common\MySqlDatabase.cpp" + $File "..\common\pacifier.cpp" + $File "$SRCDIR\public\scratchpad3d.cpp" + $File "..\common\scratchpad_helpers.cpp" + $File "..\common\scriplib.cpp" + $File "..\common\threads.cpp" + $File "..\common\tools_minidump.cpp" + $File "..\common\tools_minidump.h" + $File "..\common\vmpi_tools_shared.cpp" + $File "vvis.cpp" + $File "WaterDist.cpp" + $File "$SRCDIR\public\zip_utils.cpp" + } + + $Folder "Header Files" + { + $File "$SRCDIR\public\mathlib\amd3dx.h" + $File "$SRCDIR\public\tier0\basetypes.h" + $File "$SRCDIR\public\BSPFILE.H" + $File "$SRCDIR\public\bspflags.h" + $File "..\common\bsplib.h" + $File "$SRCDIR\public\BSPTreeData.h" + $File "$SRCDIR\public\mathlib\bumpvects.h" + $File "$SRCDIR\public\tier1\byteswap.h" + $File "$SRCDIR\public\tier1\checksum_crc.h" + $File "$SRCDIR\public\tier1\checksum_md5.h" + $File "..\common\cmdlib.h" + $File "$SRCDIR\public\cmodel.h" + $File "$SRCDIR\public\tier0\commonmacros.h" + $File "$SRCDIR\public\GameBSPFile.h" + $File "..\common\ISQLDBReplyTarget.h" + $File "$SRCDIR\public\mathlib\mathlib.h" + $File "mpivis.h" + $File "..\common\MySqlDatabase.h" + $File "..\common\pacifier.h" + $File "..\common\scriplib.h" + $File "$SRCDIR\public\tier1\strtools.h" + $File "..\common\threads.h" + $File "$SRCDIR\public\tier1\utlbuffer.h" + $File "$SRCDIR\public\tier1\utllinkedlist.h" + $File "$SRCDIR\public\tier1\utlmemory.h" + $File "$SRCDIR\public\tier1\utlrbtree.h" + $File "$SRCDIR\public\tier1\utlsymbol.h" + $File "$SRCDIR\public\tier1\utlvector.h" + $File "$SRCDIR\public\vcollide.h" + $File "$SRCDIR\public\mathlib\vector.h" + $File "$SRCDIR\public\mathlib\vector2d.h" + $File "vis.h" + $File "..\vmpi\vmpi_distribute_work.h" + $File "..\common\vmpi_tools_shared.h" + $File "$SRCDIR\public\vstdlib\vstdlib.h" + $File "$SRCDIR\public\wadtypes.h" + } + + $Folder "Link Libraries" + { + $Lib mathlib + $Lib tier2 + $Lib vmpi + } +} |