635 lines
12 KiB
C++
635 lines
12 KiB
C++
// Copyright (C) 1998 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:
|
|
// Uniform non-rational bspline class.
|
|
//
|
|
|
|
#include "g_local.h"
|
|
#include "BSpline.h"
|
|
|
|
void BSpline::Set
|
|
(
|
|
Vector *control_points_,
|
|
int num_control_points_,
|
|
splinetype_t type
|
|
)
|
|
|
|
{
|
|
int i;
|
|
|
|
SetType( type );
|
|
|
|
has_orientation = false;
|
|
|
|
if ( control_points )
|
|
{
|
|
delete [] control_points;
|
|
control_points = NULL;
|
|
}
|
|
|
|
num_control_points = num_control_points_;
|
|
if ( num_control_points )
|
|
{
|
|
control_points = new BSplineControlPoint[ num_control_points ];
|
|
assert( control_points );
|
|
|
|
for( i = 0; i < num_control_points; i++ )
|
|
{
|
|
control_points[ i ].Set( control_points_[ i ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
void BSpline::Set
|
|
(
|
|
Vector *control_points_,
|
|
Vector *control_orients_,
|
|
float *control_speeds_,
|
|
int num_control_points_,
|
|
splinetype_t type
|
|
)
|
|
|
|
{
|
|
int i;
|
|
|
|
SetType( type );
|
|
|
|
has_orientation = true;
|
|
|
|
if ( control_points )
|
|
{
|
|
delete [] control_points;
|
|
control_points = NULL;
|
|
}
|
|
|
|
num_control_points = num_control_points_;
|
|
if ( num_control_points )
|
|
{
|
|
control_points = new BSplineControlPoint[ num_control_points ];
|
|
assert( control_points );
|
|
|
|
for( i = 0; i < num_control_points; i++ )
|
|
{
|
|
control_points[ i ].Set( control_points_[ i ], control_orients_[ i ], control_speeds_[ i ] );
|
|
}
|
|
}
|
|
}
|
|
|
|
void BSpline::Clear
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
if( control_points )
|
|
{
|
|
delete [] control_points;
|
|
control_points = NULL;
|
|
}
|
|
num_control_points = 0;
|
|
has_orientation = false;
|
|
}
|
|
|
|
inline float BSpline::EvalNormal
|
|
(
|
|
float u,
|
|
Vector& pos,
|
|
Vector& orient
|
|
)
|
|
|
|
{
|
|
int segment_id;
|
|
float B[ 4 ];
|
|
float tmp;
|
|
float u_2;
|
|
float u_3;
|
|
Vector ang;
|
|
float roll;
|
|
float speed;
|
|
|
|
segment_id = ( int )u;
|
|
if ( segment_id < 0 )
|
|
{
|
|
segment_id = 0;
|
|
}
|
|
if ( segment_id > num_control_points - 4 )
|
|
{
|
|
segment_id = num_control_points - 4;
|
|
}
|
|
u -= ( float )segment_id;
|
|
|
|
u_2 = u * u;
|
|
u_3 = u * u_2;
|
|
|
|
tmp = 1 - u;
|
|
B[ 0 ] = ( tmp * tmp * tmp ) * ( 1.0f / 6.0f );
|
|
B[ 1 ] = ( 3.0f * u_3 - 6.0f * u_2 + 4.0f ) * ( 1.0f / 6.0f );
|
|
B[ 2 ] = ( -3.0f * u_3 + 3.0f * u_2 + 3.0f * u + 1 ) * ( 1.0f / 6.0f );
|
|
B[ 3 ] = u_3 * ( 1.0f / 6.0f );
|
|
|
|
pos =
|
|
*control_points[ 0 + segment_id ].GetPosition() * B[ 0 ] +
|
|
*control_points[ 1 + segment_id ].GetPosition() * B[ 1 ] +
|
|
*control_points[ 2 + segment_id ].GetPosition() * B[ 2 ] +
|
|
*control_points[ 3 + segment_id ].GetPosition() * B[ 3 ];
|
|
|
|
ang =
|
|
*control_points[ 0 + segment_id ].GetOrientation() * B[ 0 ] +
|
|
*control_points[ 1 + segment_id ].GetOrientation() * B[ 1 ] +
|
|
*control_points[ 2 + segment_id ].GetOrientation() * B[ 2 ] +
|
|
*control_points[ 3 + segment_id ].GetOrientation() * B[ 3 ];
|
|
|
|
roll =
|
|
*control_points[ 0 + segment_id ].GetRoll() * B[ 0 ] +
|
|
*control_points[ 1 + segment_id ].GetRoll() * B[ 1 ] +
|
|
*control_points[ 2 + segment_id ].GetRoll() * B[ 2 ] +
|
|
*control_points[ 3 + segment_id ].GetRoll() * B[ 3 ];
|
|
|
|
speed =
|
|
*control_points[ 0 + segment_id ].GetSpeed() * B[ 0 ] +
|
|
*control_points[ 1 + segment_id ].GetSpeed() * B[ 1 ] +
|
|
*control_points[ 2 + segment_id ].GetSpeed() * B[ 2 ] +
|
|
*control_points[ 3 + segment_id ].GetSpeed() * B[ 3 ];
|
|
|
|
orient = ang.toAngles();
|
|
orient[ ROLL ] = roll;
|
|
|
|
return speed;
|
|
}
|
|
|
|
inline float BSpline::EvalLoop
|
|
(
|
|
float t,
|
|
Vector& pos,
|
|
Vector& orient
|
|
)
|
|
|
|
{
|
|
Vector retval;
|
|
Vector ang;
|
|
float speed;
|
|
float roll;
|
|
int segment_id;
|
|
int next_id;
|
|
float B[ 4 ];
|
|
float tmp;
|
|
float u;
|
|
float u_2;
|
|
float u_3;
|
|
int i;
|
|
int j;
|
|
|
|
segment_id = ( int )floor( t );
|
|
u = t - floor( t );
|
|
|
|
segment_id %= num_control_points;
|
|
if ( segment_id < 0 )
|
|
{
|
|
segment_id += num_control_points;
|
|
}
|
|
|
|
u_2 = u * u;
|
|
u_3 = u * u_2;
|
|
|
|
tmp = 1 - u;
|
|
B[ 0 ] = ( tmp * tmp * tmp ) * ( 1.0f / 6.0f );
|
|
B[ 1 ] = ( 3.0f * u_3 - 6.0f * u_2 + 4.0f ) * ( 1.0f / 6.0f );
|
|
B[ 2 ] = ( -3.0f * u_3 + 3.0f * u_2 + 3.0f * u + 1 ) * ( 1.0f / 6.0f );
|
|
B[ 3 ] = u_3 * ( 1.0f / 6.0f );
|
|
|
|
speed = 0;
|
|
roll = 0;
|
|
|
|
for( i = 0, j = segment_id; i < 4; i++, j++ )
|
|
{
|
|
if ( j >= num_control_points )
|
|
{
|
|
j -= ( num_control_points - loop_control_point );
|
|
}
|
|
|
|
retval += *control_points[ j ].GetPosition() * B[ i ];
|
|
ang += *control_points[ j ].GetOrientation() * B[ i ];
|
|
speed += *control_points[ j ].GetSpeed() * B[ i ];
|
|
roll += *control_points[ j ].GetRoll() * B[ i ];
|
|
}
|
|
|
|
pos = retval;
|
|
|
|
next_id = segment_id + 1;
|
|
if ( next_id >= num_control_points )
|
|
{
|
|
next_id -= ( num_control_points - loop_control_point );
|
|
}
|
|
orient = ang.toAngles();
|
|
orient[ ROLL ] = roll;
|
|
|
|
return speed;
|
|
}
|
|
|
|
inline float BSpline::EvalClamp
|
|
(
|
|
float t,
|
|
Vector& pos,
|
|
Vector& orient
|
|
)
|
|
|
|
{
|
|
Vector retval;
|
|
Vector ang;
|
|
int segment_id;
|
|
int next_id;
|
|
float B[ 4 ];
|
|
float tmp;
|
|
float u;
|
|
float u_2;
|
|
float u_3;
|
|
int i;
|
|
int j;
|
|
float speed;
|
|
float roll;
|
|
|
|
segment_id = ( int )floor( t );
|
|
u = t - floor( t );
|
|
|
|
u_2 = u * u;
|
|
u_3 = u * u_2;
|
|
|
|
tmp = 1 - u;
|
|
B[ 0 ] = ( tmp * tmp * tmp ) * ( 1.0f / 6.0f );
|
|
B[ 1 ] = ( 3.0f * u_3 - 6.0f * u_2 + 4.0f ) * ( 1.0f / 6.0f );
|
|
B[ 2 ] = ( -3.0f * u_3 + 3.0f * u_2 + 3.0f * u + 1 ) * ( 1.0f / 6.0f );
|
|
B[ 3 ] = u_3 * ( 1.0f / 6.0f );
|
|
|
|
speed = 0;
|
|
roll = 0;
|
|
for( i = 0; i < 4; i++, segment_id++ )
|
|
{
|
|
j = segment_id;
|
|
if ( j < 0 )
|
|
{
|
|
j = 0;
|
|
}
|
|
else if ( j >= num_control_points )
|
|
{
|
|
j = num_control_points - 1;
|
|
}
|
|
|
|
retval += *control_points[ j ].GetPosition() * B[ i ];
|
|
ang += *control_points[ j ].GetOrientation() * B[ i ];
|
|
speed += *control_points[ j ].GetSpeed() * B[ i ];
|
|
roll += *control_points[ j ].GetRoll() * B[ i ];
|
|
}
|
|
|
|
pos = retval;
|
|
|
|
next_id = segment_id + 1;
|
|
if ( segment_id < 0 )
|
|
{
|
|
segment_id = 0;
|
|
}
|
|
if ( segment_id >= num_control_points )
|
|
{
|
|
segment_id = num_control_points - 1;
|
|
}
|
|
if ( next_id < 0 )
|
|
{
|
|
next_id = 0;
|
|
}
|
|
if ( next_id >= num_control_points )
|
|
{
|
|
next_id = num_control_points - 1;
|
|
}
|
|
orient = ang.toAngles();
|
|
orient[ ROLL ] = roll;
|
|
|
|
return speed;
|
|
}
|
|
|
|
|
|
Vector BSpline::Eval
|
|
(
|
|
float u
|
|
)
|
|
|
|
{
|
|
Vector pos;
|
|
Vector orient;
|
|
|
|
switch( curvetype )
|
|
{
|
|
default:
|
|
case SPLINE_NORMAL :
|
|
EvalNormal( u, pos, orient );
|
|
break;
|
|
|
|
case SPLINE_CLAMP:
|
|
EvalClamp( u, pos, orient );
|
|
break;
|
|
|
|
case SPLINE_LOOP:
|
|
EvalLoop( u, pos, orient );
|
|
break;
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
float BSpline::Eval
|
|
(
|
|
float u,
|
|
Vector &pos,
|
|
Vector &orient
|
|
)
|
|
|
|
{
|
|
switch( curvetype )
|
|
{
|
|
default:
|
|
case SPLINE_NORMAL :
|
|
return EvalNormal( u, pos, orient );
|
|
break;
|
|
|
|
case SPLINE_CLAMP:
|
|
return EvalClamp( u, pos, orient );
|
|
break;
|
|
|
|
case SPLINE_LOOP:
|
|
return EvalLoop( u, pos, orient );
|
|
break;
|
|
}
|
|
}
|
|
|
|
void BSpline::DrawControlSegments
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
int i;
|
|
|
|
G_BeginLine();
|
|
for( i = 0; i < num_control_points; i++ )
|
|
{
|
|
G_Vertex( *control_points[ i ].GetPosition() );
|
|
}
|
|
G_EndLine();
|
|
}
|
|
|
|
void BSpline::DrawCurve
|
|
(
|
|
int num_subdivisions
|
|
)
|
|
|
|
{
|
|
float u;
|
|
float du;
|
|
|
|
du = 1.0f / ( float )num_subdivisions;
|
|
|
|
G_BeginLine();
|
|
for( u = 0.0f; u <= ( float )num_control_points; u += du )
|
|
{
|
|
G_Vertex( ( Vector )Eval( u ) );
|
|
}
|
|
G_EndLine();
|
|
}
|
|
|
|
void BSpline::DrawCurve
|
|
(
|
|
Vector offset,
|
|
int num_subdivisions
|
|
)
|
|
|
|
{
|
|
float u;
|
|
float du;
|
|
|
|
du = 1.0f / ( float )num_subdivisions;
|
|
|
|
G_BeginLine();
|
|
for( u = 0.0f; u <= ( float )num_control_points; u += du )
|
|
{
|
|
G_Vertex( offset + ( Vector )Eval( u ) );
|
|
}
|
|
G_EndLine();
|
|
}
|
|
|
|
void BSpline::AppendControlPoint
|
|
(
|
|
const Vector& new_control_point
|
|
)
|
|
|
|
{
|
|
BSplineControlPoint *old_control_points;
|
|
int i;
|
|
|
|
old_control_points = control_points;
|
|
num_control_points++;
|
|
|
|
control_points = new BSplineControlPoint[num_control_points];
|
|
assert( control_points );
|
|
|
|
if ( old_control_points )
|
|
{
|
|
for( i = 0; i < num_control_points - 1; i++ )
|
|
{
|
|
control_points[ i ] = old_control_points[ i ];
|
|
}
|
|
delete [] old_control_points;
|
|
}
|
|
|
|
control_points[ num_control_points - 1 ].Set( new_control_point );
|
|
}
|
|
|
|
void BSpline::AppendControlPoint
|
|
(
|
|
const Vector& new_control_point,
|
|
const float& speed
|
|
)
|
|
|
|
{
|
|
BSplineControlPoint *old_control_points;
|
|
int i;
|
|
|
|
old_control_points = control_points;
|
|
num_control_points++;
|
|
|
|
control_points = new BSplineControlPoint[num_control_points];
|
|
assert( control_points );
|
|
|
|
if ( old_control_points )
|
|
{
|
|
for( i = 0; i < num_control_points - 1; i++ )
|
|
{
|
|
control_points[ i ] = old_control_points[ i ];
|
|
}
|
|
delete [] old_control_points;
|
|
}
|
|
|
|
control_points[ num_control_points - 1 ].Set( new_control_point, speed );
|
|
}
|
|
|
|
void BSpline::AppendControlPoint
|
|
(
|
|
const Vector& new_control_point,
|
|
const Vector& new_control_orient,
|
|
const float& new_control_speed
|
|
)
|
|
|
|
{
|
|
BSplineControlPoint *old_control_points;
|
|
int i;
|
|
|
|
has_orientation = true;
|
|
|
|
old_control_points = control_points;
|
|
num_control_points++;
|
|
|
|
control_points = new BSplineControlPoint[num_control_points];
|
|
assert( control_points );
|
|
|
|
if ( old_control_points )
|
|
{
|
|
for( i = 0; i < num_control_points - 1; i++ )
|
|
{
|
|
control_points[ i ] = old_control_points[ i ];
|
|
}
|
|
delete [] old_control_points;
|
|
}
|
|
|
|
control_points[ num_control_points - 1 ].Set( new_control_point, new_control_orient, new_control_speed );
|
|
}
|
|
|
|
void BSpline::SetLoopPoint
|
|
(
|
|
const Vector& pos
|
|
)
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < num_control_points; i++ )
|
|
{
|
|
if ( pos == *control_points[ i ].GetPosition() )
|
|
{
|
|
loop_control_point = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int BSpline::PickControlPoint
|
|
(
|
|
const Vector& window_point,
|
|
float pick_size
|
|
)
|
|
|
|
{
|
|
int i;
|
|
float closest_dist_2;
|
|
int closest_index;
|
|
float dist_2;
|
|
Vector delta;
|
|
|
|
closest_index = -1;
|
|
closest_dist_2 = 1000000.0f;
|
|
for( i = 0; i < num_control_points; i++ )
|
|
{
|
|
delta = window_point - *control_points[ i ].GetPosition();
|
|
dist_2 = delta * delta;
|
|
if ( dist_2 < closest_dist_2 )
|
|
{
|
|
closest_dist_2 = dist_2;
|
|
closest_index = i;
|
|
}
|
|
}
|
|
|
|
if ( pick_size * pick_size >= closest_dist_2 )
|
|
{
|
|
return closest_index;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
CLASS_DECLARATION( Entity, SplinePath, "info_splinepath" );
|
|
|
|
Event EV_SplinePath_Create( "SplinePath_create" );
|
|
|
|
ResponseDef SplinePath::Responses[] =
|
|
{
|
|
{ &EV_SplinePath_Create, ( Response )SplinePath::CreatePath },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
SplinePath::SplinePath()
|
|
{
|
|
owner = this;
|
|
next = NULL;
|
|
loop = NULL;
|
|
loop_name = G_GetStringArg( "loop" );
|
|
angles = G_GetVectorArg( "angles" );
|
|
speed = G_GetFloatArg( "speed", 1 );
|
|
setMoveType( MOVETYPE_NONE );
|
|
setSolidType( SOLID_NOT );
|
|
hideModel();
|
|
|
|
if ( !LoadingSavegame )
|
|
{
|
|
PostEvent( EV_SplinePath_Create, 0 );
|
|
}
|
|
}
|
|
|
|
void SplinePath::CreatePath
|
|
(
|
|
Event *ev
|
|
)
|
|
|
|
{
|
|
const char *target;
|
|
int num;
|
|
|
|
// Make the path from the targetlist.
|
|
target = Target();
|
|
if ( target[ 0 ] )
|
|
{
|
|
if ( num = G_FindTarget( 0, target ) )
|
|
{
|
|
next = ( SplinePath * )G_GetEntity( num );
|
|
next->owner = this;
|
|
}
|
|
else
|
|
{
|
|
gi.error( "SplinePath::CreatePath: target %s not found\n", target );
|
|
}
|
|
}
|
|
if ( loop_name.length() )
|
|
{
|
|
if ( num = G_FindTarget( 0, loop_name.c_str() ) )
|
|
{
|
|
loop = ( SplinePath * )G_GetEntity( num );
|
|
}
|
|
}
|
|
}
|
|
|
|
SplinePath *SplinePath::GetNext
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return next;
|
|
}
|
|
|
|
SplinePath *SplinePath::GetLoop
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return loop;
|
|
}
|