Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

visflow.c (36073B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 #include "vis.h"
     23 
     24 /*
     25 
     26   each portal will have a list of all possible to see from first portal
     27 
     28   if (!thread->portalmightsee[portalnum])
     29 
     30   portal mightsee
     31 
     32   for p2 = all other portals in leaf
     33 	get sperating planes
     34 	for all portals that might be seen by p2
     35 		mark as unseen if not present in seperating plane
     36 	flood fill a new mightsee
     37 	save as passagemightsee
     38 
     39 
     40   void CalcMightSee (leaf_t *leaf, 
     41 */
     42 
     43 int CountBits (byte *bits, int numbits)
     44 {
     45 	int		i;
     46 	int		c;
     47 
     48 	c = 0;
     49 	for (i=0 ; i<numbits ; i++)
     50 		if (bits[i>>3] & (1<<(i&7)) )
     51 			c++;
     52 
     53 	return c;
     54 }
     55 
     56 int		c_fullskip;
     57 int		c_portalskip, c_leafskip;
     58 int		c_vistest, c_mighttest;
     59 
     60 int		c_chop, c_nochop;
     61 
     62 int		active;
     63 
     64 void CheckStack (leaf_t *leaf, threaddata_t *thread)
     65 {
     66 	pstack_t	*p, *p2;
     67 
     68 	for (p=thread->pstack_head.next ; p ; p=p->next)
     69 	{
     70 //		_printf ("=");
     71 		if (p->leaf == leaf)
     72 			Error ("CheckStack: leaf recursion");
     73 		for (p2=thread->pstack_head.next ; p2 != p ; p2=p2->next)
     74 			if (p2->leaf == p->leaf)
     75 				Error ("CheckStack: late leaf recursion");
     76 	}
     77 //	_printf ("\n");
     78 }
     79 
     80 
     81 winding_t *AllocStackWinding (pstack_t *stack)
     82 {
     83 	int		i;
     84 
     85 	for (i=0 ; i<3 ; i++)
     86 	{
     87 		if (stack->freewindings[i])
     88 		{
     89 			stack->freewindings[i] = 0;
     90 			return &stack->windings[i];
     91 		}
     92 	}
     93 
     94 	Error ("AllocStackWinding: failed");
     95 
     96 	return NULL;
     97 }
     98 
     99 void FreeStackWinding (winding_t *w, pstack_t *stack)
    100 {
    101 	int		i;
    102 
    103 	i = w - stack->windings;
    104 
    105 	if (i<0 || i>2)
    106 		return;		// not from local
    107 
    108 	if (stack->freewindings[i])
    109 		Error ("FreeStackWinding: allready free");
    110 	stack->freewindings[i] = 1;
    111 }
    112 
    113 /*
    114 ==============
    115 VisChopWinding
    116 
    117 ==============
    118 */
    119 winding_t	*VisChopWinding (winding_t *in, pstack_t *stack, plane_t *split)
    120 {
    121 	vec_t	dists[128];
    122 	int		sides[128];
    123 	int		counts[3];
    124 	vec_t	dot;
    125 	int		i, j;
    126 	vec_t	*p1, *p2;
    127 	vec3_t	mid;
    128 	winding_t	*neww;
    129 
    130 	counts[0] = counts[1] = counts[2] = 0;
    131 
    132 	// determine sides for each point
    133 	for (i=0 ; i<in->numpoints ; i++)
    134 	{
    135 		dot = DotProduct (in->points[i], split->normal);
    136 		dot -= split->dist;
    137 		dists[i] = dot;
    138 		if (dot > ON_EPSILON)
    139 			sides[i] = SIDE_FRONT;
    140 		else if (dot < -ON_EPSILON)
    141 			sides[i] = SIDE_BACK;
    142 		else
    143 		{
    144 			sides[i] = SIDE_ON;
    145 		}
    146 		counts[sides[i]]++;
    147 	}
    148 
    149 	if (!counts[1])
    150 		return in;		// completely on front side
    151 	
    152 	if (!counts[0])
    153 	{
    154 		FreeStackWinding (in, stack);
    155 		return NULL;
    156 	}
    157 
    158 	sides[i] = sides[0];
    159 	dists[i] = dists[0];
    160 	
    161 	neww = AllocStackWinding (stack);
    162 
    163 	neww->numpoints = 0;
    164 
    165 	for (i=0 ; i<in->numpoints ; i++)
    166 	{
    167 		p1 = in->points[i];
    168 
    169 		if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
    170 		{
    171 			FreeStackWinding (neww, stack);
    172 			return in;		// can't chop -- fall back to original
    173 		}
    174 
    175 		if (sides[i] == SIDE_ON)
    176 		{
    177 			VectorCopy (p1, neww->points[neww->numpoints]);
    178 			neww->numpoints++;
    179 			continue;
    180 		}
    181 	
    182 		if (sides[i] == SIDE_FRONT)
    183 		{
    184 			VectorCopy (p1, neww->points[neww->numpoints]);
    185 			neww->numpoints++;
    186 		}
    187 		
    188 		if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
    189 			continue;
    190 			
    191 		if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
    192 		{
    193 			FreeStackWinding (neww, stack);
    194 			return in;		// can't chop -- fall back to original
    195 		}
    196 
    197 		// generate a split point
    198 		p2 = in->points[(i+1)%in->numpoints];
    199 		
    200 		dot = dists[i] / (dists[i]-dists[i+1]);
    201 		for (j=0 ; j<3 ; j++)
    202 		{	// avoid round off error when possible
    203 			if (split->normal[j] == 1)
    204 				mid[j] = split->dist;
    205 			else if (split->normal[j] == -1)
    206 				mid[j] = -split->dist;
    207 			else
    208 				mid[j] = p1[j] + dot*(p2[j]-p1[j]);
    209 		}
    210 			
    211 		VectorCopy (mid, neww->points[neww->numpoints]);
    212 		neww->numpoints++;
    213 	}
    214 	
    215 	// free the original winding
    216 	FreeStackWinding (in, stack);
    217 	
    218 	return neww;
    219 }
    220 
    221 /*
    222 ==============
    223 ClipToSeperators
    224 
    225 Source, pass, and target are an ordering of portals.
    226 
    227 Generates seperating planes canidates by taking two points from source and one
    228 point from pass, and clips target by them.
    229 
    230 If target is totally clipped away, that portal can not be seen through.
    231 
    232 Normal clip keeps target on the same side as pass, which is correct if the
    233 order goes source, pass, target.  If the order goes pass, source, target then
    234 flipclip should be set.
    235 ==============
    236 */
    237 winding_t	*ClipToSeperators (winding_t *source, winding_t *pass, winding_t *target, qboolean flipclip, pstack_t *stack)
    238 {
    239 	int			i, j, k, l;
    240 	plane_t		plane;
    241 	vec3_t		v1, v2;
    242 	float		d;
    243 	vec_t		length;
    244 	int			counts[3];
    245 	qboolean		fliptest;
    246 
    247 	// check all combinations	
    248 	for (i=0 ; i<source->numpoints ; i++)
    249 	{
    250 		l = (i+1)%source->numpoints;
    251 		VectorSubtract (source->points[l] , source->points[i], v1);
    252 
    253 		// find a vertex of pass that makes a plane that puts all of the
    254 		// vertexes of pass on the front side and all of the vertexes of
    255 		// source on the back side
    256 		for (j=0 ; j<pass->numpoints ; j++)
    257 		{
    258 			VectorSubtract (pass->points[j], source->points[i], v2);
    259 
    260 			plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
    261 			plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
    262 			plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
    263 			
    264 			// if points don't make a valid plane, skip it
    265 
    266 			length = plane.normal[0] * plane.normal[0]
    267 			+ plane.normal[1] * plane.normal[1]
    268 			+ plane.normal[2] * plane.normal[2];
    269 			
    270 			if (length < ON_EPSILON)
    271 				continue;
    272 
    273 			length = 1/sqrt(length);
    274 			
    275 			plane.normal[0] *= length;
    276 			plane.normal[1] *= length;
    277 			plane.normal[2] *= length;
    278 
    279 			plane.dist = DotProduct (pass->points[j], plane.normal);
    280 
    281 			//
    282 			// find out which side of the generated seperating plane has the
    283 			// source portal
    284 			//
    285 #if 1
    286 			fliptest = qfalse;
    287 			for (k=0 ; k<source->numpoints ; k++)
    288 			{
    289 				if (k == i || k == l)
    290 					continue;
    291 				d = DotProduct (source->points[k], plane.normal) - plane.dist;
    292 				if (d < -ON_EPSILON)
    293 				{	// source is on the negative side, so we want all
    294 					// pass and target on the positive side
    295 					fliptest = qfalse;
    296 					break;
    297 				}
    298 				else if (d > ON_EPSILON)
    299 				{	// source is on the positive side, so we want all
    300 					// pass and target on the negative side
    301 					fliptest = qtrue;
    302 					break;
    303 				}
    304 			}
    305 			if (k == source->numpoints)
    306 				continue;		// planar with source portal
    307 #else
    308 			fliptest = flipclip;
    309 #endif
    310 			//
    311 			// flip the normal if the source portal is backwards
    312 			//
    313 			if (fliptest)
    314 			{
    315 				VectorSubtract (vec3_origin, plane.normal, plane.normal);
    316 				plane.dist = -plane.dist;
    317 			}
    318 #if 1
    319 			//
    320 			// if all of the pass portal points are now on the positive side,
    321 			// this is the seperating plane
    322 			//
    323 			counts[0] = counts[1] = counts[2] = 0;
    324 			for (k=0 ; k<pass->numpoints ; k++)
    325 			{
    326 				if (k==j)
    327 					continue;
    328 				d = DotProduct (pass->points[k], plane.normal) - plane.dist;
    329 				if (d < -ON_EPSILON)
    330 					break;
    331 				else if (d > ON_EPSILON)
    332 					counts[0]++;
    333 				else
    334 					counts[2]++;
    335 			}
    336 			if (k != pass->numpoints)
    337 				continue;	// points on negative side, not a seperating plane
    338 				
    339 			if (!counts[0])
    340 				continue;	// planar with seperating plane
    341 #else
    342 			k = (j+1)%pass->numpoints;
    343 			d = DotProduct (pass->points[k], plane.normal) - plane.dist;
    344 			if (d < -ON_EPSILON)
    345 				continue;
    346 			k = (j+pass->numpoints-1)%pass->numpoints;
    347 			d = DotProduct (pass->points[k], plane.normal) - plane.dist;
    348 			if (d < -ON_EPSILON)
    349 				continue;			
    350 #endif
    351 			//
    352 			// flip the normal if we want the back side
    353 			//
    354 			if (flipclip)
    355 			{
    356 				VectorSubtract (vec3_origin, plane.normal, plane.normal);
    357 				plane.dist = -plane.dist;
    358 			}
    359 
    360 #ifdef SEPERATORCACHE
    361 			stack->seperators[flipclip][stack->numseperators[flipclip]] = plane;
    362 			if (++stack->numseperators[flipclip] >= MAX_SEPERATORS)
    363 				Error("MAX_SEPERATORS");
    364 #endif
    365 			//MrE: fast check first
    366 			d = DotProduct (stack->portal->origin, plane.normal) - plane.dist;
    367 			//if completely at the back of the seperator plane
    368 			if (d < -stack->portal->radius)
    369 				return NULL;
    370 			//if completely on the front of the seperator plane
    371 			if (d > stack->portal->radius)
    372 				break;
    373 
    374 			//
    375 			// clip target by the seperating plane
    376 			//
    377 			target = VisChopWinding (target, stack, &plane);
    378 			if (!target)
    379 				return NULL;		// target is not visible
    380 
    381 			break;		// optimization by Antony Suter
    382 		}
    383 	}
    384 	
    385 	return target;
    386 }
    387 
    388 /*
    389 ==================
    390 RecursiveLeafFlow
    391 
    392 Flood fill through the leafs
    393 If src_portal is NULL, this is the originating leaf
    394 ==================
    395 */
    396 void RecursiveLeafFlow (int leafnum, threaddata_t *thread, pstack_t *prevstack)
    397 {
    398 	pstack_t	stack;
    399 	vportal_t	*p;
    400 	plane_t		backplane;
    401 	leaf_t 		*leaf;
    402 	int			i, j, n;
    403 	long		*test, *might, *prevmight, *vis, more;
    404 	int			pnum;
    405 
    406 	thread->c_chains++;
    407 
    408 	leaf = &leafs[leafnum];
    409 //	CheckStack (leaf, thread);
    410 
    411 	prevstack->next = &stack;
    412 
    413 	stack.next = NULL;
    414 	stack.leaf = leaf;
    415 	stack.portal = NULL;
    416 	stack.depth = prevstack->depth + 1;
    417 
    418 #ifdef SEPERATORCACHE
    419 	stack.numseperators[0] = 0;
    420 	stack.numseperators[1] = 0;
    421 #endif
    422 
    423 	might = (long *)stack.mightsee;
    424 	vis = (long *)thread->base->portalvis;
    425 	
    426 	// check all portals for flowing into other leafs	
    427 	for (i = 0; i < leaf->numportals; i++)
    428 	{
    429 		p = leaf->portals[i];
    430 		if (p->removed)
    431 			continue;
    432 		pnum = p - portals;
    433 
    434 		/* MrE: portal trace debug code
    435 		{
    436 			int portaltrace[] = {13, 16, 17, 37};
    437 			pstack_t *s;
    438 
    439 			s = &thread->pstack_head;
    440 			for (j = 0; s->next && j < sizeof(portaltrace)/sizeof(int) - 1; j++, s = s->next)
    441 			{
    442 				if (s->portal->num != portaltrace[j])
    443 					break;
    444 			}
    445 			if (j >= sizeof(portaltrace)/sizeof(int) - 1)
    446 			{
    447 				if (p->num == portaltrace[j])
    448 					n = 0; //traced through all the portals
    449 			}
    450 		}
    451 		*/
    452 
    453 		if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) )
    454 		{
    455 			continue;	// can't possibly see it
    456 		}
    457 
    458 		// if the portal can't see anything we haven't allready seen, skip it
    459 		if (p->status == stat_done)
    460 		{
    461 			test = (long *)p->portalvis;
    462 		}
    463 		else
    464 		{
    465 			test = (long *)p->portalflood;
    466 		}
    467 
    468 		more = 0;
    469 		prevmight = (long *)prevstack->mightsee;
    470 		for (j=0 ; j<portallongs ; j++)
    471 		{
    472 			might[j] = prevmight[j] & test[j];
    473 			more |= (might[j] & ~vis[j]);
    474 		}
    475 		
    476 		if (!more && 
    477 			(thread->base->portalvis[pnum>>3] & (1<<(pnum&7))) )
    478 		{	// can't see anything new
    479 			continue;
    480 		}
    481 
    482 		// get plane of portal, point normal into the neighbor leaf
    483 		stack.portalplane = p->plane;
    484 		VectorSubtract (vec3_origin, p->plane.normal, backplane.normal);
    485 		backplane.dist = -p->plane.dist;
    486 		
    487 //		c_portalcheck++;
    488 		
    489 		stack.portal = p;
    490 		stack.next = NULL;
    491 		stack.freewindings[0] = 1;
    492 		stack.freewindings[1] = 1;
    493 		stack.freewindings[2] = 1;
    494 		
    495 #if 1
    496 		{
    497 			float d;
    498 
    499 			d = DotProduct (p->origin, thread->pstack_head.portalplane.normal);
    500 			d -= thread->pstack_head.portalplane.dist;
    501 			if (d < -p->radius)
    502 			{
    503 				continue;
    504 			}
    505 			else if (d > p->radius)
    506 			{
    507 				stack.pass = p->winding;
    508 			}
    509 			else	
    510 			{
    511 				stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
    512 				if (!stack.pass)
    513 					continue;
    514 			}
    515 		}
    516 #else
    517 		stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
    518 		if (!stack.pass)
    519 			continue;
    520 #endif
    521 
    522 	
    523 #if 1
    524 		{
    525 			float d;
    526 
    527 			d = DotProduct (thread->base->origin, p->plane.normal);
    528 			d -= p->plane.dist;
    529 			//MrE: vis-bug fix
    530 			//if (d > p->radius)
    531 			if (d > thread->base->radius)
    532 			{
    533 				continue;
    534 			}
    535 			//MrE: vis-bug fix
    536 			//if (d < -p->radius)
    537 			else if (d < -thread->base->radius)
    538 			{
    539 				stack.source = prevstack->source;
    540 			}
    541 			else	
    542 			{
    543 				stack.source = VisChopWinding (prevstack->source, &stack, &backplane);
    544 				//FIXME: shouldn't we create a new source origin and radius for fast checks?
    545 				if (!stack.source)
    546 					continue;
    547 			}
    548 		}
    549 #else
    550 		stack.source = VisChopWinding (prevstack->source, &stack, &backplane);
    551 		if (!stack.source)
    552 			continue;
    553 #endif
    554 
    555 		if (!prevstack->pass)
    556 		{	// the second leaf can only be blocked if coplanar
    557 
    558 			// mark the portal as visible
    559 			thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
    560 
    561 			RecursiveLeafFlow (p->leaf, thread, &stack);
    562 			continue;
    563 		}
    564 
    565 #ifdef SEPERATORCACHE
    566 		if (stack.numseperators[0])
    567 		{
    568 			for (n = 0; n < stack.numseperators[0]; n++)
    569 			{
    570 				stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[0][n]);
    571 				if (!stack.pass)
    572 					break;		// target is not visible
    573 			}
    574 			if (n < stack.numseperators[0])
    575 				continue;
    576 		}
    577 		else
    578 		{
    579 			stack.pass = ClipToSeperators (prevstack->source, prevstack->pass, stack.pass, qfalse, &stack);
    580 		}
    581 #else
    582 		stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, qfalse, &stack);
    583 #endif
    584 		if (!stack.pass)
    585 			continue;
    586 
    587 #ifdef SEPERATORCACHE
    588 		if (stack.numseperators[1])
    589 		{
    590 			for (n = 0; n < stack.numseperators[1]; n++)
    591 			{
    592 				stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[1][n]);
    593 				if (!stack.pass)
    594 					break;		// target is not visible
    595 			}
    596 		}
    597 		else
    598 		{
    599 			stack.pass = ClipToSeperators (prevstack->pass, prevstack->source, stack.pass, qtrue, &stack);
    600 		}
    601 #else
    602 		stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, qtrue, &stack);
    603 #endif
    604 		if (!stack.pass)
    605 			continue;
    606 
    607 		// mark the portal as visible
    608 		thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
    609 
    610 		// flow through it for real
    611 		RecursiveLeafFlow (p->leaf, thread, &stack);
    612 		//
    613 		stack.next = NULL;
    614 	}	
    615 }
    616 
    617 /*
    618 ===============
    619 PortalFlow
    620 
    621 generates the portalvis bit vector
    622 ===============
    623 */
    624 void PortalFlow (int portalnum)
    625 {
    626 	threaddata_t	data;
    627 	int				i;
    628 	vportal_t		*p;
    629 	int				c_might, c_can;
    630 
    631 #ifdef MREDEBUG
    632 	_printf("\r%6d", portalnum);
    633 #endif
    634 
    635 	p = sorted_portals[portalnum];
    636 
    637 	if (p->removed)
    638 	{
    639 		p->status = stat_done;
    640 		return;
    641 	}
    642 
    643 	p->status = stat_working;
    644 
    645 	c_might = CountBits (p->portalflood, numportals*2);
    646 
    647 	memset (&data, 0, sizeof(data));
    648 	data.base = p;
    649 	
    650 	data.pstack_head.portal = p;
    651 	data.pstack_head.source = p->winding;
    652 	data.pstack_head.portalplane = p->plane;
    653 	data.pstack_head.depth = 0;
    654 	for (i=0 ; i<portallongs ; i++)
    655 		((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i];
    656 
    657 	RecursiveLeafFlow (p->leaf, &data, &data.pstack_head);
    658 
    659 	p->status = stat_done;
    660 
    661 	c_can = CountBits (p->portalvis, numportals*2);
    662 
    663 	qprintf ("portal:%4i  mightsee:%4i  cansee:%4i (%i chains)\n", 
    664 		(int)(p - portals),	c_might, c_can, data.c_chains);
    665 }
    666 
    667 /*
    668 ==================
    669 RecursivePassageFlow
    670 ==================
    671 */
    672 void RecursivePassageFlow (vportal_t *portal, threaddata_t *thread, pstack_t *prevstack)
    673 {
    674 	pstack_t	stack;
    675 	vportal_t	*p;
    676 	leaf_t 		*leaf;
    677 	passage_t	*passage, *nextpassage;
    678 	int			i, j;
    679 	long		*might, *vis, *prevmight, *cansee, *portalvis, more;
    680 	int			pnum;
    681 
    682 	leaf = &leafs[portal->leaf];
    683 
    684 	prevstack->next = &stack;
    685 
    686 	stack.next = NULL;
    687 	stack.depth = prevstack->depth + 1;
    688 
    689 	vis = (long *)thread->base->portalvis;
    690 
    691 	passage = portal->passages;
    692 	nextpassage = passage;
    693 	// check all portals for flowing into other leafs	
    694 	for (i = 0; i < leaf->numportals; i++, passage = nextpassage)
    695 	{
    696 		p = leaf->portals[i];
    697 		if ( p->removed ) {
    698 			continue;
    699 		}
    700 		nextpassage = passage->next;
    701 		pnum = p - portals;
    702 
    703 		if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) ) {
    704 			continue;	// can't possibly see it
    705 		}
    706 
    707 		// mark the portal as visible
    708 		thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
    709 
    710 		prevmight = (long *)prevstack->mightsee;
    711 		cansee = (long *)passage->cansee;
    712 		might = (long *)stack.mightsee;
    713 		memcpy(might, prevmight, portalbytes);
    714 		if (p->status == stat_done)
    715 			portalvis = (long *) p->portalvis;
    716 		else
    717 			portalvis = (long *) p->portalflood;
    718 		more = 0;
    719 		for (j = 0; j < portallongs; j++)
    720 		{
    721 			if (*might)
    722 			{
    723 				*might &= *cansee++ & *portalvis++;
    724 				more |= (*might & ~vis[j]);
    725 			}
    726 			else
    727 			{
    728 				cansee++;
    729 				portalvis++;
    730 			}
    731 			might++;
    732 		}
    733 
    734 		if ( !more ) {
    735 			// can't see anything new
    736 			continue;
    737 		}
    738 
    739 		// flow through it for real
    740 		RecursivePassageFlow(p, thread, &stack);
    741 
    742 		stack.next = NULL;
    743 	}
    744 }
    745 
    746 /*
    747 ===============
    748 PassageFlow
    749 ===============
    750 */
    751 void PassageFlow (int portalnum)
    752 {
    753 	threaddata_t	data;
    754 	int				i;
    755 	vportal_t		*p;
    756 //	int				c_might, c_can;
    757 
    758 #ifdef MREDEBUG
    759 	_printf("\r%6d", portalnum);
    760 #endif
    761 
    762 	p = sorted_portals[portalnum];
    763 
    764 	if (p->removed)
    765 	{
    766 		p->status = stat_done;
    767 		return;
    768 	}
    769 
    770 	p->status = stat_working;
    771 
    772 //	c_might = CountBits (p->portalflood, numportals*2);
    773 
    774 	memset (&data, 0, sizeof(data));
    775 	data.base = p;
    776 	
    777 	data.pstack_head.portal = p;
    778 	data.pstack_head.source = p->winding;
    779 	data.pstack_head.portalplane = p->plane;
    780 	data.pstack_head.depth = 0;
    781 	for (i=0 ; i<portallongs ; i++)
    782 		((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i];
    783 
    784 	RecursivePassageFlow (p, &data, &data.pstack_head);
    785 
    786 	p->status = stat_done;
    787 
    788 	/*
    789 	c_can = CountBits (p->portalvis, numportals*2);
    790 
    791 	qprintf ("portal:%4i  mightsee:%4i  cansee:%4i (%i chains)\n", 
    792 		(int)(p - portals),	c_might, c_can, data.c_chains);
    793 	*/
    794 }
    795 
    796 /*
    797 ==================
    798 RecursivePassagePortalFlow
    799 ==================
    800 */
    801 void RecursivePassagePortalFlow (vportal_t *portal, threaddata_t *thread, pstack_t *prevstack)
    802 {
    803 	pstack_t	stack;
    804 	vportal_t	*p;
    805 	leaf_t 		*leaf;
    806 	plane_t		backplane;
    807 	passage_t	*passage, *nextpassage;
    808 	int			i, j, n;
    809 	long		*might, *vis, *prevmight, *cansee, *portalvis, more;
    810 	int			pnum;
    811 
    812 //	thread->c_chains++;
    813 
    814 	leaf = &leafs[portal->leaf];
    815 //	CheckStack (leaf, thread);
    816 
    817 	prevstack->next = &stack;
    818 
    819 	stack.next = NULL;
    820 	stack.leaf = leaf;
    821 	stack.portal = NULL;
    822 	stack.depth = prevstack->depth + 1;
    823 
    824 #ifdef SEPERATORCACHE
    825 	stack.numseperators[0] = 0;
    826 	stack.numseperators[1] = 0;
    827 #endif
    828 
    829 	vis = (long *)thread->base->portalvis;
    830 
    831 	passage = portal->passages;
    832 	nextpassage = passage;
    833 	// check all portals for flowing into other leafs	
    834 	for (i = 0; i < leaf->numportals; i++, passage = nextpassage)
    835 	{
    836 		p = leaf->portals[i];
    837 		if (p->removed)
    838 			continue;
    839 		nextpassage = passage->next;
    840 		pnum = p - portals;
    841 
    842 		if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) )
    843 			continue;	// can't possibly see it
    844 
    845 		prevmight = (long *)prevstack->mightsee;
    846 		cansee = (long *)passage->cansee;
    847 		might = (long *)stack.mightsee;
    848 		memcpy(might, prevmight, portalbytes);
    849 		if (p->status == stat_done)
    850 			portalvis = (long *) p->portalvis;
    851 		else
    852 			portalvis = (long *) p->portalflood;
    853 		more = 0;
    854 		for (j = 0; j < portallongs; j++)
    855 		{
    856 			if (*might)
    857 			{
    858 				*might &= *cansee++ & *portalvis++;
    859 				more |= (*might & ~vis[j]);
    860 			}
    861 			else
    862 			{
    863 				cansee++;
    864 				portalvis++;
    865 			}
    866 			might++;
    867 		}
    868 
    869 		if (!more && (thread->base->portalvis[pnum>>3] & (1<<(pnum&7))) )
    870 		{	// can't see anything new
    871 			continue;
    872 		}
    873 
    874 		// get plane of portal, point normal into the neighbor leaf
    875 		stack.portalplane = p->plane;
    876 		VectorSubtract (vec3_origin, p->plane.normal, backplane.normal);
    877 		backplane.dist = -p->plane.dist;
    878 		
    879 //		c_portalcheck++;
    880 		
    881 		stack.portal = p;
    882 		stack.next = NULL;
    883 		stack.freewindings[0] = 1;
    884 		stack.freewindings[1] = 1;
    885 		stack.freewindings[2] = 1;
    886 
    887 #if 1
    888 		{
    889 			float d;
    890 
    891 			d = DotProduct (p->origin, thread->pstack_head.portalplane.normal);
    892 			d -= thread->pstack_head.portalplane.dist;
    893 			if (d < -p->radius)
    894 			{
    895 				continue;
    896 			}
    897 			else if (d > p->radius)
    898 			{
    899 				stack.pass = p->winding;
    900 			}
    901 			else	
    902 			{
    903 				stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
    904 				if (!stack.pass)
    905 					continue;
    906 			}
    907 		}
    908 #else
    909 		stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
    910 		if (!stack.pass)
    911 			continue;
    912 #endif
    913 
    914 	
    915 #if 1
    916 		{
    917 			float d;
    918 
    919 			d = DotProduct (thread->base->origin, p->plane.normal);
    920 			d -= p->plane.dist;
    921 			//MrE: vis-bug fix
    922 			//if (d > p->radius)
    923 			if (d > thread->base->radius)
    924 			{
    925 				continue;
    926 			}
    927 			//MrE: vis-bug fix
    928 			//if (d < -p->radius)
    929 			else if (d < -thread->base->radius)
    930 			{
    931 				stack.source = prevstack->source;
    932 			}
    933 			else	
    934 			{
    935 				stack.source = VisChopWinding (prevstack->source, &stack, &backplane);
    936 				//FIXME: shouldn't we create a new source origin and radius for fast checks?
    937 				if (!stack.source)
    938 					continue;
    939 			}
    940 		}
    941 #else
    942 		stack.source = VisChopWinding (prevstack->source, &stack, &backplane);
    943 		if (!stack.source)
    944 			continue;
    945 #endif
    946 
    947 		if (!prevstack->pass)
    948 		{	// the second leaf can only be blocked if coplanar
    949 
    950 			// mark the portal as visible
    951 			thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
    952 
    953 			RecursivePassagePortalFlow (p, thread, &stack);
    954 			continue;
    955 		}
    956 
    957 #ifdef SEPERATORCACHE
    958 		if (stack.numseperators[0])
    959 		{
    960 			for (n = 0; n < stack.numseperators[0]; n++)
    961 			{
    962 				stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[0][n]);
    963 				if (!stack.pass)
    964 					break;		// target is not visible
    965 			}
    966 			if (n < stack.numseperators[0])
    967 				continue;
    968 		}
    969 		else
    970 		{
    971 			stack.pass = ClipToSeperators (prevstack->source, prevstack->pass, stack.pass, qfalse, &stack);
    972 		}
    973 #else
    974 		stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, qfalse, &stack);
    975 #endif
    976 		if (!stack.pass)
    977 			continue;
    978 
    979 #ifdef SEPERATORCACHE
    980 		if (stack.numseperators[1])
    981 		{
    982 			for (n = 0; n < stack.numseperators[1]; n++)
    983 			{
    984 				stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[1][n]);
    985 				if (!stack.pass)
    986 					break;		// target is not visible
    987 			}
    988 		}
    989 		else
    990 		{
    991 			stack.pass = ClipToSeperators (prevstack->pass, prevstack->source, stack.pass, qtrue, &stack);
    992 		}
    993 #else
    994 		stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, qtrue, &stack);
    995 #endif
    996 		if (!stack.pass)
    997 			continue;
    998 
    999 		// mark the portal as visible
   1000 		thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
   1001 
   1002 		// flow through it for real
   1003 		RecursivePassagePortalFlow(p, thread, &stack);
   1004 		//
   1005 		stack.next = NULL;
   1006 	}
   1007 }
   1008 
   1009 /*
   1010 ===============
   1011 PassagePortalFlow
   1012 ===============
   1013 */
   1014 void PassagePortalFlow (int portalnum)
   1015 {
   1016 	threaddata_t	data;
   1017 	int				i;
   1018 	vportal_t		*p;
   1019 //	int				c_might, c_can;
   1020 
   1021 #ifdef MREDEBUG
   1022 	_printf("\r%6d", portalnum);
   1023 #endif
   1024 
   1025 	p = sorted_portals[portalnum];
   1026 
   1027 	if (p->removed)
   1028 	{
   1029 		p->status = stat_done;
   1030 		return;
   1031 	}
   1032 
   1033 	p->status = stat_working;
   1034 
   1035 //	c_might = CountBits (p->portalflood, numportals*2);
   1036 
   1037 	memset (&data, 0, sizeof(data));
   1038 	data.base = p;
   1039 	
   1040 	data.pstack_head.portal = p;
   1041 	data.pstack_head.source = p->winding;
   1042 	data.pstack_head.portalplane = p->plane;
   1043 	data.pstack_head.depth = 0;
   1044 	for (i=0 ; i<portallongs ; i++)
   1045 		((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i];
   1046 
   1047 	RecursivePassagePortalFlow (p, &data, &data.pstack_head);
   1048 
   1049 	p->status = stat_done;
   1050 
   1051 	/*
   1052 	c_can = CountBits (p->portalvis, numportals*2);
   1053 
   1054 	qprintf ("portal:%4i  mightsee:%4i  cansee:%4i (%i chains)\n", 
   1055 		(int)(p - portals),	c_might, c_can, data.c_chains);
   1056 	*/
   1057 }
   1058 
   1059 winding_t *PassageChopWinding (winding_t *in, winding_t *out, plane_t *split)
   1060 {
   1061 	vec_t	dists[128];
   1062 	int		sides[128];
   1063 	int		counts[3];
   1064 	vec_t	dot;
   1065 	int		i, j;
   1066 	vec_t	*p1, *p2;
   1067 	vec3_t	mid;
   1068 	winding_t	*neww;
   1069 
   1070 	counts[0] = counts[1] = counts[2] = 0;
   1071 
   1072 	// determine sides for each point
   1073 	for (i=0 ; i<in->numpoints ; i++)
   1074 	{
   1075 		dot = DotProduct (in->points[i], split->normal);
   1076 		dot -= split->dist;
   1077 		dists[i] = dot;
   1078 		if (dot > ON_EPSILON)
   1079 			sides[i] = SIDE_FRONT;
   1080 		else if (dot < -ON_EPSILON)
   1081 			sides[i] = SIDE_BACK;
   1082 		else
   1083 		{
   1084 			sides[i] = SIDE_ON;
   1085 		}
   1086 		counts[sides[i]]++;
   1087 	}
   1088 
   1089 	if (!counts[1])
   1090 		return in;		// completely on front side
   1091 	
   1092 	if (!counts[0])
   1093 	{
   1094 		return NULL;
   1095 	}
   1096 
   1097 	sides[i] = sides[0];
   1098 	dists[i] = dists[0];
   1099 	
   1100 	neww = out;
   1101 
   1102 	neww->numpoints = 0;
   1103 
   1104 	for (i=0 ; i<in->numpoints ; i++)
   1105 	{
   1106 		p1 = in->points[i];
   1107 
   1108 		if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
   1109 		{
   1110 			return in;		// can't chop -- fall back to original
   1111 		}
   1112 
   1113 		if (sides[i] == SIDE_ON)
   1114 		{
   1115 			VectorCopy (p1, neww->points[neww->numpoints]);
   1116 			neww->numpoints++;
   1117 			continue;
   1118 		}
   1119 	
   1120 		if (sides[i] == SIDE_FRONT)
   1121 		{
   1122 			VectorCopy (p1, neww->points[neww->numpoints]);
   1123 			neww->numpoints++;
   1124 		}
   1125 		
   1126 		if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
   1127 			continue;
   1128 			
   1129 		if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
   1130 		{
   1131 			return in;		// can't chop -- fall back to original
   1132 		}
   1133 
   1134 		// generate a split point
   1135 		p2 = in->points[(i+1)%in->numpoints];
   1136 		
   1137 		dot = dists[i] / (dists[i]-dists[i+1]);
   1138 		for (j=0 ; j<3 ; j++)
   1139 		{	// avoid round off error when possible
   1140 			if (split->normal[j] == 1)
   1141 				mid[j] = split->dist;
   1142 			else if (split->normal[j] == -1)
   1143 				mid[j] = -split->dist;
   1144 			else
   1145 				mid[j] = p1[j] + dot*(p2[j]-p1[j]);
   1146 		}
   1147 			
   1148 		VectorCopy (mid, neww->points[neww->numpoints]);
   1149 		neww->numpoints++;
   1150 	}
   1151 	
   1152 	return neww;
   1153 }
   1154 
   1155 /*
   1156 ===============
   1157 AddSeperators
   1158 ===============
   1159 */
   1160 int AddSeperators (winding_t *source, winding_t *pass, qboolean flipclip, plane_t *seperators, int maxseperators)
   1161 {
   1162 	int			i, j, k, l;
   1163 	plane_t		plane;
   1164 	vec3_t		v1, v2;
   1165 	float		d;
   1166 	vec_t		length;
   1167 	int			counts[3], numseperators;
   1168 	qboolean	fliptest;
   1169 
   1170 	numseperators = 0;
   1171 	// check all combinations	
   1172 	for (i=0 ; i<source->numpoints ; i++)
   1173 	{
   1174 		l = (i+1)%source->numpoints;
   1175 		VectorSubtract (source->points[l] , source->points[i], v1);
   1176 
   1177 		// find a vertex of pass that makes a plane that puts all of the
   1178 		// vertexes of pass on the front side and all of the vertexes of
   1179 		// source on the back side
   1180 		for (j=0 ; j<pass->numpoints ; j++)
   1181 		{
   1182 			VectorSubtract (pass->points[j], source->points[i], v2);
   1183 
   1184 			plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
   1185 			plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
   1186 			plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
   1187 			
   1188 			// if points don't make a valid plane, skip it
   1189 
   1190 			length = plane.normal[0] * plane.normal[0]
   1191 			+ plane.normal[1] * plane.normal[1]
   1192 			+ plane.normal[2] * plane.normal[2];
   1193 			
   1194 			if (length < ON_EPSILON)
   1195 				continue;
   1196 
   1197 			length = 1/sqrt(length);
   1198 			
   1199 			plane.normal[0] *= length;
   1200 			plane.normal[1] *= length;
   1201 			plane.normal[2] *= length;
   1202 
   1203 			plane.dist = DotProduct (pass->points[j], plane.normal);
   1204 
   1205 			//
   1206 			// find out which side of the generated seperating plane has the
   1207 			// source portal
   1208 			//
   1209 #if 1
   1210 			fliptest = qfalse;
   1211 			for (k=0 ; k<source->numpoints ; k++)
   1212 			{
   1213 				if (k == i || k == l)
   1214 					continue;
   1215 				d = DotProduct (source->points[k], plane.normal) - plane.dist;
   1216 				if (d < -ON_EPSILON)
   1217 				{	// source is on the negative side, so we want all
   1218 					// pass and target on the positive side
   1219 					fliptest = qfalse;
   1220 					break;
   1221 				}
   1222 				else if (d > ON_EPSILON)
   1223 				{	// source is on the positive side, so we want all
   1224 					// pass and target on the negative side
   1225 					fliptest = qtrue;
   1226 					break;
   1227 				}
   1228 			}
   1229 			if (k == source->numpoints)
   1230 				continue;		// planar with source portal
   1231 #else
   1232 			fliptest = flipclip;
   1233 #endif
   1234 			//
   1235 			// flip the normal if the source portal is backwards
   1236 			//
   1237 			if (fliptest)
   1238 			{
   1239 				VectorSubtract (vec3_origin, plane.normal, plane.normal);
   1240 				plane.dist = -plane.dist;
   1241 			}
   1242 #if 1
   1243 			//
   1244 			// if all of the pass portal points are now on the positive side,
   1245 			// this is the seperating plane
   1246 			//
   1247 			counts[0] = counts[1] = counts[2] = 0;
   1248 			for (k=0 ; k<pass->numpoints ; k++)
   1249 			{
   1250 				if (k==j)
   1251 					continue;
   1252 				d = DotProduct (pass->points[k], plane.normal) - plane.dist;
   1253 				if (d < -ON_EPSILON)
   1254 					break;
   1255 				else if (d > ON_EPSILON)
   1256 					counts[0]++;
   1257 				else
   1258 					counts[2]++;
   1259 			}
   1260 			if (k != pass->numpoints)
   1261 				continue;	// points on negative side, not a seperating plane
   1262 				
   1263 			if (!counts[0])
   1264 				continue;	// planar with seperating plane
   1265 #else
   1266 			k = (j+1)%pass->numpoints;
   1267 			d = DotProduct (pass->points[k], plane.normal) - plane.dist;
   1268 			if (d < -ON_EPSILON)
   1269 				continue;
   1270 			k = (j+pass->numpoints-1)%pass->numpoints;
   1271 			d = DotProduct (pass->points[k], plane.normal) - plane.dist;
   1272 			if (d < -ON_EPSILON)
   1273 				continue;			
   1274 #endif
   1275 			//
   1276 			// flip the normal if we want the back side
   1277 			//
   1278 			if (flipclip)
   1279 			{
   1280 				VectorSubtract (vec3_origin, plane.normal, plane.normal);
   1281 				plane.dist = -plane.dist;
   1282 			}
   1283 
   1284 			if (numseperators >= maxseperators)
   1285 				Error("max seperators");
   1286 			seperators[numseperators] = plane;
   1287 			numseperators++;
   1288 			break;
   1289 		}
   1290 	}
   1291 	return numseperators;
   1292 }
   1293 
   1294 /*
   1295 ===============
   1296 CreatePassages
   1297 
   1298 MrE: create passages from one portal to all the portals in the leaf the portal leads to
   1299 	 every passage has a cansee bit string with all the portals that can be
   1300 	 seen through the passage
   1301 ===============
   1302 */
   1303 void CreatePassages(int portalnum)
   1304 {
   1305 	int i, j, k, n, numseperators, numsee;
   1306 	float d;
   1307 	vportal_t *portal, *p, *target;
   1308 	leaf_t *leaf;
   1309 	passage_t	*passage, *lastpassage;
   1310 	plane_t seperators[MAX_SEPERATORS*2];
   1311 	winding_t *w;
   1312 	winding_t in, out, *res;
   1313 
   1314 #ifdef MREDEBUG
   1315 	_printf("\r%6d", portalnum);
   1316 #endif
   1317 
   1318 	portal = sorted_portals[portalnum];
   1319 
   1320 	if (portal->removed)
   1321 	{
   1322 		portal->status = stat_done;
   1323 		return;
   1324 	}
   1325 
   1326 	lastpassage = NULL;
   1327 	leaf = &leafs[portal->leaf];
   1328 	for (i = 0; i < leaf->numportals; i++)
   1329 	{
   1330 		target = leaf->portals[i];
   1331 		if (target->removed)
   1332 			continue;
   1333 
   1334 		passage = (passage_t *) malloc(sizeof(passage_t) + portalbytes);
   1335 		memset(passage, 0, sizeof(passage_t) + portalbytes);
   1336 		numseperators = AddSeperators(portal->winding, target->winding, qfalse, seperators, MAX_SEPERATORS*2);
   1337 		numseperators += AddSeperators(target->winding, portal->winding, qtrue, &seperators[numseperators], MAX_SEPERATORS*2-numseperators);
   1338 
   1339 		passage->next = NULL;
   1340 		if (lastpassage)
   1341 			lastpassage->next = passage;
   1342 		else
   1343 			portal->passages = passage;
   1344 		lastpassage = passage;
   1345 
   1346 		numsee = 0;
   1347 		//create the passage->cansee
   1348 		for (j = 0; j < numportals * 2; j++)
   1349 		{
   1350 			p = &portals[j];
   1351 			if (p->removed)
   1352 				continue;
   1353 			if ( ! (target->portalflood[j >> 3] & (1<<(j&7)) ) )
   1354 				continue;
   1355 			if ( ! (portal->portalflood[j >> 3] & (1<<(j&7)) ) )
   1356 				continue;
   1357 			for (k = 0; k < numseperators; k++)
   1358 			{
   1359 				//
   1360 				d = DotProduct (p->origin, seperators[k].normal) - seperators[k].dist;
   1361 				//if completely at the back of the seperator plane
   1362 				if (d < -p->radius + ON_EPSILON)
   1363 					break;
   1364 				w = p->winding;
   1365 				for (n = 0; n < w->numpoints; n++)
   1366 				{
   1367 					d = DotProduct (w->points[n], seperators[k].normal) - seperators[k].dist;
   1368 					//if at the front of the seperator
   1369 					if (d > ON_EPSILON)
   1370 						break;
   1371 				}
   1372 				//if no points are at the front of the seperator
   1373 				if (n >= w->numpoints)
   1374 					break;
   1375 			}
   1376 			if (k < numseperators)
   1377 				continue;
   1378 			memcpy(&in, p->winding, sizeof(winding_t));
   1379 			for (k = 0; k < numseperators; k++)
   1380 			{
   1381 				res = PassageChopWinding(&in, &out, &seperators[k]);
   1382 				if (res == &out)
   1383 					memcpy(&in, &out, sizeof(winding_t));
   1384 				if (res == NULL)
   1385 					break;
   1386 			}
   1387 			if (k < numseperators)
   1388 				continue;
   1389 			passage->cansee[j >> 3] |= (1<<(j&7));
   1390 			numsee++;
   1391 		}
   1392 	}
   1393 }
   1394 
   1395 void PassageMemory(void)
   1396 {
   1397 	int i, j, totalmem, totalportals;
   1398 	vportal_t *portal, *target;
   1399 	leaf_t *leaf;
   1400 
   1401 	totalmem = 0;
   1402 	totalportals = 0;
   1403 	for (i = 0; i < numportals; i++)
   1404 	{
   1405 		portal = sorted_portals[i];
   1406 		if (portal->removed)
   1407 			continue;
   1408 		leaf = &leafs[portal->leaf];
   1409 		for (j = 0; j < leaf->numportals; j++)
   1410 		{
   1411 			target = leaf->portals[j];
   1412 			if (target->removed)
   1413 				continue;
   1414 			totalmem += sizeof(passage_t) + portalbytes;
   1415 			totalportals++;
   1416 		}
   1417 	}
   1418 	_printf("%7i average number of passages per leaf\n", totalportals / numportals);
   1419 	_printf("%7i MB required passage memory\n", totalmem >> 10 >> 10);
   1420 }
   1421 
   1422 /*
   1423 ===============================================================================
   1424 
   1425 This is a rough first-order aproximation that is used to trivially reject some
   1426 of the final calculations.
   1427 
   1428 
   1429 Calculates portalfront and portalflood bit vectors
   1430 
   1431 thinking about:
   1432 
   1433 typedef struct passage_s
   1434 {
   1435 	struct passage_s	*next;
   1436 	struct portal_s		*to;
   1437 	stryct sep_s		*seperators;
   1438 	byte				*mightsee;
   1439 } passage_t;
   1440 
   1441 typedef struct portal_s
   1442 {
   1443 	struct passage_s	*passages;
   1444 	int					leaf;		// leaf portal faces into
   1445 } portal_s;
   1446 
   1447 leaf = portal->leaf
   1448 clear 
   1449 for all portals
   1450 
   1451 
   1452 calc portal visibility
   1453 	clear bit vector
   1454 	for all passages
   1455 		passage visibility
   1456 
   1457 
   1458 for a portal to be visible to a passage, it must be on the front of
   1459 all seperating planes, and both portals must be behind the new portal
   1460 
   1461 ===============================================================================
   1462 */
   1463 
   1464 int		c_flood, c_vis;
   1465 
   1466 
   1467 /*
   1468 ==================
   1469 SimpleFlood
   1470 
   1471 ==================
   1472 */
   1473 void SimpleFlood (vportal_t *srcportal, int leafnum)
   1474 {
   1475 	int		i;
   1476 	leaf_t	*leaf;
   1477 	vportal_t	*p;
   1478 	int		pnum;
   1479 
   1480 	leaf = &leafs[leafnum];
   1481 	
   1482 	for (i=0 ; i<leaf->numportals ; i++)
   1483 	{
   1484 		p = leaf->portals[i];
   1485 		if (p->removed)
   1486 			continue;
   1487 		pnum = p - portals;
   1488 		if ( ! (srcportal->portalfront[pnum>>3] & (1<<(pnum&7)) ) )
   1489 			continue;
   1490 
   1491 		if (srcportal->portalflood[pnum>>3] & (1<<(pnum&7)) )
   1492 			continue;
   1493 
   1494 		srcportal->portalflood[pnum>>3] |= (1<<(pnum&7));
   1495 		
   1496 		SimpleFlood (srcportal, p->leaf);
   1497 	}
   1498 }
   1499 
   1500 /*
   1501 ==============
   1502 BasePortalVis
   1503 ==============
   1504 */
   1505 void BasePortalVis (int portalnum)
   1506 {
   1507 	int			j, k;
   1508 	vportal_t	*tp, *p;
   1509 	float		d;
   1510 	winding_t	*w;
   1511 
   1512 	p = portals+portalnum;
   1513 
   1514 	if (p->removed)
   1515 		return;
   1516 
   1517 	p->portalfront = malloc (portalbytes);
   1518 	memset (p->portalfront, 0, portalbytes);
   1519 
   1520 	p->portalflood = malloc (portalbytes);
   1521 	memset (p->portalflood, 0, portalbytes);
   1522 	
   1523 	p->portalvis = malloc (portalbytes);
   1524 	memset (p->portalvis, 0, portalbytes);
   1525 	
   1526 	for (j=0, tp = portals ; j<numportals*2 ; j++, tp++)
   1527 	{
   1528 		if (j == portalnum)
   1529 			continue;
   1530 		if (tp->removed)
   1531 			continue;
   1532 		/*
   1533 		if (farplanedist >= 0)
   1534 		{
   1535 			vec3_t dir;
   1536 			VectorSubtract(p->origin, tp->origin, dir);
   1537 			if (VectorLength(dir) > farplanedist - p->radius - tp->radius)
   1538 				continue;
   1539 		}
   1540 		*/
   1541 		w = tp->winding;
   1542 		for (k=0 ; k<w->numpoints ; k++)
   1543 		{
   1544 			d = DotProduct (w->points[k], p->plane.normal)
   1545 				- p->plane.dist;
   1546 			if (d > ON_EPSILON)
   1547 				break;
   1548 		}
   1549 		if (k == w->numpoints)
   1550 			continue;	// no points on front
   1551 
   1552 		w = p->winding;
   1553 		for (k=0 ; k<w->numpoints ; k++)
   1554 		{
   1555 			d = DotProduct (w->points[k], tp->plane.normal)
   1556 				- tp->plane.dist;
   1557 			if (d < -ON_EPSILON)
   1558 				break;
   1559 		}
   1560 		if (k == w->numpoints)
   1561 			continue;	// no points on front
   1562 
   1563 		p->portalfront[j>>3] |= (1<<(j&7));
   1564 	}
   1565 	
   1566 	SimpleFlood (p, p->leaf);
   1567 
   1568 	p->nummightsee = CountBits (p->portalflood, numportals*2);
   1569 //	_printf ("portal %i: %i mightsee\n", portalnum, p->nummightsee);
   1570 	c_flood += p->nummightsee;
   1571 }
   1572 
   1573 
   1574 
   1575 
   1576 
   1577 /*
   1578 ===============================================================================
   1579 
   1580 This is a second order aproximation 
   1581 
   1582 Calculates portalvis bit vector
   1583 
   1584 WAAAAAAY too slow.
   1585 
   1586 ===============================================================================
   1587 */
   1588 
   1589 /*
   1590 ==================
   1591 RecursiveLeafBitFlow
   1592 
   1593 ==================
   1594 */
   1595 void RecursiveLeafBitFlow (int leafnum, byte *mightsee, byte *cansee)
   1596 {
   1597 	vportal_t	*p;
   1598 	leaf_t 		*leaf;
   1599 	int			i, j;
   1600 	long		more;
   1601 	int			pnum;
   1602 	byte		newmight[MAX_PORTALS/8];
   1603 
   1604 	leaf = &leafs[leafnum];
   1605 	
   1606 	// check all portals for flowing into other leafs
   1607 	for (i=0 ; i<leaf->numportals ; i++)
   1608 	{
   1609 		p = leaf->portals[i];
   1610 		if (p->removed)
   1611 			continue;
   1612 		pnum = p - portals;
   1613 
   1614 		// if some previous portal can't see it, skip
   1615 		if (! (mightsee[pnum>>3] & (1<<(pnum&7)) ) )
   1616 			continue;
   1617 
   1618 		// if this portal can see some portals we mightsee, recurse
   1619 		more = 0;
   1620 		for (j=0 ; j<portallongs ; j++)
   1621 		{
   1622 			((long *)newmight)[j] = ((long *)mightsee)[j] 
   1623 				& ((long *)p->portalflood)[j];
   1624 			more |= ((long *)newmight)[j] & ~((long *)cansee)[j];
   1625 		}
   1626 
   1627 		if (!more)
   1628 			continue;	// can't see anything new
   1629 
   1630 		cansee[pnum>>3] |= (1<<(pnum&7));
   1631 
   1632 		RecursiveLeafBitFlow (p->leaf, newmight, cansee);
   1633 	}	
   1634 }
   1635 
   1636 /*
   1637 ==============
   1638 BetterPortalVis
   1639 ==============
   1640 */
   1641 void BetterPortalVis (int portalnum)
   1642 {
   1643 	vportal_t	*p;
   1644 
   1645 	p = portals+portalnum;
   1646 
   1647 	if (p->removed)
   1648 		return;
   1649 
   1650 	RecursiveLeafBitFlow (p->leaf, p->portalflood, p->portalvis);
   1651 
   1652 	// build leaf vis information
   1653 	p->nummightsee = CountBits (p->portalvis, numportals*2);
   1654 	c_vis += p->nummightsee;
   1655 }
   1656 
   1657