ef2-sdk/dlls/game/path.cpp
2003-11-05 00:00:00 +00:00

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;
}