DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

AASFile_sample.cpp (15518B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #pragma hdrstop
     30 #include "../idlib/precompiled.h"
     31 
     32 
     33 #include "AASFile.h"
     34 #include "AASFile_local.h"
     35 
     36 
     37 //===============================================================
     38 //
     39 //	Environment Sampling
     40 //
     41 //===============================================================
     42 
     43 /*
     44 ================
     45 idAASFileLocal::EdgeCenter
     46 ================
     47 */
     48 idVec3 idAASFileLocal::EdgeCenter( int edgeNum ) const {
     49 	const aasEdge_t *edge;
     50 	edge = &edges[edgeNum];
     51 	return ( vertices[edge->vertexNum[0]] + vertices[edge->vertexNum[1]] ) * 0.5f;
     52 }
     53 
     54 /*
     55 ================
     56 idAASFileLocal::FaceCenter
     57 ================
     58 */
     59 idVec3 idAASFileLocal::FaceCenter( int faceNum ) const {
     60 	int i, edgeNum;
     61 	const aasFace_t *face;
     62 	const aasEdge_t *edge;
     63 	idVec3 center;
     64 
     65 	center = vec3_origin;
     66 
     67 	face = &faces[faceNum];
     68 	if ( face->numEdges > 0 ) {
     69 		for ( i = 0; i < face->numEdges; i++ ) {
     70 			edgeNum = edgeIndex[ face->firstEdge + i ];
     71 			edge = &edges[ abs( edgeNum ) ];
     72 			center += vertices[ edge->vertexNum[ INT32_SIGNBITSET(edgeNum) ] ];
     73 		}
     74 		center /= face->numEdges;
     75 	}
     76 	return center;
     77 }
     78 
     79 /*
     80 ================
     81 idAASFileLocal::AreaCenter
     82 ================
     83 */
     84 idVec3 idAASFileLocal::AreaCenter( int areaNum ) const {
     85 	int i, faceNum;
     86 	const aasArea_t *area;
     87 	idVec3 center;
     88 
     89 	center = vec3_origin;
     90 
     91 	area = &areas[areaNum];
     92 	if ( area->numFaces > 0 ) {
     93 		for ( i = 0; i < area->numFaces; i++ ) {
     94 			faceNum = faceIndex[area->firstFace + i];
     95 			center += FaceCenter( abs(faceNum) );
     96 		}
     97 		center /= area->numFaces;
     98 	}
     99 	return center;
    100 }
    101 
    102 /*
    103 ============
    104 idAASFileLocal::AreaReachableGoal
    105 ============
    106 */
    107 idVec3 idAASFileLocal::AreaReachableGoal( int areaNum ) const {
    108 	int i, faceNum, numFaces;
    109 	const aasArea_t *area;
    110 	idVec3 center;
    111 	idVec3 start, end;
    112 	aasTrace_t trace;
    113 
    114 	area = &areas[areaNum];
    115 
    116 	if ( !(area->flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY)) || (area->flags & AREA_LIQUID) ) {
    117 		return AreaCenter( areaNum );
    118 	}
    119 
    120 	center = vec3_origin;
    121 
    122 	numFaces = 0;
    123 	for ( i = 0; i < area->numFaces; i++ ) {
    124 		faceNum = faceIndex[area->firstFace + i];
    125 		if ( !(faces[abs(faceNum)].flags & FACE_FLOOR) ) {
    126 			continue;
    127 		}
    128 		center += FaceCenter( abs(faceNum) );
    129 		numFaces++;
    130 	}
    131 	if ( numFaces > 0 ) {
    132 		center /= numFaces;
    133 	}
    134 	center[2] += 1.0f;
    135 	end = center;
    136 	end[2] -= 1024;
    137 	Trace( trace, center, end );
    138 
    139 	return trace.endpos;
    140 }
    141 
    142 /*
    143 ================
    144 idAASFileLocal::EdgeBounds
    145 ================
    146 */
    147 idBounds idAASFileLocal::EdgeBounds( int edgeNum ) const {
    148 	const aasEdge_t *edge;
    149 	idBounds bounds;
    150 
    151 	edge = &edges[ abs( edgeNum ) ];
    152 	bounds[0] = bounds[1] = vertices[ edge->vertexNum[0] ];
    153 	bounds += vertices[ edge->vertexNum[1] ];
    154 	return bounds;
    155 }
    156 
    157 /*
    158 ================
    159 idAASFileLocal::FaceBounds
    160 ================
    161 */
    162 idBounds idAASFileLocal::FaceBounds( int faceNum ) const {
    163 	int i, edgeNum;
    164 	const aasFace_t *face;
    165 	const aasEdge_t *edge;
    166 	idBounds bounds;
    167 
    168 	face = &faces[faceNum];
    169 	bounds.Clear();
    170 
    171 	for ( i = 0; i < face->numEdges; i++ ) {
    172 		edgeNum = edgeIndex[ face->firstEdge + i ];
    173 		edge = &edges[ abs( edgeNum ) ];
    174 		bounds.AddPoint( vertices[ edge->vertexNum[ INT32_SIGNBITSET(edgeNum) ] ] );
    175 	}
    176 	return bounds;
    177 }
    178 
    179 /*
    180 ================
    181 idAASFileLocal::AreaBounds
    182 ================
    183 */
    184 idBounds idAASFileLocal::AreaBounds( int areaNum ) const {
    185 	int i, faceNum;
    186 	const aasArea_t *area;
    187 	idBounds bounds;
    188 
    189 	area = &areas[areaNum];
    190 	bounds.Clear();
    191 
    192 	for ( i = 0; i < area->numFaces; i++ ) {
    193 		faceNum = faceIndex[area->firstFace + i];
    194 		bounds += FaceBounds( abs(faceNum) );
    195 	}
    196 	return bounds;
    197 }
    198 
    199 /*
    200 ============
    201 idAASFileLocal::PointAreaNum
    202 ============
    203 */
    204 int idAASFileLocal::PointAreaNum( const idVec3 &origin ) const {
    205 	int nodeNum;
    206 	const aasNode_t *node;
    207 
    208 	nodeNum = 1;
    209 	do {
    210 		node = &nodes[nodeNum];
    211 		if ( planeList[node->planeNum].Side( origin ) == PLANESIDE_BACK ) {
    212 			nodeNum = node->children[1];
    213 		}
    214 		else {
    215 			nodeNum = node->children[0];
    216 		}
    217 		if ( nodeNum < 0 ) {
    218 			return -nodeNum;
    219 		}
    220 	} while( nodeNum );
    221 
    222 	return 0;
    223 }
    224 
    225 /*
    226 ============
    227 idAASFileLocal::PointReachableAreaNum
    228 ============
    229 */
    230 int idAASFileLocal::PointReachableAreaNum( const idVec3 &origin, const idBounds &searchBounds, const int areaFlags, const int excludeTravelFlags ) const {
    231 	int areaList[32], areaNum, i;
    232 	idVec3 start, end, pointList[32];
    233 	aasTrace_t trace;
    234 	idBounds bounds;
    235 	float frac;
    236 
    237 	start = origin;
    238 
    239 	trace.areas = areaList;
    240 	trace.points = pointList;
    241 	trace.maxAreas = sizeof( areaList ) / sizeof( int );
    242 	trace.getOutOfSolid = true;
    243 
    244 	areaNum = PointAreaNum( start );
    245 	if ( areaNum ) {
    246 		if ( ( areas[areaNum].flags & areaFlags ) && ( ( areas[areaNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
    247 			return areaNum;
    248 		}
    249 	}
    250 	else {
    251 		// trace up
    252 		end = start;
    253 		end[2] += 32.0f;
    254 		Trace( trace, start, end );
    255 		if ( trace.numAreas >= 1 ) {
    256 			if ( ( areas[0].flags & areaFlags ) && ( ( areas[0].travelFlags & excludeTravelFlags ) == 0 ) ) {
    257 				return areaList[0];
    258 			}
    259 			start = pointList[0];
    260 			start[2] += 1.0f;
    261 		}
    262 	}
    263 
    264 	// trace down
    265 	end = start;
    266 	end[2] -= 32.0f;
    267 	Trace( trace, start, end );
    268 	if ( trace.lastAreaNum ) {
    269 		if ( ( areas[trace.lastAreaNum].flags & areaFlags ) && ( ( areas[trace.lastAreaNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
    270 			return trace.lastAreaNum;
    271 		}
    272 		start = trace.endpos;
    273 	}
    274 
    275 	// expand bounds until an area is found
    276 	for ( i = 1; i <= 12; i++ ) {
    277 		frac = i * ( 1.0f / 12.0f );
    278 		bounds[0] = origin + searchBounds[0] * frac;
    279 		bounds[1] = origin + searchBounds[1] * frac;
    280 		areaNum = BoundsReachableAreaNum( bounds, areaFlags, excludeTravelFlags );
    281 		if ( areaNum && ( areas[areaNum].flags & areaFlags ) && ( ( areas[areaNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
    282 			return areaNum;
    283 		}
    284 	}
    285 	return 0;
    286 }
    287 
    288 /*
    289 ============
    290 idAASFileLocal::BoundsReachableAreaNum_r
    291 ============
    292 */
    293 int idAASFileLocal::BoundsReachableAreaNum_r( int nodeNum, const idBounds &bounds, const int areaFlags, const int excludeTravelFlags ) const {
    294 	int res;
    295 	const aasNode_t *node;
    296 
    297 	while( nodeNum ) {
    298 		if ( nodeNum < 0 ) {
    299 			if ( ( areas[-nodeNum].flags & areaFlags ) && ( ( areas[-nodeNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
    300 				return -nodeNum;
    301 			}
    302 			return 0;
    303 		}
    304 		node = &nodes[nodeNum];
    305 		res = bounds.PlaneSide( planeList[node->planeNum] );
    306 		if ( res == PLANESIDE_BACK ) {
    307 			nodeNum = node->children[1];
    308 		}
    309 		else if ( res == PLANESIDE_FRONT ) {
    310 			nodeNum = node->children[0];
    311 		}
    312 		else {
    313 			nodeNum = BoundsReachableAreaNum_r( node->children[1], bounds, areaFlags, excludeTravelFlags );
    314 			if ( nodeNum ) {
    315 				return nodeNum;
    316 			}
    317 			nodeNum = node->children[0];
    318 		}
    319 	}
    320 
    321 	return 0;
    322 }
    323 
    324 /*
    325 ============
    326 idAASFileLocal::BoundsReachableAreaNum
    327 ============
    328 */
    329 int idAASFileLocal::BoundsReachableAreaNum( const idBounds &bounds, const int areaFlags, const int excludeTravelFlags ) const {
    330 
    331 	return BoundsReachableAreaNum_r( 1, bounds, areaFlags, excludeTravelFlags );
    332 }
    333 
    334 /*
    335 ============
    336 idAASFileLocal::PushPointIntoAreaNum
    337 ============
    338 */
    339 void idAASFileLocal::PushPointIntoAreaNum( int areaNum, idVec3 &point ) const {
    340 	int i, faceNum;
    341 	const aasArea_t *area;
    342 	const aasFace_t *face;
    343 
    344 	area = &areas[areaNum];
    345 
    346 	// push the point to the right side of all area face planes
    347 	for ( i = 0; i < area->numFaces; i++ ) {
    348 		faceNum = faceIndex[area->firstFace + i];
    349 		face = &faces[abs( faceNum )];
    350 
    351 		const idPlane &plane = planeList[face->planeNum ^ INT32_SIGNBITSET( faceNum )];
    352 		float dist = plane.Distance( point );
    353 
    354 		// project the point onto the face plane if it is on the wrong side
    355 		if ( dist < 0.0f ) {
    356 			point -= dist * plane.Normal();
    357 		}
    358 	}
    359 }
    360 
    361 /*
    362 ============
    363 idAASFileLocal::Trace
    364 ============
    365 */
    366 #define TRACEPLANE_EPSILON		0.125f
    367 
    368 typedef struct aasTraceStack_s
    369 {
    370 	idVec3			start;
    371 	idVec3			end;
    372 	int				planeNum;
    373 	int				nodeNum;
    374 } aasTraceStack_t;
    375 
    376 bool idAASFileLocal::Trace( aasTrace_t &trace, const idVec3 &start, const idVec3 &end ) const {
    377 	int side, nodeNum, tmpPlaneNum;
    378 	double front, back, frac;
    379 	idVec3 cur_start, cur_end, cur_mid, v1, v2;
    380 	aasTraceStack_t tracestack[MAX_AAS_TREE_DEPTH];
    381 	aasTraceStack_t *tstack_p;
    382 	const aasNode_t *node;
    383 	const idPlane *plane;
    384 
    385 	trace.numAreas = 0;
    386 	trace.lastAreaNum = 0;
    387 	trace.blockingAreaNum = 0;
    388 
    389 	tstack_p = tracestack;
    390 	tstack_p->start = start;
    391 	tstack_p->end = end;
    392 	tstack_p->planeNum = 0;
    393 	tstack_p->nodeNum = 1;		//start with the root of the tree
    394 	tstack_p++;
    395 	
    396 	while( 1 ) {
    397 
    398 		tstack_p--;
    399 		// if the trace stack is empty
    400 		if ( tstack_p < tracestack ) {
    401 			if ( !trace.lastAreaNum ) {
    402 				// completely in solid
    403 				trace.fraction = 0.0f;
    404 				trace.endpos = start;
    405 			}
    406 			else {
    407 				// nothing was hit
    408 				trace.fraction = 1.0f;
    409 				trace.endpos = end;
    410 			}
    411 			trace.planeNum = 0;
    412 			return false;
    413 		}
    414 
    415 		// number of the current node to test the line against
    416 		nodeNum = tstack_p->nodeNum;
    417 
    418 		// if it is an area
    419 		if ( nodeNum < 0) {
    420 			// if can't enter the area
    421 			if ( ( areas[-nodeNum].flags & trace.flags ) || ( areas[-nodeNum].travelFlags & trace.travelFlags ) ) {
    422 				if ( !trace.lastAreaNum ) {
    423 					trace.fraction = 0.0f;
    424 					v1 = vec3_origin;
    425 				} else {
    426 					v1 = end - start;
    427 					v2 = tstack_p->start - start;
    428 					trace.fraction = v2.Length() / v1.Length();
    429 				}
    430 				trace.endpos = tstack_p->start;
    431 				trace.blockingAreaNum = -nodeNum;
    432 				trace.planeNum = tstack_p->planeNum;
    433 				// always take the plane with normal facing towards the trace start
    434 				plane = &planeList[trace.planeNum];
    435 				if ( v1 * plane->Normal() > 0.0f ) {
    436 					trace.planeNum ^= 1;
    437 				}
    438 				return true;
    439 			}
    440 			trace.lastAreaNum = -nodeNum;
    441 			if ( trace.numAreas < trace.maxAreas ) {
    442 				if ( trace.areas ) {
    443 					trace.areas[trace.numAreas] = -nodeNum;
    444 				}
    445 				if ( trace.points ) {
    446 					trace.points[trace.numAreas] = tstack_p->start;
    447 				}
    448 				trace.numAreas++;
    449 			}
    450 			continue;
    451 		}
    452 
    453 		// if it is a solid leaf
    454 		if ( !nodeNum ) {
    455 			if ( !trace.lastAreaNum ) {
    456 				trace.fraction = 0.0f;
    457 				v1 = vec3_origin;
    458 			} else {
    459 				v1 = end - start;
    460 				v2 = tstack_p->start - start;
    461 				trace.fraction = v2.Length() / v1.Length();
    462 			}
    463 			trace.endpos = tstack_p->start;
    464 			trace.blockingAreaNum = 0;	// hit solid leaf
    465 			trace.planeNum = tstack_p->planeNum;
    466 			// always take the plane with normal facing towards the trace start
    467 			plane = &planeList[trace.planeNum];
    468 			if ( v1 * plane->Normal() > 0.0f ) {
    469 				trace.planeNum ^= 1;
    470 			}
    471 			if ( !trace.lastAreaNum && trace.getOutOfSolid ) {
    472 				continue;
    473 			}
    474 			else {
    475 				return true;
    476 			}
    477 		}
    478 
    479 		// the node to test against
    480 		node = &nodes[nodeNum];
    481 		// start point of current line to test against node
    482 		cur_start = tstack_p->start;
    483 		// end point of the current line to test against node
    484 		cur_end = tstack_p->end;
    485 		// the current node plane
    486 		plane = &planeList[node->planeNum];
    487 
    488 		front = plane->Distance( cur_start );
    489 		back = plane->Distance( cur_end );
    490 
    491 		// if the whole to be traced line is totally at the front of this node
    492 		// only go down the tree with the front child
    493 		if ( front >= -ON_EPSILON && back >= -ON_EPSILON ) {
    494 			// keep the current start and end point on the stack and go down the tree with the front child
    495 			tstack_p->nodeNum = node->children[0];
    496 			tstack_p++;
    497 			if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
    498 				common->Error("idAASFileLocal::Trace: stack overflow\n" );
    499 				return false;
    500 			}
    501 		}
    502 		// if the whole to be traced line is totally at the back of this node
    503 		// only go down the tree with the back child
    504 		else if ( front < ON_EPSILON && back < ON_EPSILON ) {
    505 			// keep the current start and end point on the stack and go down the tree with the back child
    506 			tstack_p->nodeNum = node->children[1];
    507 			tstack_p++;
    508 			if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
    509 				common->Error("idAASFileLocal::Trace: stack overflow\n" );
    510 				return false;
    511 			}
    512 		}
    513 		// go down the tree both at the front and back of the node
    514 		else {
    515 			tmpPlaneNum = tstack_p->planeNum;
    516 			// calculate the hit point with the node plane
    517 			// put the cross point TRACEPLANE_EPSILON on the near side
    518 			if (front < 0) {
    519 				frac = (front + TRACEPLANE_EPSILON) / ( front - back );
    520 			}
    521 			else {
    522 				frac = (front - TRACEPLANE_EPSILON) / ( front - back );
    523 			}
    524 
    525 			if (frac < 0) {
    526 				frac = 0.001f; //0
    527 			}
    528 			else if (frac > 1) {
    529 				frac = 0.999f; //1
    530 			}
    531 
    532 			cur_mid = cur_start + ( cur_end - cur_start ) * frac;
    533 
    534 			// side the front part of the line is on
    535 			side = front < 0;
    536 
    537 			// first put the end part of the line on the stack (back side)
    538 			tstack_p->start = cur_mid;
    539 			tstack_p->planeNum = node->planeNum;
    540 			tstack_p->nodeNum = node->children[!side];
    541 			tstack_p++;
    542 			if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
    543 				common->Error("idAASFileLocal::Trace: stack overflow\n" );
    544 				return false;
    545 			}
    546 			// now put the part near the start of the line on the stack so we will
    547 			// continue with that part first.
    548 			tstack_p->start = cur_start;
    549 			tstack_p->end = cur_mid;
    550 			tstack_p->planeNum = tmpPlaneNum;
    551 			tstack_p->nodeNum = node->children[side];
    552 			tstack_p++;
    553 			if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
    554 				common->Error("idAASFileLocal::Trace: stack overflow\n" );
    555 				return false;
    556 			}
    557 		}
    558 	}
    559 	return false;
    560 }
    561 
    562 /*
    563 ============
    564 idAASLocal::AreaContentsTravelFlags
    565 ============
    566 */
    567 int idAASFileLocal::AreaContentsTravelFlags( int areaNum ) const {
    568 	if ( areas[areaNum].contents & AREACONTENTS_WATER ) {
    569 		return TFL_WATER;
    570 	}
    571 	return TFL_AIR;
    572 }
    573 
    574 /*
    575 ============
    576 idAASFileLocal::MaxTreeDepth_r
    577 ============
    578 */
    579 void idAASFileLocal::MaxTreeDepth_r( int nodeNum, int &depth, int &maxDepth ) const {
    580 	const aasNode_t *node;
    581 
    582 	if ( nodeNum <= 0 ) {
    583 		return;
    584 	}
    585 
    586 	depth++;
    587 	if ( depth > maxDepth ) {
    588 		maxDepth = depth;
    589 	}
    590 
    591 	node = &nodes[nodeNum];
    592 	MaxTreeDepth_r( node->children[0], depth, maxDepth );
    593 	MaxTreeDepth_r( node->children[1], depth, maxDepth );
    594 
    595 	depth--;
    596 }
    597 
    598 /*
    599 ============
    600 idAASFileLocal::MaxTreeDepth
    601 ============
    602 */
    603 int idAASFileLocal::MaxTreeDepth() const {
    604 	int depth, maxDepth;
    605 
    606 	depth = maxDepth = 0;
    607 	MaxTreeDepth_r( 1, depth, maxDepth );
    608 	return maxDepth;
    609 }