📄 flow.cpp
字号:
#include "vis.h"
#include "vmpi.h"
/*
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 ("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;
}
/*
==================
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;
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -