// ===================================================================================== // 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 the target argument is NULL, then a list of clipping planes is built in // stack instead. // 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. // ===================================================================================== inline static winding_t* ClipToSeperators( const winding_t* const source, const winding_t* const pass, winding_t* const a_target, const bool flipclip, pstack_t* const stack) { int i, j, k, l; plane_t plane; vec3_t v1, v2; float d; int counts[3]; bool fliptest; winding_t* target = a_target; const unsigned int numpoints = source->numpoints; // check all combinations for (i=0, l=1; i < numpoints; i++, l++) { if (l == numpoints) { l = 0; } 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); CrossProduct(v1, v2, plane.normal); if (VectorNormalize(plane.normal) < ON_EPSILON) { continue; } plane.dist = DotProduct(pass->points[j], plane.normal); // find out which side of the generated seperating plane has the // source portal fliptest = false; for (k = 0; k < numpoints; k++) { if ((k == i) | (k == l)) // | instead of || for branch optimization { continue; } d = DotProduct(source->points[k], plane.normal) - plane.dist; if (d < -ON_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_EPSILON) { // source is on the positive side, so we want all // pass and target on the negative side fliptest = true; break; } } if (k == numpoints) { continue; // planar with source portal } // flip the normal if the source portal is backwards if (fliptest) { VectorSubtract(vec3_origin, plane.normal, plane.normal); plane.dist = -plane.dist; } // 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_EPSILON) { break; } else if (d > ON_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 } // flip the normal if we want the back side if (flipclip) { VectorSubtract(vec3_origin, plane.normal, plane.normal); plane.dist = -plane.dist; } if (target != NULL) { // clip target by the seperating plane target = ChopWinding(target, stack, &plane); if (!target) { return NULL; // target is not visible } } else { AddPlane(stack, &plane); } #ifdef RVIS_LEVEL_1 break; /* Antony was here */ #endif } } return target; }
// ===================================================================================== // RecursiveLeafFlow // Flood fill through the leafs // If src_portal is NULL, this is the originating leaf // ===================================================================================== inline static void RecursiveLeafFlow(const int leafnum, const threaddata_t* const thread, const pstack_t* const prevstack) { pstack_t stack; leaf_t* leaf; leaf = &g_leafs[leafnum]; #ifdef USE_CHECK_STACK CheckStack(leaf, thread); #endif { const unsigned offset = leafnum >> 3; const unsigned bit = (1 << (leafnum & 7)); // mark the leaf as visible if (!(thread->leafvis[offset] & bit)) { thread->leafvis[offset] |= bit; thread->base->numcansee++; } } #ifdef USE_CHECK_STACK prevstack->next = &stack; stack.next = NULL; #endif stack.head = prevstack->head; stack.leaf = leaf; stack.portal = NULL; #ifdef RVIS_LEVEL_2 stack.clipPlaneCount = -1; stack.clipPlane = NULL; #endif // check all portals for flowing into other leafs unsigned i; portal_t** plist = leaf->portals; for (i = 0; i < leaf->numportals; i++, plist++) { portal_t* p = *plist; #if ZHLT_ZONES portal_t * head_p = stack.head->portal; if (g_Zones->check(head_p->zone, p->zone)) { continue; } #endif { const unsigned offset = p->leaf >> 3; const unsigned bit = 1 << (p->leaf & 7); if (!(stack.head->mightsee[offset] & bit)) { continue; // can't possibly see it } if (!(prevstack->mightsee[offset] & bit)) { continue; // can't possibly see it } } // if the portal can't see anything we haven't allready seen, skip it { long* test; if (p->status == stat_done) { test = (long*)p->visbits; } else { test = (long*)p->mightsee; } { const int bitlongs = g_bitlongs; { long* prevmight = (long*)prevstack->mightsee; long* might = (long*)stack.mightsee; unsigned j; for (j = 0; j < bitlongs; j++, test++, might++, prevmight++) { (*might) = (*prevmight) & (*test); } } { long* might = (long*)stack.mightsee; long* vis = (long*)thread->leafvis; unsigned j; for (j = 0; j < bitlongs; j++, might++, vis++) { if ((*might) & ~(*vis)) { break; } } if (j == g_bitlongs) { // can't see anything new continue; } } } } // get plane of portal, point normal into the neighbor leaf stack.portalplane = &p->plane; plane_t backplane; VectorSubtract(vec3_origin, p->plane.normal, backplane.normal); backplane.dist = -p->plane.dist; if (VectorCompare(prevstack->portalplane->normal, backplane.normal)) { continue; // can't go out a coplanar face } stack.portal = p; #ifdef USE_CHECK_STACK stack.next = NULL; #endif stack.freewindings[0] = 1; stack.freewindings[1] = 1; stack.freewindings[2] = 1; stack.pass = ChopWinding(p->winding, &stack, thread->pstack_head.portalplane); if (!stack.pass) { continue; } stack.source = ChopWinding(prevstack->source, &stack, &backplane); if (!stack.source) { continue; } if (!prevstack->pass) { // the second leaf can only be blocked if coplanar RecursiveLeafFlow(p->leaf, thread, &stack); continue; } stack.pass = ChopWinding(stack.pass, &stack, prevstack->portalplane); if (!stack.pass) { continue; } #ifdef RVIS_LEVEL_2 if (stack.clipPlaneCount == -1) { stack.clipPlaneCount = 0; stack.clipPlane = (plane_t*)alloca(sizeof(plane_t) * prevstack->source->numpoints * prevstack->pass->numpoints); ClipToSeperators(prevstack->source, prevstack->pass, NULL, false, &stack); ClipToSeperators(prevstack->pass, prevstack->source, NULL, true, &stack); } if (stack.clipPlaneCount > 0) { unsigned j; for (j = 0; j < stack.clipPlaneCount && stack.pass != NULL; j++) { stack.pass = ChopWinding(stack.pass, &stack, &(stack.clipPlane[j])); } if (stack.pass == NULL) continue; } #else 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; } #endif if (g_fullvis) { stack.source = ClipToSeperators(stack.pass, prevstack->pass, stack.source, false, &stack); if (!stack.source) { continue; } stack.source = ClipToSeperators(prevstack->pass, stack.pass, stack.source, true, &stack); if (!stack.source) { continue; } } // flow through it for real RecursiveLeafFlow(p->leaf, thread, &stack); } #ifdef RVIS_LEVEL_2 #if 0 if (stack.clipPlane != NULL) { free(stack.clipPlane); } #endif #endif }
/* =========== MakeHullFaces =========== */ void MakeHullFaces (brush_t *b, brushhull_t *h) { bface_t *f, *f2; winding_t *w; plane_t *p; int i, j; vec_t v; vec_t area; restart: h->mins[0] = h->mins[1] = h->mins[2] = 9999; h->maxs[0] = h->maxs[1] = h->maxs[2] = -9999; for (f = h->faces ; f ; f=f->next) { // w = BaseWindingForIPlane (f->plane); w = BaseWindingForPlane (f->plane->normal, f->plane->dist); for (f2 = h->faces ; f2 && w ; f2=f2->next) { if (f == f2) continue; p = &mapplanes[f2->planenum ^ 1]; w = ChopWinding (w, p->normal, p->dist); } area = w ? WindingArea(w) : 0; if (area < 0.1) { qprintf ("Entity %i, Brush %i: plane with area %4.2f\n" , b->entitynum, b->brushnum, area); // remove the face and regenerate the hull if (h->faces == f) h->faces = f->next; else { for (f2=h->faces ; f2->next != f ; f2=f2->next) ; f2->next = f->next; } goto restart; } f->w = w; f->contents = CONTENTS_EMPTY; if (w) { for (i=0 ; i<w->numpoints ; i++) { for (j=0 ; j<3 ; j++) { v = w->p[i][j]; // w->p[i][j] = floor (v+0.5); // round to int if (v<h->mins[j]) h->mins[j] = v; if (v>h->maxs[j]) h->maxs[j] = v; } } } } for (i=0 ; i<3 ; i++) { if (h->mins[i] < -BOGUS_RANGE/2 || h->maxs[i] > BOGUS_RANGE/2) { vec3_t eorigin = { 0, 0, 0}; char *pszClass = "Unknown Class"; if ( b->entitynum ) { entity_t *e = entities + b->entitynum; pszClass = ValueForKey(e, "classname" ); GetVectorForKey( e, "origin", eorigin ); } printf( "Entity %i, Brush %i: A '%s' @(%.0f,%.0f,%.0f)\n", b->entitynum, b->brushnum, pszClass, eorigin[0], eorigin[1], eorigin[2] ); printf( "\toutside world(+/-%d): (%.0f, %.0f, %.0f)-(%.0f,%.0f,%.0f)\n", BOGUS_RANGE/2, h->mins[0], h->mins[1], h->mins[2], h->maxs[0], h->maxs[1], h->maxs[2] ); break; } } }