Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

portals.c (33180B)


      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 
     23 #include "qbsp.h"
     24 #include "l_mem.h"
     25 
     26 int		c_active_portals;
     27 int		c_peak_portals;
     28 int		c_boundary;
     29 int		c_boundary_sides;
     30 int		c_portalmemory;
     31 
     32 //portal_t *portallist = NULL;
     33 //===========================================================================
     34 //
     35 // Parameter:				-
     36 // Returns:					-
     37 // Changes Globals:		-
     38 //===========================================================================
     39 portal_t *AllocPortal (void)
     40 {
     41 	portal_t	*p;
     42 	
     43 	p = GetMemory(sizeof(portal_t));
     44 	memset (p, 0, sizeof(portal_t));
     45 
     46 	if (numthreads == 1)
     47 	{
     48 		c_active_portals++;
     49 		if (c_active_portals > c_peak_portals)
     50 		{
     51 			c_peak_portals = c_active_portals;
     52 		} //end if
     53 		c_portalmemory += MemorySize(p);	
     54 	} //end if
     55 
     56 //	p->nextportal = portallist;
     57 //	portallist = p;
     58 	
     59 	return p;
     60 } //end of the function AllocPortal
     61 //===========================================================================
     62 //
     63 // Parameter:				-
     64 // Returns:					-
     65 // Changes Globals:		-
     66 //===========================================================================
     67 void FreePortal (portal_t *p)
     68 {
     69 	if (p->winding) FreeWinding(p->winding);
     70 	if (numthreads == 1)
     71 	{
     72 		c_active_portals--;
     73 		c_portalmemory -= MemorySize(p);
     74 	} //end if
     75 	FreeMemory(p);
     76 } //end of the function FreePortal
     77 //===========================================================================
     78 // Returns the single content bit of the
     79 // strongest visible content present
     80 //
     81 // Parameter:				-
     82 // Returns:					-
     83 // Changes Globals:		-
     84 //===========================================================================
     85 int VisibleContents (int contents)
     86 {
     87 	int		i;
     88 
     89 	for (i=1 ; i<=LAST_VISIBLE_CONTENTS ; i<<=1)
     90 		if (contents & i )
     91 			return i;
     92 
     93 	return 0;
     94 } //end of the function VisibleContents
     95 //===========================================================================
     96 //
     97 // Parameter:				-
     98 // Returns:					-
     99 // Changes Globals:		-
    100 //===========================================================================
    101 int ClusterContents (node_t *node)
    102 {
    103 	int		c1, c2, c;
    104 
    105 	if (node->planenum == PLANENUM_LEAF)
    106 		return node->contents;
    107 
    108 	c1 = ClusterContents(node->children[0]);
    109 	c2 = ClusterContents(node->children[1]);
    110 	c = c1|c2;
    111 
    112 	// a cluster may include some solid detail areas, but
    113 	// still be seen into
    114 	if ( ! (c1&CONTENTS_SOLID) || ! (c2&CONTENTS_SOLID) )
    115 		c &= ~CONTENTS_SOLID;
    116 	return c;
    117 } //end of the function ClusterContents
    118 
    119 //===========================================================================
    120 // Returns true if the portal is empty or translucent, allowing
    121 // the PVS calculation to see through it.
    122 // The nodes on either side of the portal may actually be clusters,
    123 // not leaves, so all contents should be ored together
    124 //
    125 // Parameter:				-
    126 // Returns:					-
    127 // Changes Globals:		-
    128 //===========================================================================
    129 qboolean Portal_VisFlood (portal_t *p)
    130 {
    131 	int		c1, c2;
    132 
    133 	if (!p->onnode)
    134 		return false;	// to global outsideleaf
    135 
    136 	c1 = ClusterContents(p->nodes[0]);
    137 	c2 = ClusterContents(p->nodes[1]);
    138 
    139 	if (!VisibleContents (c1^c2))
    140 		return true;
    141 
    142 	if (c1 & (CONTENTS_Q2TRANSLUCENT|CONTENTS_DETAIL))
    143 		c1 = 0;
    144 	if (c2 & (CONTENTS_Q2TRANSLUCENT|CONTENTS_DETAIL))
    145 		c2 = 0;
    146 
    147 	if ( (c1|c2) & CONTENTS_SOLID )
    148 		return false;		// can't see through solid
    149 
    150 	if (! (c1 ^ c2))
    151 		return true;		// identical on both sides
    152 
    153 	if (!VisibleContents (c1^c2))
    154 		return true;
    155 	return false;
    156 } //end of the function Portal_VisFlood
    157 //===========================================================================
    158 // The entity flood determines which areas are
    159 // "outside" on the map, which are then filled in.
    160 // Flowing from side s to side !s
    161 //
    162 // Parameter:				-
    163 // Returns:					-
    164 // Changes Globals:		-
    165 //===========================================================================
    166 qboolean Portal_EntityFlood (portal_t *p, int s)
    167 {
    168 	if (p->nodes[0]->planenum != PLANENUM_LEAF
    169 		|| p->nodes[1]->planenum != PLANENUM_LEAF)
    170 		Error ("Portal_EntityFlood: not a leaf");
    171 
    172 	// can never cross to a solid 
    173 	if ( (p->nodes[0]->contents & CONTENTS_SOLID)
    174 	|| (p->nodes[1]->contents & CONTENTS_SOLID) )
    175 		return false;
    176 
    177 	// can flood through everything else
    178 	return true;
    179 }
    180 
    181 
    182 //=============================================================================
    183 
    184 int		c_tinyportals;
    185 
    186 //===========================================================================
    187 //
    188 // Parameter:				-
    189 // Returns:					-
    190 // Changes Globals:		-
    191 //===========================================================================
    192 void AddPortalToNodes (portal_t *p, node_t *front, node_t *back)
    193 {
    194 	if (p->nodes[0] || p->nodes[1])
    195 		Error ("AddPortalToNode: allready included");
    196 
    197 	p->nodes[0] = front;
    198 	p->next[0] = front->portals;
    199 	front->portals = p;
    200 	
    201 	p->nodes[1] = back;
    202 	p->next[1] = back->portals;
    203 	back->portals = p;
    204 } //end of the function AddPortalToNodes
    205 //===========================================================================
    206 //
    207 // Parameter:				-
    208 // Returns:					-
    209 // Changes Globals:		-
    210 //===========================================================================
    211 void RemovePortalFromNode (portal_t *portal, node_t *l)
    212 {
    213 	portal_t	**pp, *t;
    214 
    215 	int s, i, n;
    216 	portal_t *p;
    217 	portal_t *portals[4096];
    218 	
    219 // remove reference to the current portal
    220 	pp = &l->portals;
    221 	while (1)
    222 	{
    223 		t = *pp;
    224 		if (!t)
    225 			Error ("RemovePortalFromNode: portal not in leaf");	
    226 
    227 		if ( t == portal )
    228 			break;
    229 
    230 		if (t->nodes[0] == l)
    231 			pp = &t->next[0];
    232 		else if (t->nodes[1] == l)
    233 			pp = &t->next[1];
    234 		else
    235 			Error ("RemovePortalFromNode: portal not bounding leaf");
    236 	}
    237 	
    238 	if (portal->nodes[0] == l)
    239 	{
    240 		*pp = portal->next[0];
    241 		portal->nodes[0] = NULL;
    242 	} //end if
    243 	else if (portal->nodes[1] == l)
    244 	{
    245 		*pp = portal->next[1];	
    246 		portal->nodes[1] = NULL;
    247 	} //end else if
    248 	else
    249 	{
    250 		Error("RemovePortalFromNode: mislinked portal");
    251 	} //end else
    252 //#ifdef ME
    253 	n = 0;
    254 	for (p = l->portals; p; p = p->next[s])
    255 	{
    256 		for (i = 0; i < n; i++)
    257 		{
    258 			if (p == portals[i]) Error("RemovePortalFromNode: circular linked\n");
    259 		} //end for
    260 		if (p->nodes[0] != l && p->nodes[1] != l)
    261 		{
    262 			Error("RemovePortalFromNodes: portal does not belong to node\n");
    263 		} //end if
    264 		portals[n] = p;
    265 		s = (p->nodes[1] == l);
    266 //		if (++n >= 4096) Error("RemovePortalFromNode: more than 4096 portals\n");
    267 	} //end for
    268 //#endif
    269 } //end of the function RemovePortalFromNode
    270 //===========================================================================
    271 //
    272 // Parameter:				-
    273 // Returns:					-
    274 // Changes Globals:		-
    275 //===========================================================================
    276 void PrintPortal (portal_t *p)
    277 {
    278 	int			i;
    279 	winding_t	*w;
    280 	
    281 	w = p->winding;
    282 	for (i=0 ; i<w->numpoints ; i++)
    283 		printf ("(%5.0f,%5.0f,%5.0f)\n",w->p[i][0]
    284 		, w->p[i][1], w->p[i][2]);
    285 } //end of the function PrintPortal
    286 //===========================================================================
    287 // The created portals will face the global outside_node
    288 //
    289 // Parameter:				-
    290 // Returns:					-
    291 // Changes Globals:		-
    292 //===========================================================================
    293 #define	SIDESPACE	8
    294 
    295 void MakeHeadnodePortals (tree_t *tree)
    296 {
    297 	vec3_t		bounds[2];
    298 	int			i, j, n;
    299 	portal_t	*p, *portals[6];
    300 	plane_t		bplanes[6], *pl;
    301 	node_t *node;
    302 
    303 	node = tree->headnode;
    304 
    305 // pad with some space so there will never be null volume leaves
    306 	for (i=0 ; i<3 ; i++)
    307 	{
    308 		bounds[0][i] = tree->mins[i] - SIDESPACE;
    309 		bounds[1][i] = tree->maxs[i] + SIDESPACE;
    310 		if ( bounds[0][i] > bounds[1][i] ) {
    311 			Error("empty BSP tree");
    312 		}
    313 	}
    314 	
    315 	tree->outside_node.planenum = PLANENUM_LEAF;
    316 	tree->outside_node.brushlist = NULL;
    317 	tree->outside_node.portals = NULL;
    318 	tree->outside_node.contents = 0;
    319 
    320 	for (i=0 ; i<3 ; i++)
    321 		for (j=0 ; j<2 ; j++)
    322 		{
    323 			n = j*3 + i;
    324 
    325 			p = AllocPortal ();
    326 			portals[n] = p;
    327 			
    328 			pl = &bplanes[n];
    329 			memset (pl, 0, sizeof(*pl));
    330 			if (j)
    331 			{
    332 				pl->normal[i] = -1;
    333 				pl->dist = -bounds[j][i];
    334 			}
    335 			else
    336 			{
    337 				pl->normal[i] = 1;
    338 				pl->dist = bounds[j][i];
    339 			}
    340 			p->plane = *pl;
    341 			p->winding = BaseWindingForPlane (pl->normal, pl->dist);
    342 			AddPortalToNodes (p, node, &tree->outside_node);
    343 		}
    344 		
    345 // clip the basewindings by all the other planes
    346 	for (i=0 ; i<6 ; i++)
    347 	{
    348 		for (j=0 ; j<6 ; j++)
    349 		{
    350 			if (j == i) continue;
    351 			ChopWindingInPlace (&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON);
    352 		} //end for
    353 	} //end for
    354 } //end of the function MakeHeadNodePortals
    355 //===========================================================================
    356 //
    357 // Parameter:				-
    358 // Returns:					-
    359 // Changes Globals:		-
    360 //===========================================================================
    361 #define	BASE_WINDING_EPSILON		0.001
    362 #define	SPLIT_WINDING_EPSILON	0.001
    363 
    364 winding_t *BaseWindingForNode (node_t *node)
    365 {
    366 	winding_t	*w;
    367 	node_t		*n;
    368 	plane_t		*plane;
    369 	vec3_t		normal;
    370 	vec_t		dist;
    371 
    372 	w = BaseWindingForPlane (mapplanes[node->planenum].normal
    373 		, mapplanes[node->planenum].dist);
    374 
    375 	// clip by all the parents
    376 	for (n=node->parent ; n && w ; )
    377 	{
    378 		plane = &mapplanes[n->planenum];
    379 
    380 		if (n->children[0] == node)
    381 		{	// take front
    382 			ChopWindingInPlace (&w, plane->normal, plane->dist, BASE_WINDING_EPSILON);
    383 		}
    384 		else
    385 		{	// take back
    386 			VectorSubtract (vec3_origin, plane->normal, normal);
    387 			dist = -plane->dist;
    388 			ChopWindingInPlace (&w, normal, dist, BASE_WINDING_EPSILON);
    389 		}
    390 		node = n;
    391 		n = n->parent;
    392 	}
    393 
    394 	return w;
    395 } //end of the function BaseWindingForNode
    396 //===========================================================================
    397 // create the new portal by taking the full plane winding for the cutting
    398 // plane and clipping it by all of parents of this node
    399 //
    400 // Parameter:				-
    401 // Returns:					-
    402 // Changes Globals:		-
    403 //===========================================================================
    404 qboolean WindingIsTiny (winding_t *w);
    405 
    406 void MakeNodePortal (node_t *node)
    407 {
    408 	portal_t	*new_portal, *p;
    409 	winding_t	*w;
    410 	vec3_t		normal;
    411 	float		dist;
    412 	int			side;
    413 
    414 	w = BaseWindingForNode (node);
    415 
    416 	// clip the portal by all the other portals in the node
    417 	for (p = node->portals; p && w; p = p->next[side])	
    418 	{
    419 		if (p->nodes[0] == node)
    420 		{
    421 			side = 0;
    422 			VectorCopy (p->plane.normal, normal);
    423 			dist = p->plane.dist;
    424 		} //end if
    425 		else if (p->nodes[1] == node)
    426 		{
    427 			side = 1;
    428 			VectorSubtract (vec3_origin, p->plane.normal, normal);
    429 			dist = -p->plane.dist;
    430 		} //end else if
    431 		else
    432 		{
    433 			Error ("MakeNodePortal: mislinked portal");
    434 		} //end else
    435 		ChopWindingInPlace (&w, normal, dist, 0.1);
    436 	} //end for
    437 
    438 	if (!w)
    439 	{
    440 		return;
    441 	} //end if
    442 
    443 	if (WindingIsTiny (w))
    444 	{
    445 		c_tinyportals++;
    446 		FreeWinding(w);
    447 		return;
    448 	} //end if
    449 
    450 #ifdef DEBUG
    451 /* //NOTE: don't use this winding ok check
    452 	// all the invalid windings only have a degenerate edge
    453 	if (WindingError(w))
    454 	{
    455 		Log_Print("MakeNodePortal: %s\n", WindingErrorString());
    456 		FreeWinding(w);
    457 		return;
    458 	} //end if*/
    459 #endif //DEBUG
    460 
    461 
    462 	new_portal = AllocPortal();
    463 	new_portal->plane = mapplanes[node->planenum];
    464 
    465 #ifdef ME
    466 	new_portal->planenum = node->planenum;
    467 #endif //ME
    468 
    469 	new_portal->onnode = node;
    470 	new_portal->winding = w;
    471 	AddPortalToNodes (new_portal, node->children[0], node->children[1]);
    472 } //end of the function MakeNodePortal
    473 //===========================================================================
    474 // Move or split the portals that bound node so that the node's
    475 // children have portals instead of node.
    476 //
    477 // Parameter:				-
    478 // Returns:					-
    479 // Changes Globals:		-
    480 //===========================================================================
    481 void SplitNodePortals (node_t *node)
    482 {
    483 	portal_t	*p, *next_portal, *new_portal;
    484 	node_t *f, *b, *other_node;
    485 	int side;
    486 	plane_t *plane;
    487 	winding_t *frontwinding, *backwinding;
    488 
    489 	plane = &mapplanes[node->planenum];
    490 	f = node->children[0];
    491 	b = node->children[1];
    492 
    493 	for (p = node->portals ; p ; p = next_portal)	
    494 	{
    495 		if (p->nodes[0] == node) side = 0;
    496 		else if (p->nodes[1] == node) side = 1;
    497 		else Error ("SplitNodePortals: mislinked portal");
    498 		next_portal = p->next[side];
    499 
    500 		other_node = p->nodes[!side];
    501 		RemovePortalFromNode (p, p->nodes[0]);
    502 		RemovePortalFromNode (p, p->nodes[1]);
    503 
    504 //
    505 // cut the portal into two portals, one on each side of the cut plane
    506 //
    507 		ClipWindingEpsilon (p->winding, plane->normal, plane->dist,
    508 				SPLIT_WINDING_EPSILON, &frontwinding, &backwinding);
    509 
    510 		if (frontwinding && WindingIsTiny(frontwinding))
    511 		{
    512 			FreeWinding (frontwinding);
    513 			frontwinding = NULL;
    514 			c_tinyportals++;
    515 		} //end if
    516 
    517 		if (backwinding && WindingIsTiny(backwinding))
    518 		{
    519 			FreeWinding (backwinding);
    520 			backwinding = NULL;
    521 			c_tinyportals++;
    522 		} //end if
    523 
    524 #ifdef DEBUG
    525 /* 	//NOTE: don't use this winding ok check
    526 		// all the invalid windings only have a degenerate edge
    527 		if (frontwinding && WindingError(frontwinding))
    528 		{
    529 			Log_Print("SplitNodePortals: front %s\n", WindingErrorString());
    530 			FreeWinding(frontwinding);
    531 			frontwinding = NULL;
    532 		} //end if
    533 		if (backwinding && WindingError(backwinding))
    534 		{
    535 			Log_Print("SplitNodePortals: back %s\n", WindingErrorString());
    536 			FreeWinding(backwinding);
    537 			backwinding = NULL;
    538 		} //end if*/
    539 #endif //DEBUG
    540 
    541 		if (!frontwinding && !backwinding)
    542 		{	// tiny windings on both sides
    543 			continue;
    544 		}
    545 
    546 		if (!frontwinding)
    547 		{
    548 			FreeWinding (backwinding);
    549 			if (side == 0) AddPortalToNodes (p, b, other_node);
    550 			else AddPortalToNodes (p, other_node, b);
    551 			continue;
    552 		}
    553 		if (!backwinding)
    554 		{
    555 			FreeWinding (frontwinding);
    556 			if (side == 0) AddPortalToNodes (p, f, other_node);
    557 			else AddPortalToNodes (p, other_node, f);
    558 			continue;
    559 		}
    560 		
    561 	// the winding is split
    562 		new_portal = AllocPortal();
    563 		*new_portal = *p;
    564 		new_portal->winding = backwinding;
    565 		FreeWinding (p->winding);
    566 		p->winding = frontwinding;
    567 
    568 		if (side == 0)
    569 		{
    570 			AddPortalToNodes (p, f, other_node);
    571 			AddPortalToNodes (new_portal, b, other_node);
    572 		} //end if
    573 		else
    574 		{
    575 			AddPortalToNodes (p, other_node, f);
    576 			AddPortalToNodes (new_portal, other_node, b);
    577 		} //end else
    578 	}
    579 
    580 	node->portals = NULL;
    581 } //end of the function SplitNodePortals
    582 //===========================================================================
    583 //
    584 // Parameter:				-
    585 // Returns:					-
    586 // Changes Globals:		-
    587 //===========================================================================
    588 void CalcNodeBounds (node_t *node)
    589 {
    590 	portal_t	*p;
    591 	int			s;
    592 	int			i;
    593 
    594 	// calc mins/maxs for both leaves and nodes
    595 	ClearBounds (node->mins, node->maxs);
    596 	for (p = node->portals ; p ; p = p->next[s])	
    597 	{
    598 		s = (p->nodes[1] == node);
    599 		for (i=0 ; i<p->winding->numpoints ; i++)
    600 			AddPointToBounds (p->winding->p[i], node->mins, node->maxs);
    601 	}
    602 } //end of the function CalcNodeBounds
    603 //===========================================================================
    604 //
    605 // Parameter:				-
    606 // Returns:					-
    607 // Changes Globals:		-
    608 //===========================================================================
    609 int c_numportalizednodes;
    610 
    611 void MakeTreePortals_r (node_t *node)
    612 {
    613 	int		i;
    614 
    615 #ifdef ME
    616 	qprintf("\r%6d", ++c_numportalizednodes);
    617 	if (cancelconversion) return;
    618 #endif //ME
    619 
    620 	CalcNodeBounds (node);
    621 	if (node->mins[0] >= node->maxs[0])
    622 	{
    623 		Log_Print("WARNING: node without a volume\n");
    624 	}
    625 
    626 	for (i=0 ; i<3 ; i++)
    627 	{
    628 		if (node->mins[i] < -MAX_MAP_BOUNDS || node->maxs[i] > MAX_MAP_BOUNDS)
    629 		{
    630 			Log_Print("WARNING: node with unbounded volume\n");
    631 			break;
    632 		}
    633 	}
    634 	if (node->planenum == PLANENUM_LEAF)
    635 		return;
    636 
    637 	MakeNodePortal (node);
    638 	SplitNodePortals (node);
    639 
    640 	MakeTreePortals_r (node->children[0]);
    641 	MakeTreePortals_r (node->children[1]);
    642 } //end of the function MakeTreePortals_r
    643 //===========================================================================
    644 //
    645 // Parameter:				-
    646 // Returns:					-
    647 // Changes Globals:		-
    648 //===========================================================================
    649 void MakeTreePortals(tree_t *tree)
    650 {
    651 
    652 #ifdef ME
    653 	Log_Print("---- Node Portalization ----\n");
    654 	c_numportalizednodes = 0;
    655 	c_portalmemory = 0;
    656 	qprintf("%6d nodes portalized", c_numportalizednodes);
    657 #endif //ME
    658 
    659 	MakeHeadnodePortals(tree);
    660 	MakeTreePortals_r(tree->headnode);
    661 
    662 #ifdef ME
    663 	qprintf("\n");
    664 	Log_Write("%6d nodes portalized\r\n", c_numportalizednodes);
    665 	Log_Print("%6d tiny portals\r\n", c_tinyportals);
    666 	Log_Print("%6d KB of portal memory\r\n", c_portalmemory >> 10);
    667 	Log_Print("%6i KB of winding memory\r\n", WindingMemory() >> 10);
    668 #endif //ME
    669 } //end of the function MakeTreePortals
    670 
    671 /*
    672 =========================================================
    673 
    674 FLOOD ENTITIES
    675 
    676 =========================================================
    677 */
    678 //#define P_NODESTACK
    679 
    680 node_t *p_firstnode;
    681 node_t *p_lastnode;
    682 
    683 //===========================================================================
    684 //
    685 // Parameter:				-
    686 // Returns:					-
    687 // Changes Globals:		-
    688 //===========================================================================
    689 #ifdef P_NODESTACK
    690 void P_AddNodeToList(node_t *node)
    691 {
    692 	node->next = p_firstnode;
    693 	p_firstnode = node;
    694 	if (!p_lastnode) p_lastnode = node;
    695 } //end of the function P_AddNodeToList
    696 #else //it's a node queue
    697 //add the node to the end of the node list
    698 void P_AddNodeToList(node_t *node)
    699 {
    700 	node->next = NULL;
    701 	if (p_lastnode) p_lastnode->next = node;
    702 	else p_firstnode = node;
    703 	p_lastnode = node;
    704 } //end of the function P_AddNodeToList
    705 #endif //P_NODESTACK
    706 //===========================================================================
    707 // get the first node from the front of the node list
    708 //
    709 // Parameter:				-
    710 // Returns:					-
    711 // Changes Globals:		-
    712 //===========================================================================
    713 node_t *P_NextNodeFromList(void)
    714 {
    715 	node_t *node;
    716 
    717 	node = p_firstnode;
    718 	if (p_firstnode) p_firstnode = p_firstnode->next;
    719 	if (!p_firstnode) p_lastnode = NULL;
    720 	return node;
    721 } //end of the function P_NextNodeFromList
    722 //===========================================================================
    723 //
    724 // Parameter:				-
    725 // Returns:					-
    726 // Changes Globals:		-
    727 //===========================================================================
    728 void FloodPortals(node_t *firstnode)
    729 {
    730 	node_t *node;
    731 	portal_t *p;
    732 	int s;
    733 
    734 	firstnode->occupied = 1;
    735 	P_AddNodeToList(firstnode);
    736 
    737 	for (node = P_NextNodeFromList(); node; node = P_NextNodeFromList())
    738 	{
    739 		for (p = node->portals; p; p = p->next[s])
    740 		{
    741 			s = (p->nodes[1] == node);
    742 			//if the node at the other side of the portal is occupied already
    743 			if (p->nodes[!s]->occupied) continue;
    744 			//if it isn't possible to flood through this portal
    745 			if (!Portal_EntityFlood(p, s)) continue;
    746 			//
    747 			p->nodes[!s]->occupied = node->occupied + 1;
    748 			//
    749 			P_AddNodeToList(p->nodes[!s]);
    750 		} //end for
    751 	} //end for
    752 } //end of the function FloodPortals
    753 //===========================================================================
    754 //
    755 // Parameter:				-
    756 // Returns:					-
    757 // Changes Globals:		-
    758 //===========================================================================
    759 int numrec;
    760 
    761 void FloodPortals_r (node_t *node, int dist)
    762 {
    763 	portal_t *p;
    764 	int s;
    765 //	int i;
    766 
    767 	Log_Print("\r%6d", ++numrec);
    768 
    769 	if (node->occupied) Error("FloodPortals_r: node already occupied\n");
    770 	if (!node)
    771 	{
    772 		Error("FloodPortals_r: NULL node\n");
    773 	} //end if*/
    774 	node->occupied = dist;
    775 
    776 	for (p = node->portals; p; p = p->next[s])
    777 	{
    778 		s = (p->nodes[1] == node);
    779 		//if the node at the other side of the portal is occupied already
    780 		if (p->nodes[!s]->occupied) continue;
    781 		//if it isn't possible to flood through this portal
    782 		if (!Portal_EntityFlood(p, s)) continue;
    783 		//flood recursively through the current portal
    784 		FloodPortals_r(p->nodes[!s], dist+1);
    785 	} //end for
    786 	Log_Print("\r%6d", --numrec);
    787 } //end of the function FloodPortals_r
    788 //===========================================================================
    789 //
    790 // Parameter:				-
    791 // Returns:					-
    792 // Changes Globals:		-
    793 //===========================================================================
    794 qboolean PlaceOccupant (node_t *headnode, vec3_t origin, entity_t *occupant)
    795 {
    796 	node_t *node;
    797 	vec_t	d;
    798 	plane_t *plane;
    799 
    800 	//find the leaf to start in
    801 	node = headnode;
    802 	while(node->planenum != PLANENUM_LEAF)
    803 	{
    804 		if (node->planenum < 0 || node->planenum > nummapplanes)
    805 		{
    806 			Error("PlaceOccupant: invalid node->planenum\n");
    807 		} //end if
    808 		plane = &mapplanes[node->planenum];
    809 		d = DotProduct(origin, plane->normal) - plane->dist;
    810 		if (d >= 0) node = node->children[0];
    811 		else node = node->children[1];
    812 		if (!node)
    813 		{
    814 			Error("PlaceOccupant: invalid child %d\n", d < 0);
    815 		} //end if
    816 	} //end while
    817 	//don't start in solid
    818 //	if (node->contents == CONTENTS_SOLID)
    819 	//ME: replaced because in LeafNode in brushbsp.c
    820 	//    some nodes have contents solid with other contents
    821 	if (node->contents & CONTENTS_SOLID) return false;
    822 	//if the node is already occupied
    823 	if (node->occupied) return false;
    824 
    825 	//place the occupant in the first leaf
    826 	node->occupant = occupant;
    827 
    828 	numrec = 0;
    829 //	Log_Print("%6d recurses", numrec);
    830 //	FloodPortals_r(node, 1);
    831 //	Log_Print("\n");
    832 	FloodPortals(node);
    833 
    834 	return true;
    835 } //end of the function PlaceOccupant
    836 //===========================================================================
    837 // Marks all nodes that can be reached by entites
    838 //
    839 // Parameter:				-
    840 // Returns:					-
    841 // Changes Globals:		-
    842 //===========================================================================
    843 qboolean FloodEntities (tree_t *tree)
    844 {
    845 	int i;
    846 	int x, y;
    847 	vec3_t origin;
    848 	char *cl;
    849 	qboolean inside;
    850 	node_t *headnode;
    851 
    852 	headnode = tree->headnode;
    853 	Log_Print("------ FloodEntities -------\n");
    854 	inside = false;
    855 	tree->outside_node.occupied = 0;
    856 
    857 	//start at entity 1 not the world ( = 0)
    858 	for (i = 1; i < num_entities; i++)
    859 	{
    860 		GetVectorForKey(&entities[i], "origin", origin);
    861 		if (VectorCompare(origin, vec3_origin)) continue;
    862 
    863 		cl = ValueForKey(&entities[i], "classname");
    864 		origin[2] += 1;	//so objects on floor are ok
    865 
    866 //		Log_Print("flooding from entity %d: %s\n", i, cl);
    867 		//nudge playerstart around if needed so clipping hulls allways
    868 		//have a valid point
    869 		if (!strcmp(cl, "info_player_start"))
    870 		{
    871 			for (x = -16; x <= 16; x += 16)
    872 			{
    873 				for (y = -16; y <= 16; y += 16)
    874 				{
    875 					origin[0] += x;
    876 					origin[1] += y;
    877 					if (PlaceOccupant(headnode, origin, &entities[i]))
    878 					{
    879 						inside = true;
    880 						x = 999; //stop for this info_player_start
    881 						break;
    882 					} //end if
    883 					origin[0] -= x;
    884 					origin[1] -= y;
    885 				} //end for
    886 			} //end for
    887 		} //end if
    888 		else
    889 		{
    890 			if (PlaceOccupant(headnode, origin, &entities[i]))
    891 			{
    892 				inside = true;
    893 			} //end if
    894 		} //end else
    895 	} //end for
    896 
    897 	if (!inside)
    898 	{
    899 		Log_Print("WARNING: no entities inside\n");
    900 	} //end if
    901 	else if (tree->outside_node.occupied)
    902 	{
    903 		Log_Print("WARNING: entity reached from outside\n");
    904 	} //end else if
    905 
    906 	return (qboolean)(inside && !tree->outside_node.occupied);
    907 } //end of the function FloodEntities
    908 
    909 /*
    910 =========================================================
    911 
    912 FILL OUTSIDE
    913 
    914 =========================================================
    915 */
    916 
    917 int c_outside;
    918 int c_inside;
    919 int c_solid;
    920 
    921 //===========================================================================
    922 //
    923 // Parameter:				-
    924 // Returns:					-
    925 // Changes Globals:		-
    926 //===========================================================================
    927 void FillOutside_r (node_t *node)
    928 {
    929 	if (node->planenum != PLANENUM_LEAF)
    930 	{
    931 		FillOutside_r (node->children[0]);
    932 		FillOutside_r (node->children[1]);
    933 		return;
    934 	} //end if
    935 	// anything not reachable by an entity
    936 	// can be filled away (by setting solid contents)
    937 	if (!node->occupied)
    938 	{
    939 		if (!(node->contents & CONTENTS_SOLID))
    940 		{
    941 			c_outside++;
    942 			node->contents |= CONTENTS_SOLID;
    943 		} //end if
    944 		else
    945 		{
    946 			c_solid++;
    947 		} //end else
    948 	} //end if
    949 	else
    950 	{
    951 		c_inside++;
    952 	} //end else
    953 } //end of the function FillOutside_r
    954 //===========================================================================
    955 // Fill all nodes that can't be reached by entities
    956 //
    957 // Parameter:				-
    958 // Returns:					-
    959 // Changes Globals:		-
    960 //===========================================================================
    961 void FillOutside (node_t *headnode)
    962 {
    963 	c_outside = 0;
    964 	c_inside = 0;
    965 	c_solid = 0;
    966 	Log_Print("------- FillOutside --------\n");
    967 	FillOutside_r (headnode);
    968 	Log_Print("%5i solid leaves\n", c_solid);
    969 	Log_Print("%5i leaves filled\n", c_outside);
    970 	Log_Print("%5i inside leaves\n", c_inside);
    971 } //end of the function FillOutside
    972 
    973 /*
    974 =========================================================
    975 
    976 FLOOD AREAS
    977 
    978 =========================================================
    979 */
    980 
    981 int		c_areas;
    982 
    983 //===========================================================================
    984 //
    985 // Parameter:				-
    986 // Returns:					-
    987 // Changes Globals:		-
    988 //===========================================================================
    989 void FloodAreas_r (node_t *node)
    990 {
    991 	portal_t	*p;
    992 	int			s;
    993 	bspbrush_t	*b;
    994 	entity_t	*e;
    995 
    996 	if (node->contents == CONTENTS_AREAPORTAL)
    997 	{
    998 		// this node is part of an area portal
    999 		b = node->brushlist;
   1000 		e = &entities[b->original->entitynum];
   1001 
   1002 		// if the current area has allready touched this
   1003 		// portal, we are done
   1004 		if (e->portalareas[0] == c_areas || e->portalareas[1] == c_areas)
   1005 			return;
   1006 
   1007 		// note the current area as bounding the portal
   1008 		if (e->portalareas[1])
   1009 		{
   1010 			Log_Print("WARNING: areaportal entity %i touches > 2 areas\n", b->original->entitynum);
   1011 			return;
   1012 		}
   1013 		if (e->portalareas[0])
   1014 			e->portalareas[1] = c_areas;
   1015 		else
   1016 			e->portalareas[0] = c_areas;
   1017 
   1018 		return;
   1019 	} //end if
   1020 
   1021 	if (node->area)
   1022 		return;		// allready got it
   1023 	node->area = c_areas;
   1024 
   1025 	for (p=node->portals ; p ; p = p->next[s])
   1026 	{
   1027 		s = (p->nodes[1] == node);
   1028 #if 0
   1029 		if (p->nodes[!s]->occupied)
   1030 			continue;
   1031 #endif
   1032 		if (!Portal_EntityFlood (p, s))
   1033 			continue;
   1034 
   1035 		FloodAreas_r (p->nodes[!s]);
   1036 	} //end for
   1037 } //end of the function FloodAreas_r
   1038 //===========================================================================
   1039 // Just decend the tree, and for each node that hasn't had an
   1040 // area set, flood fill out from there
   1041 //
   1042 // Parameter:				-
   1043 // Returns:					-
   1044 // Changes Globals:		-
   1045 //===========================================================================
   1046 void FindAreas_r (node_t *node)
   1047 {
   1048 	if (node->planenum != PLANENUM_LEAF)
   1049 	{
   1050 		FindAreas_r (node->children[0]);
   1051 		FindAreas_r (node->children[1]);
   1052 		return;
   1053 	}
   1054 
   1055 	if (node->area)
   1056 		return;		// allready got it
   1057 
   1058 	if (node->contents & CONTENTS_SOLID)
   1059 		return;
   1060 
   1061 	if (!node->occupied)
   1062 		return;			// not reachable by entities
   1063 
   1064 	// area portals are allways only flooded into, never
   1065 	// out of
   1066 	if (node->contents == CONTENTS_AREAPORTAL)
   1067 		return;
   1068 
   1069 	c_areas++;
   1070 	FloodAreas_r (node);
   1071 } //end of the function FindAreas_r
   1072 //===========================================================================
   1073 // Just decend the tree, and for each node that hasn't had an
   1074 // area set, flood fill out from there
   1075 //
   1076 // Parameter:				-
   1077 // Returns:					-
   1078 // Changes Globals:		-
   1079 //===========================================================================
   1080 void SetAreaPortalAreas_r (node_t *node)
   1081 {
   1082 	bspbrush_t	*b;
   1083 	entity_t	*e;
   1084 
   1085 	if (node->planenum != PLANENUM_LEAF)
   1086 	{
   1087 		SetAreaPortalAreas_r (node->children[0]);
   1088 		SetAreaPortalAreas_r (node->children[1]);
   1089 		return;
   1090 	} //end if
   1091 
   1092 	if (node->contents == CONTENTS_AREAPORTAL)
   1093 	{
   1094 		if (node->area)
   1095 			return;		// allready set
   1096 
   1097 		b = node->brushlist;
   1098 		e = &entities[b->original->entitynum];
   1099 		node->area = e->portalareas[0];
   1100 		if (!e->portalareas[1])
   1101 		{
   1102 			Log_Print("WARNING: areaportal entity %i doesn't touch two areas\n", b->original->entitynum);
   1103 			return;
   1104 		} //end if
   1105 	} //end if
   1106 } //end of the function SetAreaPortalAreas_r
   1107 //===========================================================================
   1108 //
   1109 // Parameter:				-
   1110 // Returns:					-
   1111 // Changes Globals:		-
   1112 //===========================================================================
   1113 /*
   1114 void EmitAreaPortals(node_t *headnode)
   1115 {
   1116 	int				i, j;
   1117 	entity_t		*e;
   1118 	dareaportal_t	*dp;
   1119 
   1120 	if (c_areas > MAX_MAP_AREAS)
   1121 		Error ("MAX_MAP_AREAS");
   1122 	numareas = c_areas+1;
   1123 	numareaportals = 1;		// leave 0 as an error
   1124 
   1125 	for (i=1 ; i<=c_areas ; i++)
   1126 	{
   1127 		dareas[i].firstareaportal = numareaportals;
   1128 		for (j=0 ; j<num_entities ; j++)
   1129 		{
   1130 			e = &entities[j];
   1131 			if (!e->areaportalnum)
   1132 				continue;
   1133 			dp = &dareaportals[numareaportals];
   1134 			if (e->portalareas[0] == i)
   1135 			{
   1136 				dp->portalnum = e->areaportalnum;
   1137 				dp->otherarea = e->portalareas[1];
   1138 				numareaportals++;
   1139 			} //end if
   1140 			else if (e->portalareas[1] == i)
   1141 			{
   1142 				dp->portalnum = e->areaportalnum;
   1143 				dp->otherarea = e->portalareas[0];
   1144 				numareaportals++;
   1145 			} //end else if
   1146 		} //end for
   1147 		dareas[i].numareaportals = numareaportals - dareas[i].firstareaportal;
   1148 	} //end for
   1149 
   1150 	Log_Print("%5i numareas\n", numareas);
   1151 	Log_Print("%5i numareaportals\n", numareaportals);
   1152 } //end of the function EmitAreaPortals
   1153 */
   1154 //===========================================================================
   1155 // Mark each leaf with an area, bounded by CONTENTS_AREAPORTAL
   1156 //
   1157 // Parameter:				-
   1158 // Returns:					-
   1159 // Changes Globals:		-
   1160 //===========================================================================
   1161 void FloodAreas (tree_t *tree)
   1162 {
   1163 	Log_Print("--- FloodAreas ---\n");
   1164 	FindAreas_r (tree->headnode);
   1165 	SetAreaPortalAreas_r (tree->headnode);
   1166 	Log_Print("%5i areas\n", c_areas);
   1167 } //end of the function FloodAreas
   1168 //===========================================================================
   1169 // Finds a brush side to use for texturing the given portal
   1170 //
   1171 // Parameter:				-
   1172 // Returns:					-
   1173 // Changes Globals:		-
   1174 //===========================================================================
   1175 void FindPortalSide (portal_t *p)
   1176 {
   1177 	int			viscontents;
   1178 	bspbrush_t	*bb;
   1179 	mapbrush_t	*brush;
   1180 	node_t		*n;
   1181 	int			i,j;
   1182 	int			planenum;
   1183 	side_t		*side, *bestside;
   1184 	float		dot, bestdot;
   1185 	plane_t		*p1, *p2;
   1186 
   1187 	// decide which content change is strongest
   1188 	// solid > lava > water, etc
   1189 	viscontents = VisibleContents (p->nodes[0]->contents ^ p->nodes[1]->contents);
   1190 	if (!viscontents)
   1191 		return;
   1192 
   1193 	planenum = p->onnode->planenum;
   1194 	bestside = NULL;
   1195 	bestdot = 0;
   1196 
   1197 	for (j=0 ; j<2 ; j++)
   1198 	{
   1199 		n = p->nodes[j];
   1200 		p1 = &mapplanes[p->onnode->planenum];
   1201 		for (bb=n->brushlist ; bb ; bb=bb->next)
   1202 		{
   1203 			brush = bb->original;
   1204 			if ( !(brush->contents & viscontents) )
   1205 				continue;
   1206 			for (i=0 ; i<brush->numsides ; i++)
   1207 			{
   1208 				side = &brush->original_sides[i];
   1209 				if (side->flags & SFL_BEVEL)
   1210 					continue;
   1211 				if (side->texinfo == TEXINFO_NODE)
   1212 					continue;		// non-visible
   1213 				if ((side->planenum&~1) == planenum)
   1214 				{	// exact match
   1215 					bestside = &brush->original_sides[i];
   1216 					goto gotit;
   1217 				} //end if
   1218 				// see how close the match is
   1219 				p2 = &mapplanes[side->planenum&~1];
   1220 				dot = DotProduct (p1->normal, p2->normal);
   1221 				if (dot > bestdot)
   1222 				{
   1223 					bestdot = dot;
   1224 					bestside = side;
   1225 				} //end if
   1226 			} //end for
   1227 		} //end for
   1228 	} //end for
   1229 
   1230 gotit:
   1231 	if (!bestside)
   1232 		Log_Print("WARNING: side not found for portal\n");
   1233 
   1234 	p->sidefound = true;
   1235 	p->side = bestside;
   1236 } //end of the function FindPortalSide
   1237 //===========================================================================
   1238 //
   1239 // Parameter:				-
   1240 // Returns:					-
   1241 // Changes Globals:		-
   1242 //===========================================================================
   1243 void MarkVisibleSides_r (node_t *node)
   1244 {
   1245 	portal_t *p;
   1246 	int s;
   1247 
   1248 	if (node->planenum != PLANENUM_LEAF)
   1249 	{
   1250 		MarkVisibleSides_r (node->children[0]);
   1251 		MarkVisibleSides_r (node->children[1]);
   1252 		return;
   1253 	} //end if
   1254 
   1255 	// empty leaves are never boundary leaves
   1256 	if (!node->contents) return;
   1257 
   1258 	// see if there is a visible face
   1259 	for (p=node->portals ; p ; p = p->next[!s])
   1260 	{
   1261 		s = (p->nodes[0] == node);
   1262 		if (!p->onnode)
   1263 			continue;		// edge of world
   1264 		if (!p->sidefound)
   1265 			FindPortalSide (p);
   1266 		if (p->side)
   1267 			p->side->flags |= SFL_VISIBLE;
   1268 	} //end for
   1269 } //end of the function MarkVisibleSides_r
   1270 //===========================================================================
   1271 //
   1272 // Parameter:				-
   1273 // Returns:					-
   1274 // Changes Globals:		-
   1275 //===========================================================================
   1276 void MarkVisibleSides(tree_t *tree, int startbrush, int endbrush)
   1277 {
   1278 	int		i, j;
   1279 	mapbrush_t	*mb;
   1280 	int		numsides;
   1281 
   1282 	Log_Print("--- MarkVisibleSides ---\n");
   1283 
   1284 	// clear all the visible flags
   1285 	for (i=startbrush ; i<endbrush ; i++)
   1286 	{
   1287 		mb = &mapbrushes[i];
   1288 
   1289 		numsides = mb->numsides;
   1290 		for (j=0 ; j<numsides ; j++)
   1291 			mb->original_sides[j].flags &= ~SFL_VISIBLE;
   1292 	}
   1293 
   1294 	// set visible flags on the sides that are used by portals
   1295 	MarkVisibleSides_r (tree->headnode);
   1296 } //end of the function MarkVisibleSides
   1297