478 lines
8.5 KiB
C++
478 lines
8.5 KiB
C++
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Logfile:: /Code/DLLs/game/path.cpp $
|
|
// $Revision:: 7 $
|
|
// $Author:: Steven $
|
|
// $Date:: 10/06/02 7:08p $
|
|
//
|
|
// Copyright (C) 1997 by Ritual Entertainment, Inc.
|
|
// All rights reserved.
|
|
//
|
|
// This source is may not be distributed and/or modified without
|
|
// expressly written permission by Ritual Entertainment, Inc.
|
|
//
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
|
|
#include "_pch_cpp.h"
|
|
#include "entity.h"
|
|
#include "path.h"
|
|
#include "container.h"
|
|
#include "navigate.h"
|
|
#include "misc.h"
|
|
|
|
CLASS_DECLARATION( Class, Path, NULL )
|
|
{
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
Path::Path()
|
|
{
|
|
pathlength = 0;
|
|
from = NULL;
|
|
to = NULL;
|
|
nextnode = 1;
|
|
}
|
|
|
|
Path::Path( int numnodes )
|
|
{
|
|
pathlength = 0;
|
|
from = NULL;
|
|
to = NULL;
|
|
nextnode = 1;
|
|
pathlist.Resize( numnodes );
|
|
dirToNextNode.Resize( numnodes );
|
|
distanceToNextNode.Resize( numnodes );
|
|
}
|
|
|
|
void Path::Clear( void )
|
|
{
|
|
nextnode = 1;
|
|
pathlength = 0;
|
|
from = NULL;
|
|
to = NULL;
|
|
pathlist.FreeObjectList();
|
|
dirToNextNode.FreeObjectList();
|
|
distanceToNextNode.FreeObjectList();
|
|
}
|
|
|
|
void Path::Reset( void )
|
|
{
|
|
nextnode = 1;
|
|
}
|
|
|
|
PathNode *Path::Start( void )
|
|
{
|
|
return from;
|
|
}
|
|
|
|
PathNode *Path::End( void )
|
|
{
|
|
return to;
|
|
}
|
|
|
|
void Path::AddNode( PathNode *node )
|
|
{
|
|
Vector dir;
|
|
float len;
|
|
int num;
|
|
|
|
if ( !from )
|
|
{
|
|
from = node;
|
|
}
|
|
|
|
to = node;
|
|
pathlist.AddObject( PathNodePtr( node ) );
|
|
|
|
len = 0;
|
|
distanceToNextNode.AddObject( len );
|
|
dirToNextNode.AddObject( vec_zero );
|
|
|
|
num = NumNodes();
|
|
if ( num > 1 )
|
|
{
|
|
dir = node->origin - GetNode( num - 1 )->origin;
|
|
len = dir.length();
|
|
dir *= 1.0f / len;
|
|
|
|
distanceToNextNode.SetObjectAt( num - 1, len );
|
|
dirToNextNode.SetObjectAt( num - 1, dir );
|
|
|
|
pathlength += len;
|
|
}
|
|
}
|
|
|
|
void Path::_UpdateNodeValues(int const nodeNumber)
|
|
{
|
|
if (nodeNumber < 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Vector dir(vec_zero);
|
|
float len=0.0f;
|
|
|
|
if (nodeNumber < NumNodes())
|
|
{
|
|
dir = GetNode( nodeNumber + 1 )->origin - GetNode( nodeNumber )->origin;
|
|
len = dir.length();
|
|
dir *= 1.0f / len;
|
|
}
|
|
distanceToNextNode.SetObjectAt( nodeNumber, len );
|
|
dirToNextNode.SetObjectAt( nodeNumber, dir );
|
|
}
|
|
|
|
void Path::_UpdatePathLength(void)
|
|
{
|
|
int numNodes=NumNodes();
|
|
pathlength=0.0f;
|
|
for (int i=1; i<=numNodes;i++)
|
|
{
|
|
pathlength+=distanceToNextNode.ObjectAt(i);
|
|
}
|
|
}
|
|
|
|
void Path::InsertNode( PathNode *node, int const insertionPoint )
|
|
{
|
|
if (insertionPoint == 1)
|
|
{
|
|
from = node;
|
|
}
|
|
|
|
if (insertionPoint > NumNodes())
|
|
{
|
|
to = node;
|
|
}
|
|
pathlist.InsertObjectAt(insertionPoint, PathNodePtr( node ) );
|
|
distanceToNextNode.InsertObjectAt( insertionPoint, 0.0f );
|
|
dirToNextNode.InsertObjectAt( insertionPoint, vec_zero );
|
|
|
|
_UpdateNodeValues(insertionPoint-1);
|
|
_UpdateNodeValues(insertionPoint);
|
|
_UpdatePathLength();
|
|
}
|
|
|
|
void Path::RemoveNode( PathNode *node )
|
|
{
|
|
|
|
int nodeIndex=GetNodeIndex(node);
|
|
int numNodes=NumNodes();
|
|
if (nodeIndex < 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pathlist.RemoveObjectAt(nodeIndex);
|
|
if (NumNodes() == 0)
|
|
{
|
|
to=NULL;
|
|
from=NULL;
|
|
}
|
|
else
|
|
{
|
|
if (nodeIndex == numNodes)
|
|
{
|
|
to=GetNode(NumNodes());
|
|
}
|
|
if (nodeIndex == 1)
|
|
{
|
|
from=GetNode(1);
|
|
}
|
|
else
|
|
{
|
|
_UpdateNodeValues(nodeIndex-1);
|
|
}
|
|
}
|
|
_UpdatePathLength();
|
|
}
|
|
|
|
PathNode *Path::GetNode( int num )
|
|
{
|
|
PathNode *node;
|
|
|
|
node = pathlist.ObjectAt( num );
|
|
assert( node != NULL );
|
|
if ( node == NULL )
|
|
{
|
|
error( "GetNode", "Null pointer in node list\n" );
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
int Path::GetNodeIndex( PathNode *node )
|
|
{
|
|
int num = NumNodes();
|
|
for( int i = 1; i <= num; i++ )
|
|
{
|
|
if ( pathlist.ObjectAt( i ) == node )
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
PathNode *Path::NextNode( void )
|
|
{
|
|
if ( nextnode <= NumNodes() )
|
|
{
|
|
return pathlist.ObjectAt( nextnode++ );
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
PathNode *Path::NextNode( const PathNode *node )
|
|
{
|
|
int i;
|
|
int num;
|
|
PathNode *n;
|
|
|
|
num = NumNodes();
|
|
|
|
// NOTE: We specifically DON'T check the last object (hence the i < num instead
|
|
// of the usual i <= num, so don't go doing something stupid like trying to fix
|
|
// this without keeping this in mind!! :)
|
|
for( i = 1; i < num; i++ )
|
|
{
|
|
n = pathlist.ObjectAt( i );
|
|
if ( n == node )
|
|
{
|
|
// Since we only check up to num - 1, it's ok to do this.
|
|
// We do this since the last node in the list has no next node (duh!).
|
|
return pathlist.ObjectAt( i + 1 );
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
Vector Path::ClosestPointOnPath( const Vector &pos )
|
|
{
|
|
PathNode *s;
|
|
PathNode *e;
|
|
int num;
|
|
int i;
|
|
float bestdist;
|
|
Vector bestpoint;
|
|
float dist;
|
|
float segmentlength;
|
|
Vector delta;
|
|
Vector p1;
|
|
Vector p2;
|
|
Vector p3;
|
|
float t;
|
|
|
|
num = NumNodes();
|
|
s = GetNode( 1 );
|
|
|
|
bestpoint = s->origin;
|
|
delta = bestpoint - pos;
|
|
bestdist = delta * delta;
|
|
|
|
for( i = 2; i <= num; i++ )
|
|
{
|
|
e = GetNode( i );
|
|
|
|
// check if we're closest to the endpoint
|
|
delta = e->origin - pos;
|
|
dist = delta * delta;
|
|
|
|
if ( dist < bestdist )
|
|
{
|
|
bestdist = dist;
|
|
bestpoint = e->origin;
|
|
}
|
|
|
|
// check if we're closest to the segment
|
|
segmentlength = distanceToNextNode.ObjectAt( i - 1 );
|
|
p1 = dirToNextNode.ObjectAt( i - 1 );
|
|
p2 = pos - s->origin;
|
|
|
|
t = p1 * p2;
|
|
if ( ( t > 0.0f ) && ( t < segmentlength ) )
|
|
{
|
|
p3 = ( p1 * t ) + s->origin;
|
|
|
|
delta = p3 - pos;
|
|
dist = delta * delta;
|
|
if ( dist < bestdist )
|
|
{
|
|
bestdist = dist;
|
|
bestpoint = p3;
|
|
}
|
|
}
|
|
|
|
s = e;
|
|
}
|
|
|
|
return bestpoint;
|
|
}
|
|
|
|
float Path::DistanceAlongPath( const Vector &pos )
|
|
{
|
|
PathNode *s;
|
|
PathNode *e;
|
|
int num;
|
|
int i;
|
|
float bestdist;
|
|
float dist;
|
|
float segmentlength;
|
|
Vector delta;
|
|
Vector p1;
|
|
Vector p2;
|
|
Vector p3;
|
|
float t;
|
|
float pathdist;
|
|
float bestdistalongpath;
|
|
|
|
pathdist = 0;
|
|
|
|
num = NumNodes();
|
|
s = GetNode( 1 );
|
|
delta = s->origin - pos;
|
|
bestdist = delta * delta;
|
|
bestdistalongpath = 0;
|
|
|
|
for( i = 2; i <= num; i++ )
|
|
{
|
|
e = GetNode( i );
|
|
|
|
segmentlength = distanceToNextNode.ObjectAt( i - 1 );
|
|
|
|
// check if we're closest to the endpoint
|
|
delta = e->origin - pos;
|
|
dist = delta * delta;
|
|
|
|
if ( dist < bestdist )
|
|
{
|
|
bestdist = dist;
|
|
bestdistalongpath = pathdist + segmentlength;
|
|
}
|
|
|
|
// check if we're closest to the segment
|
|
p1 = dirToNextNode.ObjectAt( i - 1 );
|
|
p2 = pos - s->origin;
|
|
|
|
t = p1 * p2;
|
|
if ( ( t > 0.0f ) && ( t < segmentlength ) )
|
|
{
|
|
p3 = ( p1 * t ) + s->origin;
|
|
|
|
delta = p3 - pos;
|
|
dist = delta * delta;
|
|
if ( dist < bestdist )
|
|
{
|
|
bestdist = dist;
|
|
bestdistalongpath = pathdist + t;
|
|
}
|
|
}
|
|
|
|
s = e;
|
|
|
|
pathdist += segmentlength;
|
|
}
|
|
|
|
return bestdistalongpath;
|
|
}
|
|
|
|
Vector Path::PointAtDistance( float dist )
|
|
{
|
|
PathNode *s;
|
|
PathNode *e;
|
|
int num;
|
|
int i;
|
|
float t;
|
|
float pathdist;
|
|
float segmentlength;
|
|
|
|
num = NumNodes();
|
|
s = GetNode( 1 );
|
|
pathdist = 0;
|
|
|
|
for( i = 2; i <= num; i++ )
|
|
{
|
|
e = GetNode( i );
|
|
|
|
segmentlength = distanceToNextNode.ObjectAt( i - 1 );
|
|
if ( ( pathdist + segmentlength ) > dist )
|
|
{
|
|
t = dist - pathdist;
|
|
return s->origin + ( dirToNextNode.ObjectAt( i - 1 ) * t );
|
|
}
|
|
|
|
s = e;
|
|
pathdist += segmentlength;
|
|
}
|
|
|
|
// cap it off at start or end of path
|
|
return s->origin;
|
|
}
|
|
|
|
PathNode *Path::NextNode( float dist )
|
|
{
|
|
PathNode *s;
|
|
PathNode *e;
|
|
int num;
|
|
int i;
|
|
float pathdist;
|
|
float segmentlength;
|
|
|
|
num = NumNodes();
|
|
s = GetNode( 1 );
|
|
pathdist = 0;
|
|
|
|
for( i = 2; i <= num; i++ )
|
|
{
|
|
e = GetNode( i );
|
|
|
|
segmentlength = distanceToNextNode.ObjectAt( i - 1 );
|
|
if ( ( pathdist + segmentlength ) > dist )
|
|
{
|
|
return e;
|
|
}
|
|
|
|
s = e;
|
|
pathdist += segmentlength;
|
|
}
|
|
|
|
// cap it off at start or end of path
|
|
return s;
|
|
}
|
|
|
|
void Path::DrawPath( float r, float g, float b, float time )
|
|
{
|
|
Vector s;
|
|
Vector e;
|
|
Vector offset;
|
|
PathNode *node;
|
|
int num;
|
|
int i;
|
|
|
|
num = NumNodes();
|
|
|
|
node = GetNode( 1 );
|
|
s = node->origin;
|
|
|
|
offset = Vector( r, g, b ) * 4.0f + Vector( 0.0f, 0.0f, 20.0f );
|
|
for( i = 2; i <= num; i++ )
|
|
{
|
|
node = GetNode( i );
|
|
e = node->origin;
|
|
|
|
G_DebugLine( s + offset, e + offset, r, g, b, 1.0f );
|
|
s = e;
|
|
}
|
|
}
|
|
|
|
int Path::NumNodes( void )
|
|
{
|
|
return pathlist.NumObjects();
|
|
}
|
|
|
|
float Path::Length( void )
|
|
{
|
|
return pathlength;
|
|
}
|