#include "vis.h"
int32_t CountBits(byte *bits, int32_t numbits) {
int32_t i;
int32_t c;
c = 0;
for (i = 0; i < numbits; i++)
if (bits[i >> 3] & (1 << (i & 7)))
c++;
return c;
}
int32_t c_fullskip;
int32_t c_portalskip, c_leafskip;
int32_t c_vistest, c_mighttest;
int32_t c_chop, c_nochop;
int32_t active;
void CheckStack(leaf_t *leaf, threaddata_t *thread) {
pstack_t *p, *p2;
for (p = thread->pstack_head.next; p; p = p->next) {
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");
}
}
winding_t *AllocStackWinding(pstack_t *stack) {
int32_t 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) {
int32_t i;
i = w - stack->windings;
if (i < 0 || i > 2)
return;
if (stack->freewindings[i])
Error("FreeStackWinding: allready free");
stack->freewindings[i] = 1;
}
winding_t *ChopWinding_flow(winding_t *in, pstack_t *stack, plane_t *split) {
vec_t dists[128];
int32_t sides[128];
int32_t counts[3];
vec_t dot;
int32_t i, j;
vec_t *p1, *p2;
vec3_t mid;
winding_t *neww;
counts[0] = counts[1] = counts[2] = 0;
for (i = 0; i < in->numpoints; i++) {
dot = DotProduct(in->points[i], split->normal);
dot -= split->dist;
dists[i] = dot;
if (dot > ON_EPSILON)
sides[i] = SIDE_FRONT;
else if (dot < -ON_EPSILON)
sides[i] = SIDE_BACK;
else {
sides[i] = SIDE_ON;
}
counts[sides[i]]++;
}
if (!counts[1])
return in;
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++) {
p1 = in->points[i];
if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING) {
FreeStackWinding(neww, stack);
return in; }
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; }
p2 = in->points[(i + 1) % in->numpoints];
dot = dists[i] / (dists[i] - dists[i + 1]);
for (j = 0; j < 3; j++) { 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++;
}
FreeStackWinding(in, stack);
return neww;
}
winding_t *ClipToSeperators(winding_t *source, winding_t *pass, winding_t *target, qboolean flipclip, pstack_t *stack) {
int32_t i, j, k, l;
plane_t plane;
vec3_t v1, v2;
float d;
vec_t length;
int32_t counts[3];
qboolean fliptest;
for (i = 0; i < source->numpoints; i++) {
l = (i + 1) % source->numpoints;
VectorSubtract(source->points[l], source->points[i], v1);
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];
length = plane.normal[0] * plane.normal[0] + plane.normal[1] * plane.normal[1] + plane.normal[2] * plane.normal[2];
if (length < ON_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);
#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_EPSILON) { fliptest = false;
break;
} else if (d > ON_EPSILON) { fliptest = true;
break;
}
}
if (k == source->numpoints)
continue; #else#endif
if (fliptest) {
VectorSubtract(vec3_origin, plane.normal, plane.normal);
plane.dist = -plane.dist;
}
#if 1
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_EPSILON)
break;
else if (d > ON_EPSILON)
counts[0]++;
else
counts[2]++;
}
if (k != pass->numpoints)
continue;
if (!counts[0])
continue; #else#endif
if (flipclip) {
VectorSubtract(vec3_origin, plane.normal, plane.normal);
plane.dist = -plane.dist;
}
target = ChopWinding_flow(target, stack, &plane);
if (!target)
return NULL; }
}
return target;
}
void RecursiveLeafFlow(int32_t leafnum, threaddata_t *thread, pstack_t *prevstack) {
pstack_t stack;
portal_t *p;
plane_t backplane;
leaf_t *leaf;
int32_t i, j;
long *test, *might, *vis, more;
int32_t pnum;
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;
for (i = 0; i < leaf->numportals; i++) {
p = leaf->portals[i];
pnum = p - portals;
if (!(prevstack->mightsee[pnum >> 3] & (1 << (pnum & 7)))) {
continue; }
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 &&
(thread->base->portalvis[pnum >> 3] & (1 << (pnum & 7)))) { continue;
}
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;
#if 1
{
float d;
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_flow(p->winding, &stack, &thread->pstack_head.portalplane);
if (!stack.pass)
continue;
}
}
#else#endif
#if 1
{
float d;
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_flow(prevstack->source, &stack, &backplane);
if (!stack.source)
continue;
}
}
#else#endif
if (!prevstack->pass) {
thread->base->portalvis[pnum >> 3] |= (1 << (pnum & 7));
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;
thread->base->portalvis[pnum >> 3] |= (1 << (pnum & 7));
RecursiveLeafFlow(p->leaf, thread, &stack);
}
}
void PortalFlow(int32_t portalnum) {
threaddata_t data;
int32_t i;
portal_t *p;
int32_t c_might, c_can;
p = sorted_portals[portalnum];
p->status = stat_working;
c_might = CountBits(p->portalflood, 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, numportals * 2);
qprintf("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n",
(int32_t)(p - portals), c_might, c_can, data.c_chains);
}
int32_t c_flood, c_vis;
char test_leaf[MAX_MAP_LEAFS_QBSP];
void SimpleFlood(portal_t *srcportal, int32_t leafnum) {
int32_t i;
leaf_t *leaf;
portal_t *p;
int32_t pnum;
leaf = &leafs[leafnum];
for (i = 0; i < leaf->numportals; i++) {
p = leaf->portals[i];
pnum = p - portals;
if (!(srcportal->portalfront[pnum >> 3] & (1 << (pnum & 7))))
continue;
if (srcportal->portalflood[pnum >> 3] & (1 << (pnum & 7)))
continue;
srcportal->portalflood[pnum >> 3] |= (1 << (pnum & 7));
SimpleFlood(srcportal, p->leaf);
}
}
void BasePortalVis(int32_t portalnum) {
int32_t j, k;
portal_t *tp, *p;
float d;
winding_t *w;
p = portals + portalnum;
p->portalfront = malloc(portalbytes);
memset(p->portalfront, 0, portalbytes);
p->portalflood = malloc(portalbytes);
memset(p->portalflood, 0, portalbytes);
p->portalvis = malloc(portalbytes);
memset(p->portalvis, 0, portalbytes);
for (j = 0, tp = portals; j < numportals * 2; j++, tp++) {
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_EPSILON)
break;
}
if (k == w->numpoints)
continue;
w = p->winding;
for (k = 0; k < w->numpoints; k++) {
d = DotProduct(w->points[k], tp->plane.normal) - tp->plane.dist;
if (d < -ON_EPSILON)
break;
}
if (k == w->numpoints)
continue;
p->portalfront[j >> 3] |= (1 << (j & 7));
}
SimpleFlood(p, p->leaf);
p->nummightsee = CountBits(p->portalflood, numportals * 2);
c_flood += p->nummightsee;
}
void RecursiveLeafBitFlow(int32_t leafnum, byte *mightsee, byte *cansee) {
portal_t *p;
leaf_t *leaf;
int32_t i, j;
long more;
int32_t pnum;
byte newmight[MAX_MAP_PORTALS_QBSP / 8];
leaf = &leafs[leafnum];
for (i = 0; i < leaf->numportals; i++) {
p = leaf->portals[i];
pnum = p - portals;
if (!(mightsee[pnum >> 3] & (1 << (pnum & 7))))
continue;
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;
cansee[pnum >> 3] |= (1 << (pnum & 7));
RecursiveLeafBitFlow(p->leaf, newmight, cansee);
}
}
void BetterPortalVis(int32_t portalnum) {
portal_t *p;
p = portals + portalnum;
RecursiveLeafBitFlow(p->leaf, p->portalflood, p->portalvis);
p->nummightsee = CountBits(p->portalvis, numportals * 2);
c_vis += p->nummightsee;
}