123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- 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.
- 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.
- ===========================================================================
- */
- #pragma hdrstop
- #include "../idlib/precompiled.h"
- #include "AASFile.h"
- #include "AASFile_local.h"
- //===============================================================
- //
- // Environment Sampling
- //
- //===============================================================
- /*
- ================
- idAASFileLocal::EdgeCenter
- ================
- */
- idVec3 idAASFileLocal::EdgeCenter( int edgeNum ) const {
- const aasEdge_t *edge;
- edge = &edges[edgeNum];
- return ( vertices[edge->vertexNum[0]] + vertices[edge->vertexNum[1]] ) * 0.5f;
- }
- /*
- ================
- idAASFileLocal::FaceCenter
- ================
- */
- idVec3 idAASFileLocal::FaceCenter( int faceNum ) const {
- int i, edgeNum;
- const aasFace_t *face;
- const aasEdge_t *edge;
- idVec3 center;
- center = vec3_origin;
- face = &faces[faceNum];
- if ( face->numEdges > 0 ) {
- for ( i = 0; i < face->numEdges; i++ ) {
- edgeNum = edgeIndex[ face->firstEdge + i ];
- edge = &edges[ abs( edgeNum ) ];
- center += vertices[ edge->vertexNum[ INT32_SIGNBITSET(edgeNum) ] ];
- }
- center /= face->numEdges;
- }
- return center;
- }
- /*
- ================
- idAASFileLocal::AreaCenter
- ================
- */
- idVec3 idAASFileLocal::AreaCenter( int areaNum ) const {
- int i, faceNum;
- const aasArea_t *area;
- idVec3 center;
- center = vec3_origin;
- area = &areas[areaNum];
- if ( area->numFaces > 0 ) {
- for ( i = 0; i < area->numFaces; i++ ) {
- faceNum = faceIndex[area->firstFace + i];
- center += FaceCenter( abs(faceNum) );
- }
- center /= area->numFaces;
- }
- return center;
- }
- /*
- ============
- idAASFileLocal::AreaReachableGoal
- ============
- */
- idVec3 idAASFileLocal::AreaReachableGoal( int areaNum ) const {
- int i, faceNum, numFaces;
- const aasArea_t *area;
- idVec3 center;
- idVec3 start, end;
- aasTrace_t trace;
- area = &areas[areaNum];
- if ( !(area->flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY)) || (area->flags & AREA_LIQUID) ) {
- return AreaCenter( areaNum );
- }
- center = vec3_origin;
- numFaces = 0;
- for ( i = 0; i < area->numFaces; i++ ) {
- faceNum = faceIndex[area->firstFace + i];
- if ( !(faces[abs(faceNum)].flags & FACE_FLOOR) ) {
- continue;
- }
- center += FaceCenter( abs(faceNum) );
- numFaces++;
- }
- if ( numFaces > 0 ) {
- center /= numFaces;
- }
- center[2] += 1.0f;
- end = center;
- end[2] -= 1024;
- Trace( trace, center, end );
- return trace.endpos;
- }
- /*
- ================
- idAASFileLocal::EdgeBounds
- ================
- */
- idBounds idAASFileLocal::EdgeBounds( int edgeNum ) const {
- const aasEdge_t *edge;
- idBounds bounds;
- edge = &edges[ abs( edgeNum ) ];
- bounds[0] = bounds[1] = vertices[ edge->vertexNum[0] ];
- bounds += vertices[ edge->vertexNum[1] ];
- return bounds;
- }
- /*
- ================
- idAASFileLocal::FaceBounds
- ================
- */
- idBounds idAASFileLocal::FaceBounds( int faceNum ) const {
- int i, edgeNum;
- const aasFace_t *face;
- const aasEdge_t *edge;
- idBounds bounds;
- face = &faces[faceNum];
- bounds.Clear();
- for ( i = 0; i < face->numEdges; i++ ) {
- edgeNum = edgeIndex[ face->firstEdge + i ];
- edge = &edges[ abs( edgeNum ) ];
- bounds.AddPoint( vertices[ edge->vertexNum[ INT32_SIGNBITSET(edgeNum) ] ] );
- }
- return bounds;
- }
- /*
- ================
- idAASFileLocal::AreaBounds
- ================
- */
- idBounds idAASFileLocal::AreaBounds( int areaNum ) const {
- int i, faceNum;
- const aasArea_t *area;
- idBounds bounds;
- area = &areas[areaNum];
- bounds.Clear();
- for ( i = 0; i < area->numFaces; i++ ) {
- faceNum = faceIndex[area->firstFace + i];
- bounds += FaceBounds( abs(faceNum) );
- }
- return bounds;
- }
- /*
- ============
- idAASFileLocal::PointAreaNum
- ============
- */
- int idAASFileLocal::PointAreaNum( const idVec3 &origin ) const {
- int nodeNum;
- const aasNode_t *node;
- nodeNum = 1;
- do {
- node = &nodes[nodeNum];
- if ( planeList[node->planeNum].Side( origin ) == PLANESIDE_BACK ) {
- nodeNum = node->children[1];
- }
- else {
- nodeNum = node->children[0];
- }
- if ( nodeNum < 0 ) {
- return -nodeNum;
- }
- } while( nodeNum );
- return 0;
- }
- /*
- ============
- idAASFileLocal::PointReachableAreaNum
- ============
- */
- int idAASFileLocal::PointReachableAreaNum( const idVec3 &origin, const idBounds &searchBounds, const int areaFlags, const int excludeTravelFlags ) const {
- int areaList[32], areaNum, i;
- idVec3 start, end, pointList[32];
- aasTrace_t trace;
- idBounds bounds;
- float frac;
- start = origin;
- trace.areas = areaList;
- trace.points = pointList;
- trace.maxAreas = sizeof( areaList ) / sizeof( int );
- trace.getOutOfSolid = true;
- areaNum = PointAreaNum( start );
- if ( areaNum ) {
- if ( ( areas[areaNum].flags & areaFlags ) && ( ( areas[areaNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
- return areaNum;
- }
- }
- else {
- // trace up
- end = start;
- end[2] += 32.0f;
- Trace( trace, start, end );
- if ( trace.numAreas >= 1 ) {
- if ( ( areas[0].flags & areaFlags ) && ( ( areas[0].travelFlags & excludeTravelFlags ) == 0 ) ) {
- return areaList[0];
- }
- start = pointList[0];
- start[2] += 1.0f;
- }
- }
- // trace down
- end = start;
- end[2] -= 32.0f;
- Trace( trace, start, end );
- if ( trace.lastAreaNum ) {
- if ( ( areas[trace.lastAreaNum].flags & areaFlags ) && ( ( areas[trace.lastAreaNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
- return trace.lastAreaNum;
- }
- start = trace.endpos;
- }
- // expand bounds until an area is found
- for ( i = 1; i <= 12; i++ ) {
- frac = i * ( 1.0f / 12.0f );
- bounds[0] = origin + searchBounds[0] * frac;
- bounds[1] = origin + searchBounds[1] * frac;
- areaNum = BoundsReachableAreaNum( bounds, areaFlags, excludeTravelFlags );
- if ( areaNum && ( areas[areaNum].flags & areaFlags ) && ( ( areas[areaNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
- return areaNum;
- }
- }
- return 0;
- }
- /*
- ============
- idAASFileLocal::BoundsReachableAreaNum_r
- ============
- */
- int idAASFileLocal::BoundsReachableAreaNum_r( int nodeNum, const idBounds &bounds, const int areaFlags, const int excludeTravelFlags ) const {
- int res;
- const aasNode_t *node;
- while( nodeNum ) {
- if ( nodeNum < 0 ) {
- if ( ( areas[-nodeNum].flags & areaFlags ) && ( ( areas[-nodeNum].travelFlags & excludeTravelFlags ) == 0 ) ) {
- return -nodeNum;
- }
- return 0;
- }
- node = &nodes[nodeNum];
- res = bounds.PlaneSide( planeList[node->planeNum] );
- if ( res == PLANESIDE_BACK ) {
- nodeNum = node->children[1];
- }
- else if ( res == PLANESIDE_FRONT ) {
- nodeNum = node->children[0];
- }
- else {
- nodeNum = BoundsReachableAreaNum_r( node->children[1], bounds, areaFlags, excludeTravelFlags );
- if ( nodeNum ) {
- return nodeNum;
- }
- nodeNum = node->children[0];
- }
- }
- return 0;
- }
- /*
- ============
- idAASFileLocal::BoundsReachableAreaNum
- ============
- */
- int idAASFileLocal::BoundsReachableAreaNum( const idBounds &bounds, const int areaFlags, const int excludeTravelFlags ) const {
- return BoundsReachableAreaNum_r( 1, bounds, areaFlags, excludeTravelFlags );
- }
- /*
- ============
- idAASFileLocal::PushPointIntoAreaNum
- ============
- */
- void idAASFileLocal::PushPointIntoAreaNum( int areaNum, idVec3 &point ) const {
- int i, faceNum;
- const aasArea_t *area;
- const aasFace_t *face;
- area = &areas[areaNum];
- // push the point to the right side of all area face planes
- for ( i = 0; i < area->numFaces; i++ ) {
- faceNum = faceIndex[area->firstFace + i];
- face = &faces[abs( faceNum )];
- const idPlane &plane = planeList[face->planeNum ^ INT32_SIGNBITSET( faceNum )];
- float dist = plane.Distance( point );
- // project the point onto the face plane if it is on the wrong side
- if ( dist < 0.0f ) {
- point -= dist * plane.Normal();
- }
- }
- }
- /*
- ============
- idAASFileLocal::Trace
- ============
- */
- #define TRACEPLANE_EPSILON 0.125f
- typedef struct aasTraceStack_s
- {
- idVec3 start;
- idVec3 end;
- int planeNum;
- int nodeNum;
- } aasTraceStack_t;
- bool idAASFileLocal::Trace( aasTrace_t &trace, const idVec3 &start, const idVec3 &end ) const {
- int side, nodeNum, tmpPlaneNum;
- double front, back, frac;
- idVec3 cur_start, cur_end, cur_mid, v1, v2;
- aasTraceStack_t tracestack[MAX_AAS_TREE_DEPTH];
- aasTraceStack_t *tstack_p;
- const aasNode_t *node;
- const idPlane *plane;
- trace.numAreas = 0;
- trace.lastAreaNum = 0;
- trace.blockingAreaNum = 0;
- tstack_p = tracestack;
- tstack_p->start = start;
- tstack_p->end = end;
- tstack_p->planeNum = 0;
- tstack_p->nodeNum = 1; //start with the root of the tree
- tstack_p++;
-
- while( 1 ) {
- tstack_p--;
- // if the trace stack is empty
- if ( tstack_p < tracestack ) {
- if ( !trace.lastAreaNum ) {
- // completely in solid
- trace.fraction = 0.0f;
- trace.endpos = start;
- }
- else {
- // nothing was hit
- trace.fraction = 1.0f;
- trace.endpos = end;
- }
- trace.planeNum = 0;
- return false;
- }
- // number of the current node to test the line against
- nodeNum = tstack_p->nodeNum;
- // if it is an area
- if ( nodeNum < 0) {
- // if can't enter the area
- if ( ( areas[-nodeNum].flags & trace.flags ) || ( areas[-nodeNum].travelFlags & trace.travelFlags ) ) {
- if ( !trace.lastAreaNum ) {
- trace.fraction = 0.0f;
- v1 = vec3_origin;
- } else {
- v1 = end - start;
- v2 = tstack_p->start - start;
- trace.fraction = v2.Length() / v1.Length();
- }
- trace.endpos = tstack_p->start;
- trace.blockingAreaNum = -nodeNum;
- trace.planeNum = tstack_p->planeNum;
- // always take the plane with normal facing towards the trace start
- plane = &planeList[trace.planeNum];
- if ( v1 * plane->Normal() > 0.0f ) {
- trace.planeNum ^= 1;
- }
- return true;
- }
- trace.lastAreaNum = -nodeNum;
- if ( trace.numAreas < trace.maxAreas ) {
- if ( trace.areas ) {
- trace.areas[trace.numAreas] = -nodeNum;
- }
- if ( trace.points ) {
- trace.points[trace.numAreas] = tstack_p->start;
- }
- trace.numAreas++;
- }
- continue;
- }
- // if it is a solid leaf
- if ( !nodeNum ) {
- if ( !trace.lastAreaNum ) {
- trace.fraction = 0.0f;
- v1 = vec3_origin;
- } else {
- v1 = end - start;
- v2 = tstack_p->start - start;
- trace.fraction = v2.Length() / v1.Length();
- }
- trace.endpos = tstack_p->start;
- trace.blockingAreaNum = 0; // hit solid leaf
- trace.planeNum = tstack_p->planeNum;
- // always take the plane with normal facing towards the trace start
- plane = &planeList[trace.planeNum];
- if ( v1 * plane->Normal() > 0.0f ) {
- trace.planeNum ^= 1;
- }
- if ( !trace.lastAreaNum && trace.getOutOfSolid ) {
- continue;
- }
- else {
- return true;
- }
- }
- // the node to test against
- node = &nodes[nodeNum];
- // start point of current line to test against node
- cur_start = tstack_p->start;
- // end point of the current line to test against node
- cur_end = tstack_p->end;
- // the current node plane
- plane = &planeList[node->planeNum];
- front = plane->Distance( cur_start );
- back = plane->Distance( cur_end );
- // if the whole to be traced line is totally at the front of this node
- // only go down the tree with the front child
- if ( front >= -ON_EPSILON && back >= -ON_EPSILON ) {
- // keep the current start and end point on the stack and go down the tree with the front child
- tstack_p->nodeNum = node->children[0];
- tstack_p++;
- if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
- common->Error("idAASFileLocal::Trace: stack overflow\n" );
- return false;
- }
- }
- // if the whole to be traced line is totally at the back of this node
- // only go down the tree with the back child
- else if ( front < ON_EPSILON && back < ON_EPSILON ) {
- // keep the current start and end point on the stack and go down the tree with the back child
- tstack_p->nodeNum = node->children[1];
- tstack_p++;
- if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
- common->Error("idAASFileLocal::Trace: stack overflow\n" );
- return false;
- }
- }
- // go down the tree both at the front and back of the node
- else {
- tmpPlaneNum = tstack_p->planeNum;
- // calculate the hit point with the node plane
- // put the cross point TRACEPLANE_EPSILON on the near side
- if (front < 0) {
- frac = (front + TRACEPLANE_EPSILON) / ( front - back );
- }
- else {
- frac = (front - TRACEPLANE_EPSILON) / ( front - back );
- }
- if (frac < 0) {
- frac = 0.001f; //0
- }
- else if (frac > 1) {
- frac = 0.999f; //1
- }
- cur_mid = cur_start + ( cur_end - cur_start ) * frac;
- // side the front part of the line is on
- side = front < 0;
- // first put the end part of the line on the stack (back side)
- tstack_p->start = cur_mid;
- tstack_p->planeNum = node->planeNum;
- tstack_p->nodeNum = node->children[!side];
- tstack_p++;
- if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
- common->Error("idAASFileLocal::Trace: stack overflow\n" );
- return false;
- }
- // now put the part near the start of the line on the stack so we will
- // continue with that part first.
- tstack_p->start = cur_start;
- tstack_p->end = cur_mid;
- tstack_p->planeNum = tmpPlaneNum;
- tstack_p->nodeNum = node->children[side];
- tstack_p++;
- if ( tstack_p >= &tracestack[MAX_AAS_TREE_DEPTH] ) {
- common->Error("idAASFileLocal::Trace: stack overflow\n" );
- return false;
- }
- }
- }
- return false;
- }
- /*
- ============
- idAASLocal::AreaContentsTravelFlags
- ============
- */
- int idAASFileLocal::AreaContentsTravelFlags( int areaNum ) const {
- if ( areas[areaNum].contents & AREACONTENTS_WATER ) {
- return TFL_WATER;
- }
- return TFL_AIR;
- }
- /*
- ============
- idAASFileLocal::MaxTreeDepth_r
- ============
- */
- void idAASFileLocal::MaxTreeDepth_r( int nodeNum, int &depth, int &maxDepth ) const {
- const aasNode_t *node;
- if ( nodeNum <= 0 ) {
- return;
- }
- depth++;
- if ( depth > maxDepth ) {
- maxDepth = depth;
- }
- node = &nodes[nodeNum];
- MaxTreeDepth_r( node->children[0], depth, maxDepth );
- MaxTreeDepth_r( node->children[1], depth, maxDepth );
- depth--;
- }
- /*
- ============
- idAASFileLocal::MaxTreeDepth
- ============
- */
- int idAASFileLocal::MaxTreeDepth() const {
- int depth, maxDepth;
- depth = maxDepth = 0;
- MaxTreeDepth_r( 1, depth, maxDepth );
- return maxDepth;
- }
|