You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
506 lines
12 KiB
506 lines
12 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//============================================================================= |
|
#include "basetypes.h" |
|
#include "tier1/strtools.h" |
|
#include "interpolatortypes.h" |
|
#include "tier0/dbg.h" |
|
#include "mathlib/mathlib.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
struct InterpolatorNameMap_t |
|
{ |
|
int type; |
|
char const *name; |
|
char const *printname; |
|
}; |
|
|
|
static InterpolatorNameMap_t g_InterpolatorNameMap[] = |
|
{ |
|
{ INTERPOLATE_DEFAULT, "default", "Default" }, |
|
{ INTERPOLATE_CATMULL_ROM_NORMALIZEX, "catmullrom_normalize_x", "Catmull-Rom (Norm X)" }, |
|
{ INTERPOLATE_EASE_IN, "easein", "Ease In" }, |
|
{ INTERPOLATE_EASE_OUT, "easeout", "Ease Out" }, |
|
{ INTERPOLATE_EASE_INOUT, "easeinout", "Ease In/Out" }, |
|
{ INTERPOLATE_BSPLINE, "bspline", "B-Spline" }, |
|
{ INTERPOLATE_LINEAR_INTERP, "linear_interp", "Linear Interp." }, |
|
{ INTERPOLATE_KOCHANEK_BARTELS, "kochanek", "Kochanek-Bartels" }, |
|
{ INTERPOLATE_KOCHANEK_BARTELS_EARLY, "kochanek_early", "Kochanek-Bartels Early" }, |
|
{ INTERPOLATE_KOCHANEK_BARTELS_LATE, "kochanek_late", "Kochanek-Bartels Late" }, |
|
{ INTERPOLATE_SIMPLE_CUBIC, "simple_cubic", "Simple Cubic" }, |
|
{ INTERPOLATE_CATMULL_ROM, "catmullrom", "Catmull-Rom" }, |
|
{ INTERPOLATE_CATMULL_ROM_NORMALIZE, "catmullrom_normalize", "Catmull-Rom (Norm)" }, |
|
{ INTERPOLATE_CATMULL_ROM_TANGENT, "catmullrom_tangent", "Catmull-Rom (Tangent)" }, |
|
{ INTERPOLATE_EXPONENTIAL_DECAY, "exponential_decay", "Exponential Decay" }, |
|
{ INTERPOLATE_HOLD, "hold", "Hold" }, |
|
}; |
|
|
|
int Interpolator_InterpolatorForName( char const *name ) |
|
{ |
|
for ( int i = 0; i < NUM_INTERPOLATE_TYPES; ++i ) |
|
{ |
|
InterpolatorNameMap_t *slot = &g_InterpolatorNameMap[ i ]; |
|
if ( !Q_stricmp( name, slot->name ) ) |
|
return slot->type; |
|
} |
|
|
|
Assert( !"Interpolator_InterpolatorForName failed!!!" ); |
|
return INTERPOLATE_DEFAULT; |
|
} |
|
|
|
char const *Interpolator_NameForInterpolator( int type, bool printname ) |
|
{ |
|
int i = (int)type; |
|
int c = ARRAYSIZE( g_InterpolatorNameMap ); |
|
if ( i < 0 || i >= c ) |
|
{ |
|
Assert( "!Interpolator_NameForInterpolator: bogus type!" ); |
|
// returns "unspecified!!!"; |
|
return printname ? g_InterpolatorNameMap[ 0 ].printname : g_InterpolatorNameMap[ 0 ].name; |
|
} |
|
|
|
return printname ? g_InterpolatorNameMap[ i ].printname : g_InterpolatorNameMap[ i ].name; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
struct CurveNameMap_t |
|
{ |
|
int type; |
|
int hotkey; |
|
}; |
|
|
|
static CurveNameMap_t g_CurveNameMap[] = |
|
{ |
|
{ CURVE_CATMULL_ROM_TO_CATMULL_ROM, '1' }, |
|
{ CURVE_EASE_IN_TO_EASE_OUT, '2' }, |
|
{ CURVE_EASE_IN_TO_EASE_IN, '3' }, |
|
{ CURVE_EASE_OUT_TO_EASE_OUT, '4' }, |
|
{ CURVE_BSPLINE_TO_BSPLINE, '5' }, |
|
{ CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, '6' }, |
|
{ CURVE_KOCHANEK_BARTELS_TO_KOCHANEK_BARTELS, '7' }, |
|
{ CURVE_KOCHANEK_BARTELS_EARLY_TO_KOCHANEK_BARTELS_EARLY, '8' }, |
|
{ CURVE_KOCHANEK_BARTELS_LATE_TO_KOCHANEK_BARTELS_LATE, '9' }, |
|
{ CURVE_SIMPLE_CUBIC_TO_SIMPLE_CUBIC, '0' }, |
|
}; |
|
|
|
// Turn enum into string and vice versa |
|
int Interpolator_CurveTypeForName( const char *name ) |
|
{ |
|
char sz[ 128 ]; |
|
Q_strncpy( sz, name, sizeof( sz ) ); |
|
|
|
int leftcurve = 0; |
|
int rightcurve = 0; |
|
|
|
int skip = Q_strlen( "curve_" ); |
|
|
|
if ( !Q_strnicmp( sz, "curve_", skip ) ) |
|
{ |
|
char *p = sz + skip; |
|
char *second = Q_stristr( p, "_to_curve_" ); |
|
|
|
char save = *second; |
|
*second = 0; |
|
|
|
leftcurve = Interpolator_InterpolatorForName( p ); |
|
|
|
*second = save; |
|
|
|
p = second + Q_strlen( "_to_curve_" ); |
|
|
|
rightcurve = Interpolator_InterpolatorForName( p ); |
|
} |
|
|
|
return MAKE_CURVE_TYPE( leftcurve, rightcurve ); |
|
} |
|
|
|
const char *Interpolator_NameForCurveType( int type, bool printname ) |
|
{ |
|
static char outname[ 256 ]; |
|
|
|
int leftside = GET_LEFT_CURVE( type ); |
|
int rightside = GET_RIGHT_CURVE( type ); |
|
|
|
if ( !printname ) |
|
{ |
|
Q_snprintf( outname, sizeof( outname ), "curve_%s_to_curve_%s", |
|
Interpolator_NameForInterpolator( leftside, printname ), |
|
Interpolator_NameForInterpolator( rightside, printname ) ); |
|
} |
|
else |
|
{ |
|
Q_snprintf( outname, sizeof( outname ), "%s <-> %s", |
|
Interpolator_NameForInterpolator( leftside, printname ), |
|
Interpolator_NameForInterpolator( rightside, printname ) ); |
|
} |
|
|
|
return outname; |
|
} |
|
|
|
void Interpolator_CurveInterpolatorsForType( int type, int& inbound, int& outbound ) |
|
{ |
|
inbound = GET_LEFT_CURVE( type ); |
|
outbound = GET_RIGHT_CURVE( type ); |
|
} |
|
|
|
int Interpolator_CurveTypeForHotkey( int key ) |
|
{ |
|
int c = ARRAYSIZE( g_CurveNameMap ); |
|
for ( int i = 0; i < c; ++i ) |
|
{ |
|
CurveNameMap_t *slot = &g_CurveNameMap[ i ]; |
|
if ( slot->hotkey == key ) |
|
return slot->type; |
|
} |
|
|
|
return -1; |
|
} |
|
|
|
void Interpolator_GetKochanekBartelsParams( int interpolationType, float& tension, float& bias, float& continuity ) |
|
{ |
|
switch ( interpolationType ) |
|
{ |
|
default: |
|
tension = 0.0f; |
|
bias = 0.0f; |
|
continuity = 0.0f; |
|
Assert( 0 ); |
|
break; |
|
case INTERPOLATE_KOCHANEK_BARTELS: |
|
tension = 0.77f; |
|
bias = 0.0f; |
|
continuity = 0.77f; |
|
break; |
|
case INTERPOLATE_KOCHANEK_BARTELS_EARLY: |
|
tension = 0.77f; |
|
bias = -1.0f; |
|
continuity = 0.77f; |
|
break; |
|
case INTERPOLATE_KOCHANEK_BARTELS_LATE: |
|
tension = 0.77f; |
|
bias = 1.0f; |
|
continuity = 0.77f; |
|
break; |
|
} |
|
} |
|
|
|
void Interpolator_CurveInterpolate( int interpolationType, |
|
const Vector &vPre, |
|
const Vector &vStart, |
|
const Vector &vEnd, |
|
const Vector &vNext, |
|
float f, |
|
Vector &vOut ) |
|
{ |
|
vOut.Init(); |
|
|
|
switch ( interpolationType ) |
|
{ |
|
default: |
|
Warning( "Unknown interpolation type %d\n", |
|
(int)interpolationType ); |
|
// break; // Fall through and use catmull_rom as default |
|
case INTERPOLATE_DEFAULT: |
|
case INTERPOLATE_CATMULL_ROM_NORMALIZEX: |
|
Catmull_Rom_Spline_NormalizeX( |
|
vPre, |
|
vStart, |
|
vEnd, |
|
vNext, |
|
f, |
|
vOut ); |
|
break; |
|
case INTERPOLATE_CATMULL_ROM: |
|
Catmull_Rom_Spline( |
|
vPre, |
|
vStart, |
|
vEnd, |
|
vNext, |
|
f, |
|
vOut ); |
|
break; |
|
case INTERPOLATE_CATMULL_ROM_NORMALIZE: |
|
Catmull_Rom_Spline_Normalize( |
|
vPre, |
|
vStart, |
|
vEnd, |
|
vNext, |
|
f, |
|
vOut ); |
|
break; |
|
case INTERPOLATE_CATMULL_ROM_TANGENT: |
|
Catmull_Rom_Spline_Tangent( |
|
vPre, |
|
vStart, |
|
vEnd, |
|
vNext, |
|
f, |
|
vOut ); |
|
break; |
|
case INTERPOLATE_EASE_IN: |
|
{ |
|
f = sin( M_PI * f * 0.5f ); |
|
// Fixme, since this ignores vPre and vNext we could omit computing them aove |
|
VectorLerp( vStart, vEnd, f, vOut ); |
|
} |
|
break; |
|
case INTERPOLATE_EASE_OUT: |
|
{ |
|
f = 1.0f - sin( M_PI * f * 0.5f + 0.5f * M_PI ); |
|
// Fixme, since this ignores vPre and vNext we could omit computing them aove |
|
VectorLerp( vStart, vEnd, f, vOut ); |
|
} |
|
break; |
|
case INTERPOLATE_EASE_INOUT: |
|
{ |
|
f = SimpleSpline( f ); |
|
// Fixme, since this ignores vPre and vNext we could omit computing them aove |
|
VectorLerp( vStart, vEnd, f, vOut ); |
|
} |
|
break; |
|
case INTERPOLATE_LINEAR_INTERP: |
|
// Fixme, since this ignores vPre and vNext we could omit computing them aove |
|
VectorLerp( vStart, vEnd, f, vOut ); |
|
break; |
|
case INTERPOLATE_KOCHANEK_BARTELS: |
|
case INTERPOLATE_KOCHANEK_BARTELS_EARLY: |
|
case INTERPOLATE_KOCHANEK_BARTELS_LATE: |
|
{ |
|
float t, b, c; |
|
Interpolator_GetKochanekBartelsParams( interpolationType, t, b, c ); |
|
Kochanek_Bartels_Spline_NormalizeX |
|
( |
|
t, b, c, |
|
vPre, |
|
vStart, |
|
vEnd, |
|
vNext, |
|
f, |
|
vOut |
|
); |
|
} |
|
break; |
|
case INTERPOLATE_SIMPLE_CUBIC: |
|
Cubic_Spline_NormalizeX( |
|
vPre, |
|
vStart, |
|
vEnd, |
|
vNext, |
|
f, |
|
vOut ); |
|
break; |
|
case INTERPOLATE_BSPLINE: |
|
BSpline( |
|
vPre, |
|
vStart, |
|
vEnd, |
|
vNext, |
|
f, |
|
vOut ); |
|
break; |
|
case INTERPOLATE_EXPONENTIAL_DECAY: |
|
{ |
|
float dt = vEnd.x - vStart.x; |
|
if ( dt > 0.0f ) |
|
{ |
|
float val = 1.0f - ExponentialDecay( 0.001, dt, f * dt ); |
|
vOut.y = vStart.y + val * ( vEnd.y - vStart.y ); |
|
} |
|
else |
|
{ |
|
vOut.y = vStart.y; |
|
} |
|
} |
|
break; |
|
case INTERPOLATE_HOLD: |
|
{ |
|
vOut.y = vStart.y; |
|
} |
|
break; |
|
} |
|
} |
|
|
|
void Interpolator_CurveInterpolate_NonNormalized( int interpolationType, |
|
const Vector &vPre, |
|
const Vector &vStart, |
|
const Vector &vEnd, |
|
const Vector &vNext, |
|
float f, |
|
Vector &vOut ) |
|
{ |
|
vOut.Init(); |
|
|
|
switch ( interpolationType ) |
|
{ |
|
default: |
|
Warning( "Unknown interpolation type %d\n", |
|
(int)interpolationType ); |
|
// break; // Fall through and use catmull_rom as default |
|
case INTERPOLATE_CATMULL_ROM_NORMALIZEX: |
|
case INTERPOLATE_DEFAULT: |
|
case INTERPOLATE_CATMULL_ROM: |
|
case INTERPOLATE_CATMULL_ROM_NORMALIZE: |
|
case INTERPOLATE_CATMULL_ROM_TANGENT: |
|
Catmull_Rom_Spline( |
|
vPre, |
|
vStart, |
|
vEnd, |
|
vNext, |
|
f, |
|
vOut ); |
|
break; |
|
case INTERPOLATE_EASE_IN: |
|
{ |
|
f = sin( M_PI * f * 0.5f ); |
|
// Fixme, since this ignores vPre and vNext we could omit computing them aove |
|
VectorLerp( vStart, vEnd, f, vOut ); |
|
} |
|
break; |
|
case INTERPOLATE_EASE_OUT: |
|
{ |
|
f = 1.0f - sin( M_PI * f * 0.5f + 0.5f * M_PI ); |
|
// Fixme, since this ignores vPre and vNext we could omit computing them aove |
|
VectorLerp( vStart, vEnd, f, vOut ); |
|
} |
|
break; |
|
case INTERPOLATE_EASE_INOUT: |
|
{ |
|
f = SimpleSpline( f ); |
|
// Fixme, since this ignores vPre and vNext we could omit computing them aove |
|
VectorLerp( vStart, vEnd, f, vOut ); |
|
} |
|
break; |
|
case INTERPOLATE_LINEAR_INTERP: |
|
// Fixme, since this ignores vPre and vNext we could omit computing them aove |
|
VectorLerp( vStart, vEnd, f, vOut ); |
|
break; |
|
case INTERPOLATE_KOCHANEK_BARTELS: |
|
case INTERPOLATE_KOCHANEK_BARTELS_EARLY: |
|
case INTERPOLATE_KOCHANEK_BARTELS_LATE: |
|
{ |
|
float t, b, c; |
|
Interpolator_GetKochanekBartelsParams( interpolationType, t, b, c ); |
|
Kochanek_Bartels_Spline |
|
( |
|
t, b, c, |
|
vPre, |
|
vStart, |
|
vEnd, |
|
vNext, |
|
f, |
|
vOut |
|
); |
|
} |
|
break; |
|
case INTERPOLATE_SIMPLE_CUBIC: |
|
Cubic_Spline( |
|
vPre, |
|
vStart, |
|
vEnd, |
|
vNext, |
|
f, |
|
vOut ); |
|
break; |
|
case INTERPOLATE_BSPLINE: |
|
BSpline( |
|
vPre, |
|
vStart, |
|
vEnd, |
|
vNext, |
|
f, |
|
vOut ); |
|
break; |
|
case INTERPOLATE_EXPONENTIAL_DECAY: |
|
{ |
|
float dt = vEnd.x - vStart.x; |
|
if ( dt > 0.0f ) |
|
{ |
|
float val = 1.0f - ExponentialDecay( 0.001, dt, f * dt ); |
|
vOut.y = vStart.y + val * ( vEnd.y - vStart.y ); |
|
} |
|
else |
|
{ |
|
vOut.y = vStart.y; |
|
} |
|
} |
|
break; |
|
case INTERPOLATE_HOLD: |
|
{ |
|
vOut.y = vStart.y; |
|
} |
|
break; |
|
} |
|
} |
|
|
|
|
|
void Interpolator_CurveInterpolate_NonNormalized( int interpolationType, |
|
const Quaternion &vPre, |
|
const Quaternion &vStart, |
|
const Quaternion &vEnd, |
|
const Quaternion &vNext, |
|
float f, |
|
Quaternion &vOut ) |
|
{ |
|
vOut.Init(); |
|
|
|
switch ( interpolationType ) |
|
{ |
|
default: |
|
Warning( "Unknown interpolation type %d\n", |
|
(int)interpolationType ); |
|
// break; // Fall through and use catmull_rom as default |
|
case INTERPOLATE_CATMULL_ROM_NORMALIZEX: |
|
case INTERPOLATE_DEFAULT: |
|
case INTERPOLATE_CATMULL_ROM: |
|
case INTERPOLATE_CATMULL_ROM_NORMALIZE: |
|
case INTERPOLATE_CATMULL_ROM_TANGENT: |
|
case INTERPOLATE_KOCHANEK_BARTELS: |
|
case INTERPOLATE_KOCHANEK_BARTELS_EARLY: |
|
case INTERPOLATE_KOCHANEK_BARTELS_LATE: |
|
case INTERPOLATE_SIMPLE_CUBIC: |
|
case INTERPOLATE_BSPLINE: |
|
// FIXME, since this ignores vPre and vNext we could omit computing them aove |
|
QuaternionSlerp( vStart, vEnd, f, vOut ); |
|
break; |
|
case INTERPOLATE_EASE_IN: |
|
{ |
|
f = sin( M_PI * f * 0.5f ); |
|
// Fixme, since this ignores vPre and vNext we could omit computing them aove |
|
QuaternionSlerp( vStart, vEnd, f, vOut ); |
|
} |
|
break; |
|
case INTERPOLATE_EASE_OUT: |
|
{ |
|
f = 1.0f - sin( M_PI * f * 0.5f + 0.5f * M_PI ); |
|
// Fixme, since this ignores vPre and vNext we could omit computing them aove |
|
QuaternionSlerp( vStart, vEnd, f, vOut ); |
|
} |
|
break; |
|
case INTERPOLATE_EASE_INOUT: |
|
{ |
|
f = SimpleSpline( f ); |
|
// Fixme, since this ignores vPre and vNext we could omit computing them aove |
|
QuaternionSlerp( vStart, vEnd, f, vOut ); |
|
} |
|
break; |
|
case INTERPOLATE_LINEAR_INTERP: |
|
// Fixme, since this ignores vPre and vNext we could omit computing them aove |
|
QuaternionSlerp( vStart, vEnd, f, vOut ); |
|
break; |
|
case INTERPOLATE_EXPONENTIAL_DECAY: |
|
vOut.Init(); |
|
break; |
|
case INTERPOLATE_HOLD: |
|
{ |
|
vOut = vStart; |
|
} |
|
break; |
|
} |
|
} |