aboutsummaryrefslogtreecommitdiff
path: root/mp/src/utils/vvis
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /mp/src/utils/vvis
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/utils/vvis')
-rw-r--r--mp/src/utils/vvis/WaterDist.cpp30
-rw-r--r--mp/src/utils/vvis/flow.cpp881
-rw-r--r--mp/src/utils/vvis/mpivis.cpp640
-rw-r--r--mp/src/utils/vvis/mpivis.h21
-rw-r--r--mp/src/utils/vvis/vis.h125
-rw-r--r--mp/src/utils/vvis/vvis.cpp1240
-rw-r--r--mp/src/utils/vvis/vvis_dll-2010.vcxproj291
-rw-r--r--mp/src/utils/vvis/vvis_dll-2010.vcxproj.filters218
8 files changed, 3446 insertions, 0 deletions
diff --git a/mp/src/utils/vvis/WaterDist.cpp b/mp/src/utils/vvis/WaterDist.cpp
new file mode 100644
index 00000000..5ed380c8
--- /dev/null
+++ b/mp/src/utils/vvis/WaterDist.cpp
@@ -0,0 +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.
+
+ }
+}
+
diff --git a/mp/src/utils/vvis/flow.cpp b/mp/src/utils/vvis/flow.cpp
new file mode 100644
index 00000000..7234e68a
--- /dev/null
+++ b/mp/src/utils/vvis/flow.cpp
@@ -0,0 +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 &center)
+{
+ 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
new file mode 100644
index 00000000..6da76ebc
--- /dev/null
+++ b/mp/src/utils/vvis/mpivis.cpp
@@ -0,0 +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 );
+ }
+}
+
diff --git a/mp/src/utils/vvis/mpivis.h b/mp/src/utils/vvis/mpivis.h
new file mode 100644
index 00000000..a6ee349e
--- /dev/null
+++ b/mp/src/utils/vvis/mpivis.h
@@ -0,0 +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
diff --git a/mp/src/utils/vvis/vis.h b/mp/src/utils/vvis/vis.h
new file mode 100644
index 00000000..c4b58414
--- /dev/null
+++ b/mp/src/utils/vvis/vis.h
@@ -0,0 +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 ) ) )
diff --git a/mp/src/utils/vvis/vvis.cpp b/mp/src/utils/vvis/vvis.cpp
new file mode 100644
index 00000000..577c1cc3
--- /dev/null
+++ b/mp/src/utils/vvis/vvis.cpp
@@ -0,0 +1,1240 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// vis.c
+
+#include <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-2010.vcxproj b/mp/src/utils/vvis/vvis_dll-2010.vcxproj
new file mode 100644
index 00000000..3099cd82
--- /dev/null
+++ b/mp/src/utils/vvis/vvis_dll-2010.vcxproj
@@ -0,0 +1,291 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>Vvis_dll</ProjectName>
+ <ProjectGuid>{AC70A841-561F-4DAE-7864-E50541AD99ED}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <TargetName>vvis_dll</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <TargetName>vvis_dll</TargetName>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\win32\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\win32\</IntDir>
+ <ExecutablePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\devtools\vstools;$(ExecutablePath);$(Path)</ExecutablePath>
+ <PreBuildEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</PreBuildEventUseInBuild>
+ <PreLinkEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</PreLinkEventUseInBuild>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+ <GenerateManifest Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</GenerateManifest>
+ <PostBuildEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</PostBuildEventUseInBuild>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\win32\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\win32\</IntDir>
+ <ExecutablePath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\devtools\vstools;$(ExecutablePath);$(Path)</ExecutablePath>
+ <PreBuildEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</PreBuildEventUseInBuild>
+ <PreLinkEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</PreLinkEventUseInBuild>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ <GenerateManifest Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</GenerateManifest>
+ <PostBuildEventUseInBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</PostBuildEventUseInBuild>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <PreBuildEvent>
+ </PreBuildEvent>
+ <ClCompile>
+ <AdditionalOptions> /MP</AdditionalOptions>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\common;..\..\public;..\..\public\tier0;..\..\public\tier1;..\common;..\vmpi;..\vmpi\mysql\include</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_HAS_ITERATOR_DEBUGGING=0;WIN32;_WIN32;_DEBUG;DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;DLLNAME=vvis_dll;RAD_TELEMETRY_DISABLED;COMPILER_MSVC32;MPI;PROTECTED_THINGS_DISABLE;VPCGAMECAPS=VALVE;PROJECTDIR=D:\dev\games\rel\hl2\src\utils\vvis;_DLL_EXT=.dll;VPCGAME=valve</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <BasicRuntimeChecks>Default</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <AssemblerListingLocation>$(IntDir)/</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)/</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)/</ProgramDataBaseFileName>
+ <GenerateXMLDocumentationFiles>false</GenerateXMLDocumentationFiles>
+ <BrowseInformation>false</BrowseInformation>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <CompileAs>CompileAsCpp</CompileAs>
+ <BrowseInformationFile>$(IntDir)/</BrowseInformationFile>
+ <ErrorReporting>Prompt</ErrorReporting>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE</PreprocessorDefinitions>
+ <Culture>1033</Culture>
+ </ResourceCompile>
+ <PreLinkEvent>
+ </PreLinkEvent>
+ <Link>
+ <AdditionalOptions> /ignore:4221</AdditionalOptions>
+ <AdditionalDependencies>%(AdditionalDependencies);odbc32.lib;odbccp32.lib;ws2_32.lib</AdditionalDependencies>
+ <ShowProgress>NotSet</ShowProgress>
+ <OutputFile>$(OutDir)\vvis_dll.dll</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <AdditionalLibraryDirectories>..\..\lib\common;..\..\lib\public</AdditionalLibraryDirectories>
+ <IgnoreSpecificDefaultLibraries>libc;libcd;libcmt</IgnoreSpecificDefaultLibraries>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)/$(TargetName).pdb</ProgramDatabaseFile>
+ <GenerateMapFile>false</GenerateMapFile>
+ <MapFileName>$(IntDir)/$(TargetName).map</MapFileName>
+ <SubSystem>Windows</SubSystem>
+ <BaseAddress> </BaseAddress>
+ <TargetMachine>MachineX86</TargetMachine>
+ <LinkErrorReporting>PromptImmediately</LinkErrorReporting>
+ <LinkLibraryDependencies>false</LinkLibraryDependencies>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ </Link>
+ <Manifest>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </Manifest>
+ <Xdcmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </Xdcmake>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>$(OutDir)/vvis_dll.bsc</OutputFile>
+ </Bscmake>
+ <PostBuildEvent>
+ <Message>Publishing to ..\..\..\game\bin</Message>
+ <Command>if not exist &quot;..\..\..\game\bin&quot; mkdir &quot;..\..\..\game\bin&quot;&#x0D;&#x0A;copy &quot;$(TargetDir)&quot;$(TargetFileName) &quot;..\..\..\game\bin\$(TargetFileName)&quot;&#x0D;&#x0A;if ERRORLEVEL 1 goto BuildEventFailed&#x0D;&#x0A;if exist &quot;$(TargetDir)&quot;$(TargetName).map copy &quot;$(TargetDir)&quot;$(TargetName).map ..\..\..\game\bin\$(TargetName).map&#x0D;&#x0A;copy &quot;$(TargetDir)&quot;$(TargetName).pdb ..\..\..\game\bin\$(TargetName).pdb&#x0D;&#x0A;if ERRORLEVEL 1 goto BuildEventFailed&#x0D;&#x0A;goto BuildEventOK&#x0D;&#x0A;:BuildEventFailed&#x0D;&#x0A;echo *** ERROR! PostBuildStep FAILED for $(ProjectName)! EXE or DLL is probably running. ***&#x0D;&#x0A;del /q &quot;$(TargetDir)&quot;$(TargetFileName)&#x0D;&#x0A;exit 1&#x0D;&#x0A;:BuildEventOK&#x0D;&#x0A;</Command>
+ </PostBuildEvent>
+ <CustomBuildStep>
+ </CustomBuildStep>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <PreBuildEvent>
+ </PreBuildEvent>
+ <ClCompile>
+ <AdditionalOptions> /MP /d2Zi+</AdditionalOptions>
+ <Optimization>MaxSpeed</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\common;..\..\public;..\..\public\tier0;..\..\public\tier1;..\common;..\vmpi;..\vmpi\mysql\include</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;DLLNAME=vvis_dll;RAD_TELEMETRY_DISABLED;COMPILER_MSVC32;MPI;PROTECTED_THINGS_DISABLE;VPCGAMECAPS=VALVE;PROJECTDIR=D:\dev\games\rel\hl2\src\utils\vvis;_DLL_EXT=.dll;VPCGAME=valve</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <AssemblerListingLocation>$(IntDir)/</AssemblerListingLocation>
+ <ObjectFileName>$(IntDir)/</ObjectFileName>
+ <ProgramDataBaseFileName>$(IntDir)/</ProgramDataBaseFileName>
+ <GenerateXMLDocumentationFiles>false</GenerateXMLDocumentationFiles>
+ <BrowseInformation>false</BrowseInformation>
+ <WarningLevel>Level4</WarningLevel>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <CompileAs>CompileAsCpp</CompileAs>
+ <BrowseInformationFile>$(IntDir)/</BrowseInformationFile>
+ <ErrorReporting>Prompt</ErrorReporting>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE</PreprocessorDefinitions>
+ <Culture>1033</Culture>
+ </ResourceCompile>
+ <PreLinkEvent>
+ </PreLinkEvent>
+ <Link>
+ <AdditionalOptions> /DYNAMICBASE /ignore:4221</AdditionalOptions>
+ <AdditionalDependencies>%(AdditionalDependencies);odbc32.lib;odbccp32.lib;ws2_32.lib</AdditionalDependencies>
+ <ShowProgress>NotSet</ShowProgress>
+ <OutputFile>$(OutDir)\vvis_dll.dll</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <AdditionalLibraryDirectories>..\..\lib\common;..\..\lib\public</AdditionalLibraryDirectories>
+ <IgnoreSpecificDefaultLibraries>libc;libcd;libcmtd</IgnoreSpecificDefaultLibraries>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)/$(TargetName).pdb</ProgramDatabaseFile>
+ <GenerateMapFile>false</GenerateMapFile>
+ <MapFileName>$(IntDir)/$(TargetName).map</MapFileName>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <BaseAddress> </BaseAddress>
+ <TargetMachine>MachineX86</TargetMachine>
+ <LinkErrorReporting>PromptImmediately</LinkErrorReporting>
+ <LinkLibraryDependencies>false</LinkLibraryDependencies>
+ </Link>
+ <Manifest>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </Manifest>
+ <Xdcmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ </Xdcmake>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>$(OutDir)/vvis_dll.bsc</OutputFile>
+ </Bscmake>
+ <PostBuildEvent>
+ <Message>Publishing to ..\..\..\game\bin</Message>
+ <Command>if not exist &quot;..\..\..\game\bin&quot; mkdir &quot;..\..\..\game\bin&quot;&#x0D;&#x0A;copy &quot;$(TargetDir)&quot;$(TargetFileName) &quot;..\..\..\game\bin\$(TargetFileName)&quot;&#x0D;&#x0A;if ERRORLEVEL 1 goto BuildEventFailed&#x0D;&#x0A;if exist &quot;$(TargetDir)&quot;$(TargetName).map copy &quot;$(TargetDir)&quot;$(TargetName).map ..\..\..\game\bin\$(TargetName).map&#x0D;&#x0A;copy &quot;$(TargetDir)&quot;$(TargetName).pdb ..\..\..\game\bin\$(TargetName).pdb&#x0D;&#x0A;if ERRORLEVEL 1 goto BuildEventFailed&#x0D;&#x0A;goto BuildEventOK&#x0D;&#x0A;:BuildEventFailed&#x0D;&#x0A;echo *** ERROR! PostBuildStep FAILED for $(ProjectName)! EXE or DLL is probably running. ***&#x0D;&#x0A;del /q &quot;$(TargetDir)&quot;$(TargetFileName)&#x0D;&#x0A;exit 1&#x0D;&#x0A;:BuildEventOK&#x0D;&#x0A;</Command>
+ </PostBuildEvent>
+ <CustomBuildStep>
+ </CustomBuildStep>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <Library Include="..\..\lib\public\mathlib.lib" />
+ <Library Include="..\..\lib\public\tier0.lib" />
+ <Library Include="..\..\lib\public\tier1.lib" />
+ <Library Include="..\..\lib\public\tier2.lib" />
+ <Library Include="..\..\lib\public\vmpi.lib" />
+ <Library Include="..\..\lib\public\vstdlib.lib" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\public\mathlib\amd3dx.h" />
+ <ClInclude Include="..\..\public\tier0\basetypes.h" />
+ <ClInclude Include="..\..\public\BSPFILE.H" />
+ <ClInclude Include="..\..\public\bspflags.h" />
+ <ClInclude Include="..\common\bsplib.h" />
+ <ClInclude Include="..\..\public\BSPTreeData.h" />
+ <ClInclude Include="..\..\public\mathlib\bumpvects.h" />
+ <ClInclude Include="..\..\public\tier1\byteswap.h" />
+ <ClInclude Include="..\..\public\tier1\checksum_crc.h" />
+ <ClInclude Include="..\..\public\tier1\checksum_md5.h" />
+ <ClInclude Include="..\common\cmdlib.h" />
+ <ClInclude Include="..\..\public\cmodel.h" />
+ <ClInclude Include="..\..\public\tier0\commonmacros.h" />
+ <ClInclude Include="..\..\public\GameBSPFile.h" />
+ <ClInclude Include="..\common\ISQLDBReplyTarget.h" />
+ <ClInclude Include="..\..\public\mathlib\mathlib.h" />
+ <ClInclude Include="mpivis.h" />
+ <ClInclude Include="..\common\MySqlDatabase.h" />
+ <ClInclude Include="..\common\pacifier.h" />
+ <ClInclude Include="..\common\scriplib.h" />
+ <ClInclude Include="..\..\public\tier1\strtools.h" />
+ <ClInclude Include="..\common\threads.h" />
+ <ClInclude Include="..\..\public\tier1\utlbuffer.h" />
+ <ClInclude Include="..\..\public\tier1\utllinkedlist.h" />
+ <ClInclude Include="..\..\public\tier1\utlmemory.h" />
+ <ClInclude Include="..\..\public\tier1\utlrbtree.h" />
+ <ClInclude Include="..\..\public\tier1\utlsymbol.h" />
+ <ClInclude Include="..\..\public\tier1\utlvector.h" />
+ <ClInclude Include="..\..\public\vcollide.h" />
+ <ClInclude Include="..\..\public\mathlib\vector.h" />
+ <ClInclude Include="..\..\public\mathlib\vector2d.h" />
+ <ClInclude Include="vis.h" />
+ <ClInclude Include="..\vmpi\vmpi_distribute_work.h" />
+ <ClInclude Include="..\common\vmpi_tools_shared.h" />
+ <ClInclude Include="..\..\public\vstdlib\vstdlib.h" />
+ <ClInclude Include="..\..\public\wadtypes.h" />
+ <ClInclude Include="..\common\tools_minidump.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\common\bsplib.cpp" />
+ <ClCompile Include="..\common\cmdlib.cpp" />
+ <ClCompile Include="..\..\public\collisionutils.cpp" />
+ <ClCompile Include="..\..\public\filesystem_helpers.cpp" />
+ <ClCompile Include="flow.cpp" />
+ <ClCompile Include="..\..\public\loadcmdline.cpp" />
+ <ClCompile Include="..\..\public\lumpfiles.cpp" />
+ <ClCompile Include="..\common\mpi_stats.cpp" />
+ <ClCompile Include="mpivis.cpp" />
+ <ClCompile Include="..\common\MySqlDatabase.cpp" />
+ <ClCompile Include="..\common\pacifier.cpp" />
+ <ClCompile Include="..\..\public\scratchpad3d.cpp" />
+ <ClCompile Include="..\common\scratchpad_helpers.cpp" />
+ <ClCompile Include="..\common\scriplib.cpp" />
+ <ClCompile Include="..\common\threads.cpp" />
+ <ClCompile Include="..\common\tools_minidump.cpp" />
+ <ClCompile Include="..\common\vmpi_tools_shared.cpp" />
+ <ClCompile Include="vvis.cpp" />
+ <ClCompile Include="WaterDist.cpp" />
+ <ClCompile Include="..\..\public\zip_utils.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="..\..\public\tier0\pointeroverride.asm">
+ <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compiling pointeroverride.asm</Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">&quot;$(VCInstallDir)bin\ml.exe&quot; /c /Cp /Zi /Fo&quot;$(IntDir)\%(Filename).obj&quot; &quot;%(FullPath)&quot;</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)\%(Filename).obj</Outputs>
+ <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compiling pointeroverride.asm</Message>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">&quot;$(VCInstallDir)bin\ml.exe&quot; /c /Cp /Zi /Fo&quot;$(IntDir)\%(Filename).obj&quot; &quot;%(FullPath)&quot;</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)\%(Filename).obj</Outputs>
+ </CustomBuild>
+ </ItemGroup>
+ <ItemGroup>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
diff --git a/mp/src/utils/vvis/vvis_dll-2010.vcxproj.filters b/mp/src/utils/vvis/vvis_dll-2010.vcxproj.filters
new file mode 100644
index 00000000..d25742b8
--- /dev/null
+++ b/mp/src/utils/vvis/vvis_dll-2010.vcxproj.filters
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{1680C80B-FF1E-EA4D-9817-CC12254F2E40}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Link Libraries">
+ <UniqueIdentifier>{C5D73B3A-C648-896C-B7CE-F174808E5BA5}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{BA03E055-4FA2-FCE3-8A1C-D348547D379C}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <Library Include="..\..\lib\public\mathlib.lib">
+ <Filter>Link Libraries</Filter>
+ </Library>
+ <Library Include="..\..\lib\public\tier0.lib">
+ <Filter>Link Libraries</Filter>
+ </Library>
+ <Library Include="..\..\lib\public\tier1.lib">
+ <Filter>Link Libraries</Filter>
+ </Library>
+ <Library Include="..\..\lib\public\tier2.lib">
+ <Filter>Link Libraries</Filter>
+ </Library>
+ <Library Include="..\..\lib\public\vmpi.lib">
+ <Filter>Link Libraries</Filter>
+ </Library>
+ <Library Include="..\..\lib\public\vstdlib.lib">
+ <Filter>Link Libraries</Filter>
+ </Library>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\public\mathlib\amd3dx.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\tier0\basetypes.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\BSPFILE.H">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\bspflags.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\common\bsplib.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\BSPTreeData.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\mathlib\bumpvects.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\tier1\byteswap.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\tier1\checksum_crc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\tier1\checksum_md5.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\common\cmdlib.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\cmodel.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\tier0\commonmacros.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\GameBSPFile.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\common\ISQLDBReplyTarget.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\mathlib\mathlib.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="mpivis.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\common\MySqlDatabase.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\common\pacifier.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\common\scriplib.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\tier1\strtools.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\common\threads.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\tier1\utlbuffer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\tier1\utllinkedlist.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\tier1\utlmemory.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\tier1\utlrbtree.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\tier1\utlsymbol.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\tier1\utlvector.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\vcollide.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\mathlib\vector.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\mathlib\vector2d.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="vis.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\vmpi\vmpi_distribute_work.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\common\vmpi_tools_shared.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\vstdlib\vstdlib.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\public\wadtypes.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\common\tools_minidump.h">
+ <Filter>Source Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\common\bsplib.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\common\cmdlib.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\public\collisionutils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\public\filesystem_helpers.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="flow.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\public\loadcmdline.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\public\lumpfiles.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\common\mpi_stats.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="mpivis.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\common\MySqlDatabase.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\common\pacifier.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\public\scratchpad3d.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\common\scratchpad_helpers.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\common\scriplib.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\common\threads.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\common\tools_minidump.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\common\vmpi_tools_shared.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="vvis.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="WaterDist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\public\zip_utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ </ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="..\..\public\tier0\pointeroverride.asm">
+ <Filter>Source Files</Filter>
+ </CustomBuild>
+ </ItemGroup>
+ <ItemGroup>
+ </ItemGroup>
+</Project>