2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 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.
14 Doom 3 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.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 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 Source Code. If not, please request a copy in writing from id Software at the address below.
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.
26 ===========================================================================
29 #include "../../../idlib/precompiled.h"
33 #include "AASFile_local.h"
36 //===============================================================
38 // Environment Sampling
40 //===============================================================
44 idAASFileLocal::EdgeCenter
47 idVec3 idAASFileLocal::EdgeCenter( int edgeNum ) const {
48 const aasEdge_t *edge;
49 edge = &edges[edgeNum];
50 return ( vertices[edge->vertexNum[0]] + vertices[edge->vertexNum[1]] ) * 0.5f;
55 idAASFileLocal::FaceCenter
58 idVec3 idAASFileLocal::FaceCenter( int faceNum ) const {
60 const aasFace_t *face;
61 const aasEdge_t *edge;
66 face = &faces[faceNum];
67 if ( face->numEdges > 0 ) {
68 for ( i = 0; i < face->numEdges; i++ ) {
69 edgeNum = edgeIndex[ face->firstEdge + i ];
70 edge = &edges[ abs( edgeNum ) ];
71 center += vertices[ edge->vertexNum[ INTSIGNBITSET(edgeNum) ] ];
73 center /= face->numEdges;
80 idAASFileLocal::AreaCenter
83 idVec3 idAASFileLocal::AreaCenter( int areaNum ) const {
85 const aasArea_t *area;
90 area = &areas[areaNum];
91 if ( area->numFaces > 0 ) {
92 for ( i = 0; i < area->numFaces; i++ ) {
93 faceNum = faceIndex[area->firstFace + i];
94 center += FaceCenter( abs(faceNum) );
96 center /= area->numFaces;
103 idAASFileLocal::AreaReachableGoal
106 idVec3 idAASFileLocal::AreaReachableGoal( int areaNum ) const {
107 int i, faceNum, numFaces;
108 const aasArea_t *area;
113 area = &areas[areaNum];
115 if ( !(area->flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY)) || (area->flags & AREA_LIQUID) ) {
116 return AreaCenter( areaNum );
119 center = vec3_origin;
122 for ( i = 0; i < area->numFaces; i++ ) {
123 faceNum = faceIndex[area->firstFace + i];
124 if ( !(faces[abs(faceNum)].flags & FACE_FLOOR) ) {
127 center += FaceCenter( abs(faceNum) );
130 if ( numFaces > 0 ) {
136 Trace( trace, center, end );
143 idAASFileLocal::EdgeBounds
146 idBounds idAASFileLocal::EdgeBounds( int edgeNum ) const {
147 const aasEdge_t *edge;
150 edge = &edges[ abs( edgeNum ) ];
151 bounds[0] = bounds[1] = vertices[ edge->vertexNum[0] ];
152 bounds += vertices[ edge->vertexNum[1] ];
158 idAASFileLocal::FaceBounds
161 idBounds idAASFileLocal::FaceBounds( int faceNum ) const {
163 const aasFace_t *face;
164 const aasEdge_t *edge;
167 face = &faces[faceNum];
170 for ( i = 0; i < face->numEdges; i++ ) {
171 edgeNum = edgeIndex[ face->firstEdge + i ];
172 edge = &edges[ abs( edgeNum ) ];
173 bounds.AddPoint( vertices[ edge->vertexNum[ INTSIGNBITSET(edgeNum) ] ] );
180 idAASFileLocal::AreaBounds
183 idBounds idAASFileLocal::AreaBounds( int areaNum ) const {
185 const aasArea_t *area;
188 area = &areas[areaNum];
191 for ( i = 0; i < area->numFaces; i++ ) {
192 faceNum = faceIndex[area->firstFace + i];
193 bounds += FaceBounds( abs(faceNum) );
200 idAASFileLocal::PointAreaNum
203 int idAASFileLocal::PointAreaNum( const idVec3 &origin ) const {
205 const aasNode_t *node;
209 node = &nodes[nodeNum];
210 if ( planeList[node->planeNum].Side( origin ) == PLANESIDE_BACK ) {
211 nodeNum = node->children[1];
214 nodeNum = node->children[0];
226 idAASFileLocal::PointReachableAreaNum
229 int idAASFileLocal::PointReachableAreaNum( const idVec3 &origin, const idBounds &searchBounds, const int areaFlags, const int excludeTravelFlags ) const {
230 int areaList[32], areaNum, i;
231 idVec3 start, end, pointList[32];
238 trace.areas = areaList;
239 trace.points = pointList;
240 trace.maxAreas = sizeof( areaList ) / sizeof( int );
241 trace.getOutOfSolid = true;
243 areaNum = PointAreaNum( start );
245 if ( ( areas[areaNum].flags & areaFlags ) && ( ( areas[areaNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
253 Trace( trace, start, end );
254 if ( trace.numAreas >= 1 ) {
255 if ( ( areas[0].flags & areaFlags ) && ( ( areas[0].travelFlags & excludeTravelFlags ) == 0 ) ) {
258 start = pointList[0];
266 Trace( trace, start, end );
267 if ( trace.lastAreaNum ) {
268 if ( ( areas[trace.lastAreaNum].flags & areaFlags ) && ( ( areas[trace.lastAreaNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
269 return trace.lastAreaNum;
271 start = trace.endpos;
274 // expand bounds until an area is found
275 for ( i = 1; i <= 12; i++ ) {
276 frac = i * ( 1.0f / 12.0f );
277 bounds[0] = origin + searchBounds[0] * frac;
278 bounds[1] = origin + searchBounds[1] * frac;
279 areaNum = BoundsReachableAreaNum( bounds, areaFlags, excludeTravelFlags );
280 if ( areaNum && ( areas[areaNum].flags & areaFlags ) && ( ( areas[areaNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
289 idAASFileLocal::BoundsReachableAreaNum_r
292 int idAASFileLocal::BoundsReachableAreaNum_r( int nodeNum, const idBounds &bounds, const int areaFlags, const int excludeTravelFlags ) const {
294 const aasNode_t *node;
298 if ( ( areas[-nodeNum].flags & areaFlags ) && ( ( areas[-nodeNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
303 node = &nodes[nodeNum];
304 res = bounds.PlaneSide( planeList[node->planeNum] );
305 if ( res == PLANESIDE_BACK ) {
306 nodeNum = node->children[1];
308 else if ( res == PLANESIDE_FRONT ) {
309 nodeNum = node->children[0];
312 nodeNum = BoundsReachableAreaNum_r( node->children[1], bounds, areaFlags, excludeTravelFlags );
316 nodeNum = node->children[0];
325 idAASFileLocal::BoundsReachableAreaNum
328 int idAASFileLocal::BoundsReachableAreaNum( const idBounds &bounds, const int areaFlags, const int excludeTravelFlags ) const {
330 return BoundsReachableAreaNum_r( 1, bounds, areaFlags, excludeTravelFlags );
335 idAASFileLocal::PushPointIntoAreaNum
338 void idAASFileLocal::PushPointIntoAreaNum( int areaNum, idVec3 &point ) const {
340 const aasArea_t *area;
341 const aasFace_t *face;
343 area = &areas[areaNum];
345 // push the point to the right side of all area face planes
346 for ( i = 0; i < area->numFaces; i++ ) {
347 faceNum = faceIndex[area->firstFace + i];
348 face = &faces[abs( faceNum )];
350 const idPlane &plane = planeList[face->planeNum ^ INTSIGNBITSET( faceNum )];
351 float dist = plane.Distance( point );
353 // project the point onto the face plane if it is on the wrong side
355 point -= dist * plane.Normal();
362 idAASFileLocal::Trace
365 #define TRACEPLANE_EPSILON 0.125f
367 typedef struct aasTraceStack_s
375 bool idAASFileLocal::Trace( aasTrace_t &trace, const idVec3 &start, const idVec3 &end ) const {
376 int side, nodeNum, tmpPlaneNum;
377 double front, back, frac;
378 idVec3 cur_start, cur_end, cur_mid, v1, v2;
379 aasTraceStack_t tracestack[MAX_AAS_TREE_DEPTH];
380 aasTraceStack_t *tstack_p;
381 const aasNode_t *node;
382 const idPlane *plane;
385 trace.lastAreaNum = 0;
386 trace.blockingAreaNum = 0;
388 tstack_p = tracestack;
389 tstack_p->start = start;
391 tstack_p->planeNum = 0;
392 tstack_p->nodeNum = 1; //start with the root of the tree
398 // if the trace stack is empty
399 if ( tstack_p < tracestack ) {
400 if ( !trace.lastAreaNum ) {
401 // completely in solid
402 trace.fraction = 0.0f;
403 trace.endpos = start;
407 trace.fraction = 1.0f;
414 // number of the current node to test the line against
415 nodeNum = tstack_p->nodeNum;
419 // if can't enter the area
420 if ( ( areas[-nodeNum].flags & trace.flags ) || ( areas[-nodeNum].travelFlags & trace.travelFlags ) ) {
421 if ( !trace.lastAreaNum ) {
422 trace.fraction = 0.0f;
426 v2 = tstack_p->start - start;
427 trace.fraction = v2.Length() / v1.Length();
429 trace.endpos = tstack_p->start;
430 trace.blockingAreaNum = -nodeNum;
431 trace.planeNum = tstack_p->planeNum;
432 // always take the plane with normal facing towards the trace start
433 plane = &planeList[trace.planeNum];
434 if ( v1 * plane->Normal() > 0.0f ) {
439 trace.lastAreaNum = -nodeNum;
440 if ( trace.numAreas < trace.maxAreas ) {
442 trace.areas[trace.numAreas] = -nodeNum;
444 if ( trace.points ) {
445 trace.points[trace.numAreas] = tstack_p->start;
452 // if it is a solid leaf
454 if ( !trace.lastAreaNum ) {
455 trace.fraction = 0.0f;
459 v2 = tstack_p->start - start;
460 trace.fraction = v2.Length() / v1.Length();
462 trace.endpos = tstack_p->start;
463 trace.blockingAreaNum = 0; // hit solid leaf
464 trace.planeNum = tstack_p->planeNum;
465 // always take the plane with normal facing towards the trace start
466 plane = &planeList[trace.planeNum];
467 if ( v1 * plane->Normal() > 0.0f ) {
470 if ( !trace.lastAreaNum && trace.getOutOfSolid ) {
478 // the node to test against
479 node = &nodes[nodeNum];
480 // start point of current line to test against node
481 cur_start = tstack_p->start;
482 // end point of the current line to test against node
483 cur_end = tstack_p->end;
484 // the current node plane
485 plane = &planeList[node->planeNum];
487 front = plane->Distance( cur_start );
488 back = plane->Distance( cur_end );
490 // if the whole to be traced line is totally at the front of this node
491 // only go down the tree with the front child
492 if ( front >= -ON_EPSILON && back >= -ON_EPSILON ) {
493 // keep the current start and end point on the stack and go down the tree with the front child
494 tstack_p->nodeNum = node->children[0];
496 if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
497 common->Error("idAASFileLocal::Trace: stack overflow\n" );
501 // if the whole to be traced line is totally at the back of this node
502 // only go down the tree with the back child
503 else if ( front < ON_EPSILON && back < ON_EPSILON ) {
504 // keep the current start and end point on the stack and go down the tree with the back child
505 tstack_p->nodeNum = node->children[1];
507 if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
508 common->Error("idAASFileLocal::Trace: stack overflow\n" );
512 // go down the tree both at the front and back of the node
514 tmpPlaneNum = tstack_p->planeNum;
515 // calculate the hit point with the node plane
516 // put the cross point TRACEPLANE_EPSILON on the near side
518 frac = (front + TRACEPLANE_EPSILON) / ( front - back );
521 frac = (front - TRACEPLANE_EPSILON) / ( front - back );
531 cur_mid = cur_start + ( cur_end - cur_start ) * frac;
533 // side the front part of the line is on
536 // first put the end part of the line on the stack (back side)
537 tstack_p->start = cur_mid;
538 tstack_p->planeNum = node->planeNum;
539 tstack_p->nodeNum = node->children[!side];
541 if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
542 common->Error("idAASFileLocal::Trace: stack overflow\n" );
545 // now put the part near the start of the line on the stack so we will
546 // continue with that part first.
547 tstack_p->start = cur_start;
548 tstack_p->end = cur_mid;
549 tstack_p->planeNum = tmpPlaneNum;
550 tstack_p->nodeNum = node->children[side];
552 if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
553 common->Error("idAASFileLocal::Trace: stack overflow\n" );
563 idAASLocal::AreaContentsTravelFlags
566 int idAASFileLocal::AreaContentsTravelFlags( int areaNum ) const {
567 if ( areas[areaNum].contents & AREACONTENTS_WATER ) {
575 idAASFileLocal::MaxTreeDepth_r
578 void idAASFileLocal::MaxTreeDepth_r( int nodeNum, int &depth, int &maxDepth ) const {
579 const aasNode_t *node;
581 if ( nodeNum <= 0 ) {
586 if ( depth > maxDepth ) {
590 node = &nodes[nodeNum];
591 MaxTreeDepth_r( node->children[0], depth, maxDepth );
592 MaxTreeDepth_r( node->children[1], depth, maxDepth );
599 idAASFileLocal::MaxTreeDepth
602 int idAASFileLocal::MaxTreeDepth( void ) const {
605 depth = maxDepth = 0;
606 MaxTreeDepth_r( 1, depth, maxDepth );