/* =========================================================================== IceTech GPL Source Code Copyright (C) 2026 Justin Marshall This file is part of the IceTech GPL Source Code (?IceTech Source Code?). IceTech 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. IceTech 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 IceTech Source Code. If not, see . In addition, the IceTech 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 IceTech 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 Justin Marshall, justinmarshall20@gmail.com =========================================================================== */ #include "precompiled.h" #pragma hdrstop #include "../Game_local.h" #include "NAV_local.h" /* ============ idNAV::Alloc ============ */ idNAV *idNAV::Alloc( void ) { return new idNAVLocal; } /* ============ idNAV::~idNAV ============ */ idNAV::~idNAV( void ) { } /* ============ idNAVLocal::idNAVLocal ============ */ idNAVLocal::idNAVLocal( void ) { file = NULL; } /* ============ idNAVLocal::~idNAVLocal ============ */ idNAVLocal::~idNAVLocal( void ) { Shutdown(); } /* ============ idNAVLocal::Init ============ */ bool idNAVLocal::Init( const idStr &mapName, unsigned int mapFileCRC ) { const idStr navName = idRecastNavMesh::NavFileNameForMapName( mapName ); if ( recastNavMesh.IsLoaded() && mapName.Icmp( name ) == 0 ) { common->Printf( "Keeping %s\n", navName.c_str() ); recastNavMesh.RemoveAllObstacles(); return true; } if ( recastNavMesh.Load( mapName, navName, mapFileCRC ) ) { if ( file ) { for ( int i = 0; i < obstacleList.Num(); i++ ) { delete obstacleList[i]; } obstacleList.Clear(); ShutdownRouting(); AASFileManager->FreeAAS( file ); file = NULL; } name = mapName; common->Printf( "Loaded Recast navmesh: %s\n", navName.c_str() ); return true; } if ( file && mapName.Icmp( file->GetName() ) == 0 && mapFileCRC == file->GetCRC() ) { common->Printf( "Keeping %s\n", file->GetName() ); RemoveAllObstacles(); } else { Shutdown(); file = AASFileManager->LoadAAS( mapName, mapFileCRC ); if ( !file ) { common->DWarning( "Couldn't load NAV file: '%s'", mapName.c_str() ); return false; } SetupRouting(); } return true; } /* ============ idNAVLocal::Shutdown ============ */ void idNAVLocal::Shutdown( void ) { recastNavMesh.Shutdown(); if ( file ) { ShutdownRouting(); RemoveAllObstacles(); AASFileManager->FreeAAS( file ); file = NULL; } } /* ============ idNAVLocal::Stats ============ */ void idNAVLocal::Stats( void ) const { if ( recastNavMesh.IsLoaded() ) { recastNavMesh.Stats(); return; } if ( !file ) { return; } common->Printf( "[%s]\n", file->GetName() ); file->PrintInfo(); RoutingStats(); } /* ============ idNAVLocal::GetSettings ============ */ const idAASSettings *idNAVLocal::GetSettings( void ) const { if ( recastNavMesh.IsLoaded() ) { return recastNavMesh.GetSettings(); } if ( !file ) { return NULL; } return &file->GetSettings(); } /* ============ idNAVLocal::PointAreaNum ============ */ int idNAVLocal::PointAreaNum( const idVec3 &origin ) const { if ( recastNavMesh.IsLoaded() ) { return recastNavMesh.PointAreaNum( origin ); } if ( !file ) { return 0; } return file->PointAreaNum( origin ); } /* ============ idNAVLocal::PointReachableAreaNum ============ */ int idNAVLocal::PointReachableAreaNum( const idVec3 &origin, const idBounds &searchBounds, const int areaFlags ) const { if ( recastNavMesh.IsLoaded() ) { return recastNavMesh.PointReachableAreaNum( origin, searchBounds, areaFlags ); } if ( !file ) { return 0; } return file->PointReachableAreaNum( origin, searchBounds, areaFlags, TFL_INVALID ); } /* ============ idNAVLocal::BoundsReachableAreaNum ============ */ int idNAVLocal::BoundsReachableAreaNum( const idBounds &bounds, const int areaFlags ) const { if ( recastNavMesh.IsLoaded() ) { return recastNavMesh.BoundsReachableAreaNum( bounds, areaFlags ); } if ( !file ) { return 0; } return file->BoundsReachableAreaNum( bounds, areaFlags, TFL_INVALID ); } /* ============ idNAVLocal::PushPointIntoAreaNum ============ */ void idNAVLocal::PushPointIntoAreaNum( int areaNum, idVec3 &origin ) const { if ( recastNavMesh.IsLoaded() ) { recastNavMesh.PushPointIntoAreaNum( areaNum, origin ); return; } if ( !file ) { return; } file->PushPointIntoAreaNum( areaNum, origin ); } /* ============ idNAVLocal::AreaCenter ============ */ idVec3 idNAVLocal::AreaCenter( int areaNum ) const { if ( recastNavMesh.IsLoaded() ) { return recastNavMesh.AreaCenter( areaNum ); } if ( !file ) { return vec3_origin; } return file->GetArea( areaNum ).center; } /* ============ idNAVLocal::AreaFlags ============ */ int idNAVLocal::AreaFlags( int areaNum ) const { if ( recastNavMesh.IsLoaded() ) { return recastNavMesh.AreaFlags( areaNum ); } if ( !file ) { return 0; } return file->GetArea( areaNum ).flags; } /* ============ idNAVLocal::AreaTravelFlags ============ */ int idNAVLocal::AreaTravelFlags( int areaNum ) const { if ( recastNavMesh.IsLoaded() ) { return recastNavMesh.AreaTravelFlags( areaNum ); } if ( !file ) { return 0; } return file->GetArea( areaNum ).travelFlags; } /* ============ idNAVLocal::Trace ============ */ bool idNAVLocal::Trace( aasTrace_t &trace, const idVec3 &start, const idVec3 &end ) const { if ( recastNavMesh.IsLoaded() ) { return recastNavMesh.Trace( trace, start, end ); } if ( !file ) { trace.fraction = 0.0f; trace.lastAreaNum = 0; trace.numAreas = 0; return true; } return file->Trace( trace, start, end ); } /* ============ idNAVLocal::GetPlane ============ */ const idPlane &idNAVLocal::GetPlane( int planeNum ) const { if ( !file ) { static idPlane dummy; return dummy; } return file->GetPlane( planeNum ); } /* ============ idNAVLocal::GetEdgeVertexNumbers ============ */ void idNAVLocal::GetEdgeVertexNumbers( int edgeNum, int verts[2] ) const { if ( !file ) { verts[0] = verts[1] = 0; return; } const int *v = file->GetEdge( abs(edgeNum) ).vertexNum; verts[0] = v[INTSIGNBITSET(edgeNum)]; verts[1] = v[INTSIGNBITNOTSET(edgeNum)]; } /* ============ idNAVLocal::GetEdge ============ */ void idNAVLocal::GetEdge( int edgeNum, idVec3 &start, idVec3 &end ) const { if ( !file ) { start.Zero(); end.Zero(); return; } const int *v = file->GetEdge( abs(edgeNum) ).vertexNum; start = file->GetVertex( v[INTSIGNBITSET(edgeNum)] ); end = file->GetVertex( v[INTSIGNBITNOTSET(edgeNum)] ); } /* ============ idNAVLocal::AdjustPositionAndGetArea ============ */ int idNAVLocal::AdjustPositionAndGetArea(idVec3& origin) { int area = PointReachableAreaNum(origin, DefaultSearchBounds(), AREA_REACHABLE_WALK); PushPointIntoAreaNum(area, origin); return area; }