2020-04-22 12:56:21 -04:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
# include "movieobjects/dmelog.h"
# include "datamodel/dmelementfactoryhelper.h"
# include "datamodel/dmehandle.h"
# include "vstdlib/random.h"
# include "tier0/dbg.h"
# include <limits.h>
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
LayerSelectionData_t : : DataLayer_t : : DataLayer_t ( float frac , CDmeLogLayer * layer ) :
m_flStartFraction ( frac )
{
m_hData = layer ;
}
LayerSelectionData_t : : LayerSelectionData_t ( ) :
m_DataType ( AT_UNKNOWN ) ,
m_nDuration ( 0 ) ,
m_tStartOffset ( DMETIME_ZERO )
{
m_nHoldTimes [ 0 ] = m_nHoldTimes [ 1 ] = 0 ;
}
void LayerSelectionData_t : : Release ( )
{
for ( int i = 0 ; i < m_vecData . Count ( ) ; + + i )
{
DataLayer_t * dl = & m_vecData [ i ] ;
if ( dl - > m_hData . Get ( ) )
{
g_pDataModel - > DestroyElement ( dl - > m_hData - > GetHandle ( ) ) ;
}
}
m_vecData . Purge ( ) ;
}
//-----------------------------------------------------------------------------
// Interpolatable types
//-----------------------------------------------------------------------------
inline bool IsInterpolableType ( DmAttributeType_t type )
{
return ( type = = AT_FLOAT ) | |
( type = = AT_COLOR ) | |
( type = = AT_VECTOR2 ) | |
( type = = AT_VECTOR3 ) | |
( type = = AT_QANGLE ) | |
( type = = AT_QUATERNION ) ;
}
static Vector s_pInterolationPoints [ 4 ] =
{
Vector ( 0.0f , 0.0f , 0.0f ) ,
Vector ( 0.0f , 0.0f , 0.0f ) ,
Vector ( 1.0f , 1.0f , 0.0f ) ,
Vector ( 1.0f , 1.0f , 0.0f )
} ;
static inline float ComputeInterpolationFactor ( float flFactor , int nInterpolatorType )
{
Vector out ;
Interpolator_CurveInterpolate
(
nInterpolatorType ,
s_pInterolationPoints [ 0 ] , // unused
s_pInterolationPoints [ 1 ] ,
s_pInterolationPoints [ 2 ] ,
s_pInterolationPoints [ 3 ] , // unused
flFactor ,
out
) ;
return out . y ; // clamp( out.y, 0.0f, 1.0f );
}
float DmeLog_TimeSelection_t : : AdjustFactorForInterpolatorType ( float flFactor , int nSide ) const
{
return ComputeInterpolationFactor ( flFactor , m_nFalloffInterpolatorTypes [ nSide ] ) ;
}
//-----------------------------------------------------------------------------
// NOTE: See DmeTimeSelectionTimes_t for return values, -1 means before, TS_TIME_COUNT means after
//-----------------------------------------------------------------------------
static inline int ComputeRegionForTime ( DmeTime_t t , const DmeTime_t * pRegionTimes )
{
if ( t > = pRegionTimes [ TS_LEFT_HOLD ] )
{
if ( t < = pRegionTimes [ TS_RIGHT_HOLD ] )
return 2 ;
return ( t < = pRegionTimes [ TS_RIGHT_FALLOFF ] ) ? 3 : 4 ;
}
return ( t > = pRegionTimes [ TS_LEFT_FALLOFF ] ) ? 1 : 0 ;
}
//-----------------------------------------------------------------------------
// NOTE: See DmeTimeSelectionTimes_t for return values, -1 means before, TS_TIME_COUNT means after
//-----------------------------------------------------------------------------
int DmeLog_TimeSelection_t : : ComputeRegionForTime ( DmeTime_t curtime ) const
{
return : : ComputeRegionForTime ( curtime , m_nTimes ) ;
}
//-----------------------------------------------------------------------------
// per-type averaging methods
//-----------------------------------------------------------------------------
float DmeLog_TimeSelection_t : : GetAmountForTime ( DmeTime_t dmetime ) const
{
float minfrac = 0.0f ;
float t = dmetime . GetSeconds ( ) ;
// FIXME, this is slow, we should cache this maybe?
COMPILE_TIME_ASSERT ( TS_TIME_COUNT = = 4 ) ;
float times [ TS_TIME_COUNT ] ;
times [ 0 ] = m_nTimes [ 0 ] . GetSeconds ( ) ;
times [ 1 ] = m_nTimes [ 1 ] . GetSeconds ( ) ;
times [ 2 ] = m_nTimes [ 2 ] . GetSeconds ( ) ;
times [ 3 ] = m_nTimes [ 3 ] . GetSeconds ( ) ;
float dt1 , dt2 ;
dt1 = times [ 1 ] - times [ 0 ] ;
dt2 = times [ 3 ] - times [ 2 ] ;
if ( dt1 > 0.0f & & t > = times [ 0 ] & & t < times [ 1 ] )
{
float f = ( t - times [ 0 ] ) / dt1 ;
Vector out ;
Interpolator_CurveInterpolate
(
m_nFalloffInterpolatorTypes [ 0 ] ,
s_pInterolationPoints [ 0 ] , // unused
s_pInterolationPoints [ 1 ] ,
s_pInterolationPoints [ 2 ] ,
s_pInterolationPoints [ 3 ] , // unused
f ,
out
) ;
return clamp ( out . y , minfrac , 1.0f ) ;
}
if ( t > = times [ 1 ] & & t < = times [ 2 ] )
return 1.0f ;
if ( dt2 > 0.0f & & t > times [ 2 ] & & t < = times [ 3 ] )
{
float f = ( times [ 3 ] - t ) / dt2 ;
Vector out ;
Interpolator_CurveInterpolate
(
m_nFalloffInterpolatorTypes [ 1 ] ,
s_pInterolationPoints [ 0 ] , // unused
s_pInterolationPoints [ 1 ] ,
s_pInterolationPoints [ 2 ] ,
s_pInterolationPoints [ 3 ] , // unused
f ,
out
) ;
return clamp ( out . y , minfrac , 1.0f ) ;
}
return minfrac ;
}
// catch-all for non-interpolable types - just holds first value
template < class T >
T Average ( const T * pValues , int nValues )
{
if ( IsInterpolableType ( CDmAttributeInfo < T > : : AttributeType ( ) ) )
{
static bool first = true ;
if ( first )
{
first = false ;
Warning ( " CDmeLog: interpolable type %s doesn't have an averaging function! " , CDmAttributeInfo < T > : : AttributeTypeName ( ) ) ;
}
}
Assert ( nValues > 0 ) ;
if ( nValues < = 0 )
return T ( ) ; // uninitialized for most value classes!!!
return pValues [ 0 ] ;
}
// float version
template < >
float Average ( const float * pValues , int nValues )
{
Assert ( nValues > 0 ) ;
if ( nValues < = 0 )
return 0.0f ;
float sum = 0.0f ;
for ( int i = 0 ; i < nValues ; + + i )
{
sum + = pValues [ i ] ;
}
return sum / nValues ;
}
// Color version
template < >
Color Average ( const Color * pValues , int nValues )
{
Assert ( nValues > 0 ) ;
if ( nValues < = 0 )
return Color ( 0 , 0 , 0 , 0 ) ;
float r = 0.0f , g = 0.0f , b = 0.0f , a = 0.0f ;
for ( int i = 0 ; i < nValues ; + + i )
{
r + = pValues [ i ] . r ( ) ;
g + = pValues [ i ] . g ( ) ;
b + = pValues [ i ] . b ( ) ;
a + = pValues [ i ] . a ( ) ;
}
float inv = nValues ;
return Color ( r * inv , g * inv , b * inv , a * inv ) ;
}
// Vector2 version
template < >
Vector2D Average ( const Vector2D * pValues , int nValues )
{
Assert ( nValues > 0 ) ;
if ( nValues < = 0 )
return Vector2D ( 0.0f , 0.0f ) ;
Vector2D sum ( 0.0f , 0.0f ) ;
for ( int i = 0 ; i < nValues ; + + i )
{
sum + = pValues [ i ] ;
}
return sum / nValues ;
}
// Vector3 version
template < >
Vector Average ( const Vector * pValues , int nValues )
{
Assert ( nValues > 0 ) ;
if ( nValues < = 0 )
return Vector ( 0.0f , 0.0f , 0.0f ) ;
Vector sum ( 0.0f , 0.0f , 0.0f ) ;
for ( int i = 0 ; i < nValues ; + + i )
{
sum + = pValues [ i ] ;
}
return sum / nValues ;
}
// QAngle version
template < >
QAngle Average ( const QAngle * pValues , int nValues )
{
Assert ( nValues > 0 ) ;
if ( nValues < = 0 )
return QAngle ( 0.0f , 0.0f , 0.0f ) ;
Quaternion ave ;
AngleQuaternion ( pValues [ 0 ] , ave ) ;
// this is calculating the average by slerping with decreasing weights
// for example: ave = 1/3 * q2 + 2/3 ( 1/2 * q1 + 1/2 * q0 )
for ( int i = 1 ; i < nValues ; + + i )
{
Quaternion quat ;
AngleQuaternion ( pValues [ i ] , quat ) ;
QuaternionSlerp ( ave , quat , 1 / float ( i + 1 ) , ave ) ;
}
QAngle qangle ;
QuaternionAngles ( ave , qangle ) ;
return qangle ;
}
// Quaternion version
template < >
Quaternion Average ( const Quaternion * pValues , int nValues )
{
Assert ( nValues > 0 ) ;
if ( nValues < = 0 )
return Quaternion ( 0.0f , 0.0f , 0.0f , 1.0f ) ;
Quaternion ave = pValues [ 0 ] ;
// this is calculating the average by slerping with decreasing weights
// for example: ave = 1/3 * q2 + 2/3 ( 1/2 * q1 + 1/2 * q0 )
for ( int i = 1 ; i < nValues ; + + i )
{
QuaternionSlerp ( ave , pValues [ i ] , 1 / float ( i + 1 ) , ave ) ;
}
return ave ;
}
//-----------------------------------------------------------------------------
// per-type interpolation methods
//-----------------------------------------------------------------------------
// catch-all for non-interpolable types - just holds first value
template < class T >
T Interpolate ( float t , const T & ti , const T & tj )
{
if ( IsInterpolableType ( CDmAttributeInfo < T > : : AttributeType ( ) ) )
{
static bool first = true ;
if ( first )
{
first = false ;
Warning ( " CDmeLog: interpolable type %s doesn't have an interpolation function! " , CDmAttributeInfo < T > : : AttributeTypeName ( ) ) ;
}
}
return ti ;
}
// float version
template < >
float Interpolate ( float t , const float & ti , const float & tj )
{
return t * tj + ( 1.0f - t ) * ti ;
}
// Color version
template < >
Color Interpolate ( float t , const Color & ti , const Color & tj )
{
int ri , gi , bi , ai ;
int rj , gj , bj , aj ;
ti . GetColor ( ri , gi , bi , ai ) ;
tj . GetColor ( rj , gj , bj , aj ) ;
return Color ( t * rj + ( 1.0f - t ) * ri ,
t * gj + ( 1.0f - t ) * gi ,
t * bj + ( 1.0f - t ) * bi ,
t * aj + ( 1.0f - t ) * ai ) ;
}
// Vector2 version
template < >
Vector2D Interpolate ( float t , const Vector2D & ti , const Vector2D & tj )
{
return t * tj + ( 1.0f - t ) * ti ;
}
// Vector3 version
template < >
Vector Interpolate ( float t , const Vector & ti , const Vector & tj )
{
return t * tj + ( 1.0f - t ) * ti ;
}
// QAngle version
template < >
QAngle Interpolate ( float t , const QAngle & ti , const QAngle & tj )
{
QAngle qaResult ;
Quaternion q , qi , qj ; // Some Quaternion temps for doing the slerp
AngleQuaternion ( ti , qi ) ; // Convert QAngles to Quaternions
AngleQuaternion ( tj , qj ) ;
QuaternionSlerp ( qi , qj , t , q ) ; // Do a slerp as Quaternions
QuaternionAngles ( q , qaResult ) ; // Convert back to QAngles
return qaResult ;
}
// Quaternion version
template < >
Quaternion Interpolate ( float t , const Quaternion & ti , const Quaternion & tj )
{
static Quaternion s_value ;
QuaternionSlerp ( ti , tj , t , s_value ) ;
return s_value ;
}
// catch-all for non-interpolable types - just holds first value
template < class T >
T Curve_Interpolate ( float t , DmeTime_t times [ 4 ] , const T values [ 4 ] , int curveTypes [ 4 ] , float fmin , float fmax )
{
if ( IsInterpolableType ( CDmAttributeInfo < T > : : AttributeType ( ) ) )
{
static bool first = true ;
if ( first )
{
first = false ;
Warning ( " CDmeLog: interpolable type %s doesn't have an interpolation function! " , CDmAttributeInfo < T > : : AttributeTypeName ( ) ) ;
}
}
return t ;
}
// float version
template < >
float Curve_Interpolate ( float t , DmeTime_t times [ 4 ] , const float values [ 4 ] , int curveTypes [ 4 ] , float fmin , float fmax )
{
Vector args [ 4 ] ;
for ( int i = 0 ; i < 4 ; + + i )
{
args [ i ] . Init ( times [ i ] . GetSeconds ( ) , values [ i ] , 0.0f ) ;
}
Vector vOut ;
int dummy ;
int earlypart , laterpart ;
// Not holding out value of previous curve...
Interpolator_CurveInterpolatorsForType ( curveTypes [ 1 ] , dummy , earlypart ) ;
Interpolator_CurveInterpolatorsForType ( curveTypes [ 2 ] , laterpart , dummy ) ;
if ( earlypart = = INTERPOLATE_HOLD )
{
// Hold "out" of previous sample (can cause a discontinuity)
VectorLerp ( args [ 1 ] , args [ 2 ] , t , vOut ) ;
vOut . y = args [ 1 ] . y ;
}
else if ( laterpart = = INTERPOLATE_HOLD )
{
// Hold "out" of previous sample (can cause a discontinuity)
VectorLerp ( args [ 1 ] , args [ 2 ] , t , vOut ) ;
vOut . y = args [ 2 ] . y ;
}
else
{
bool sameCurveType = earlypart = = laterpart ? true : false ;
if ( sameCurveType )
{
Interpolator_CurveInterpolate ( laterpart , args [ 0 ] , args [ 1 ] , args [ 2 ] , args [ 3 ] , t , vOut ) ;
}
else // curves differ, sigh
{
Vector vOut1 , vOut2 ;
Interpolator_CurveInterpolate ( earlypart , args [ 0 ] , args [ 1 ] , args [ 2 ] , args [ 3 ] , t , vOut1 ) ;
Interpolator_CurveInterpolate ( laterpart , args [ 0 ] , args [ 1 ] , args [ 2 ] , args [ 3 ] , t , vOut2 ) ;
VectorLerp ( vOut1 , vOut2 , t , vOut ) ;
}
}
// FIXME: This means we can only work with curves that range from 0.0 to 1.0f!!!
float retval = clamp ( vOut . y , fmin , fmax ) ;
return retval ;
}
// Vector version
template < >
Vector Curve_Interpolate ( float t , DmeTime_t times [ 4 ] , const Vector values [ 4 ] , int curveTypes [ 4 ] , float fmin , float fmax )
{
Vector vOut ;
int dummy ;
int earlypart , laterpart ;
// Not holding out value of previous curve...
Interpolator_CurveInterpolatorsForType ( curveTypes [ 1 ] , dummy , earlypart ) ;
Interpolator_CurveInterpolatorsForType ( curveTypes [ 2 ] , laterpart , dummy ) ;
if ( earlypart = = INTERPOLATE_HOLD )
{
// Hold "out" of previous sample (can cause a discontinuity)
vOut = values [ 1 ] ;
}
else if ( laterpart = = INTERPOLATE_HOLD )
{
// Hold "out" of previous sample (can cause a discontinuity)
vOut = values [ 2 ] ;
}
else
{
bool sameCurveType = earlypart = = laterpart ;
if ( sameCurveType )
{
Interpolator_CurveInterpolate_NonNormalized ( laterpart , values [ 0 ] , values [ 1 ] , values [ 2 ] , values [ 3 ] , t , vOut ) ;
}
else // curves differ, sigh
{
Vector vOut1 , vOut2 ;
Interpolator_CurveInterpolate_NonNormalized ( earlypart , values [ 0 ] , values [ 1 ] , values [ 2 ] , values [ 3 ] , t , vOut1 ) ;
Interpolator_CurveInterpolate_NonNormalized ( laterpart , values [ 0 ] , values [ 1 ] , values [ 2 ] , values [ 3 ] , t , vOut2 ) ;
VectorLerp ( vOut1 , vOut2 , t , vOut ) ;
}
}
return vOut ;
}
// Quaternion version
template < >
Quaternion Curve_Interpolate ( float t , DmeTime_t times [ 4 ] , const Quaternion values [ 4 ] , int curveTypes [ 4 ] , float fmin , float fmax )
{
Quaternion vOut ;
int dummy ;
int earlypart , laterpart ;
// Not holding out value of previous curve...
Interpolator_CurveInterpolatorsForType ( curveTypes [ 1 ] , dummy , earlypart ) ;
Interpolator_CurveInterpolatorsForType ( curveTypes [ 2 ] , laterpart , dummy ) ;
if ( earlypart = = INTERPOLATE_HOLD )
{
// Hold "out" of previous sample (can cause a discontinuity)
vOut = values [ 1 ] ;
}
else if ( laterpart = = INTERPOLATE_HOLD )
{
// Hold "out" of previous sample (can cause a discontinuity)
vOut = values [ 2 ] ;
}
else
{
bool sameCurveType = ( earlypart = = laterpart ) ? true : false ;
if ( sameCurveType )
{
Interpolator_CurveInterpolate_NonNormalized ( laterpart , values [ 0 ] , values [ 1 ] , values [ 2 ] , values [ 3 ] , t , vOut ) ;
}
else // curves differ, sigh
{
Quaternion vOut1 , vOut2 ;
Interpolator_CurveInterpolate_NonNormalized ( earlypart , values [ 0 ] , values [ 1 ] , values [ 2 ] , values [ 3 ] , t , vOut1 ) ;
Interpolator_CurveInterpolate_NonNormalized ( laterpart , values [ 0 ] , values [ 1 ] , values [ 2 ] , values [ 3 ] , t , vOut2 ) ;
QuaternionSlerp ( vOut1 , vOut2 , t , vOut ) ;
}
}
return vOut ;
}
template < class T >
T ScaleValue ( const T & value , float scale )
{
return value * scale ;
}
template < >
bool ScaleValue ( const bool & value , float scale )
{
Assert ( 0 ) ;
return value ;
}
template < >
Color ScaleValue ( const Color & value , float scale )
{
Assert ( 0 ) ;
return value ;
}
template < >
Vector4D ScaleValue ( const Vector4D & value , float scale )
{
return Vector4D ( value . x * scale , value . y * scale , value . z * scale , value . w * scale ) ;
}
template < >
Quaternion ScaleValue ( const Quaternion & value , float scale )
{
return Quaternion ( value . x * scale , value . y * scale , value . z * scale , value . w * scale ) ;
}
template < >
VMatrix ScaleValue ( const VMatrix & value , float scale )
{
Assert ( 0 ) ;
return value ;
}
template < >
CUtlString ScaleValue ( const CUtlString & value , float scale )
{
Assert ( 0 ) ;
return value ;
}
template < class T >
float LengthOf ( const T & value )
{
return value ;
}
template < >
float LengthOf ( const bool & value )
{
if ( value )
return 1.0f ;
return 0.0f ;
}
template < >
float LengthOf ( const Color & value )
{
return ( float ) sqrt ( ( float ) ( value . r ( ) * value . r ( ) +
value . g ( ) * value . g ( ) +
value . b ( ) * value . b ( ) +
value . a ( ) * value . a ( ) ) ) ;
}
template < >
float LengthOf ( const Vector4D & value )
{
return sqrt ( value . x * value . x +
value . y * value . y +
value . z * value . z +
value . w * value . w ) ;
}
template < >
float LengthOf ( const Quaternion & value )
{
return sqrt ( value . x * value . x +
value . y * value . y +
value . z * value . z +
value . w * value . w ) ;
}
template < >
float LengthOf ( const VMatrix & value )
{
return 0.0f ;
}
template < >
float LengthOf ( const CUtlString & value )
{
return 0.0f ;
}
template < >
float LengthOf ( const Vector2D & value )
{
return value . Length ( ) ;
}
template < >
float LengthOf ( const Vector & value )
{
return value . Length ( ) ;
}
template < >
float LengthOf ( const QAngle & value )
{
return value . Length ( ) ;
}
template < class T >
T Subtract ( const T & v1 , const T & v2 )
{
return v1 - v2 ;
}
template < >
bool Subtract ( const bool & v1 , const bool & v2 )
{
return v1 ;
}
template < >
CUtlString Subtract ( const CUtlString & v1 , const CUtlString & v2 )
{
return v1 ;
}
template < >
Color Subtract ( const Color & v1 , const Color & v2 )
{
Color ret ;
for ( int i = 0 ; i < 4 ; + + i )
{
ret [ i ] = clamp ( v1 [ i ] - v2 [ i ] , 0 , 255 ) ;
}
return ret ;
}
template < >
Vector4D Subtract ( const Vector4D & v1 , const Vector4D & v2 )
{
Vector4D ret ;
for ( int i = 0 ; i < 4 ; + + i )
{
ret [ i ] = v1 [ i ] - v2 [ i ] ;
}
return ret ;
}
template < >
Quaternion Subtract ( const Quaternion & v1 , const Quaternion & v2 )
{
Quaternion ret ;
for ( int i = 0 ; i < 4 ; + + i )
{
ret [ i ] = v1 [ i ] ;
}
return ret ;
}
template < class T >
T Add ( const T & v1 , const T & v2 )
{
return v1 + v2 ;
}
template < >
bool Add ( const bool & v1 , const bool & v2 )
{
return v1 ;
}
template < >
CUtlString Add ( const CUtlString & v1 , const CUtlString & v2 )
{
return v1 ;
}
template < >
Color Add ( const Color & v1 , const Color & v2 )
{
Color ret ;
for ( int i = 0 ; i < 4 ; + + i )
{
ret [ i ] = clamp ( v1 [ i ] + v2 [ i ] , 0 , 255 ) ;
}
return ret ;
}
template < >
Vector4D Add ( const Vector4D & v1 , const Vector4D & v2 )
{
Vector4D ret ;
for ( int i = 0 ; i < 4 ; + + i )
{
ret [ i ] = v1 [ i ] + v2 [ i ] ;
}
return ret ;
}
template < >
Quaternion Add ( const Quaternion & v1 , const Quaternion & v2 )
{
return v1 ;
}
IMPLEMENT_ABSTRACT_ELEMENT ( DmeLogLayer , CDmeLogLayer ) ;
2023-05-11 21:08:32 +03:00
/*
2020-04-22 12:56:21 -04:00
IMPLEMENT_ELEMENT_FACTORY ( DmeIntLogLayer , CDmeIntLogLayer ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeFloatLogLayer , CDmeFloatLogLayer ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeBoolLogLayer , CDmeBoolLogLayer ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeColorLogLayer , CDmeColorLogLayer ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeVector2LogLayer , CDmeVector2LogLayer ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeVector3LogLayer , CDmeVector3LogLayer ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeVector4LogLayer , CDmeVector4LogLayer ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeQAngleLogLayer , CDmeQAngleLogLayer ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeQuaternionLogLayer , CDmeQuaternionLogLayer ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeVMatrixLogLayer , CDmeVMatrixLogLayer ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeStringLogLayer , CDmeStringLogLayer ) ;
2023-05-11 21:08:32 +03:00
*/
2020-04-22 12:56:21 -04:00
//-----------------------------------------------------------------------------
// explicit template instantiation
//-----------------------------------------------------------------------------
template class CDmeTypedLogLayer < int > ;
template class CDmeTypedLogLayer < float > ;
template class CDmeTypedLogLayer < bool > ;
template class CDmeTypedLogLayer < Color > ;
template class CDmeTypedLogLayer < Vector2D > ;
template class CDmeTypedLogLayer < Vector > ;
template class CDmeTypedLogLayer < Vector4D > ;
template class CDmeTypedLogLayer < QAngle > ;
template class CDmeTypedLogLayer < Quaternion > ;
template class CDmeTypedLogLayer < VMatrix > ;
template class CDmeTypedLogLayer < CUtlString > ;
IMPLEMENT_ABSTRACT_ELEMENT ( DmeCurveInfo , CDmeCurveInfo ) ;
2023-05-11 21:08:32 +03:00
/*
2020-04-22 12:56:21 -04:00
IMPLEMENT_ELEMENT_FACTORY ( DmeIntCurveInfo , CDmeIntCurveInfo ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeFloatCurveInfo , CDmeFloatCurveInfo ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeBoolCurveInfo , CDmeBoolCurveInfo ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeColorCurveInfo , CDmeColorCurveInfo ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeVector2CurveInfo , CDmeVector2CurveInfo ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeVector3CurveInfo , CDmeVector3CurveInfo ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeVector4CurveInfo , CDmeVector4CurveInfo ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeQAngleCurveInfo , CDmeQAngleCurveInfo ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeQuaternionCurveInfo , CDmeQuaternionCurveInfo ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeVMatrixCurveInfo , CDmeVMatrixCurveInfo ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeStringCurveInfo , CDmeStringCurveInfo ) ;
2023-05-11 21:08:32 +03:00
*/
2020-04-22 12:56:21 -04:00
//-----------------------------------------------------------------------------
// explicit template instantiation
//-----------------------------------------------------------------------------
template class CDmeTypedCurveInfo < int > ;
template class CDmeTypedCurveInfo < float > ;
template class CDmeTypedCurveInfo < bool > ;
template class CDmeTypedCurveInfo < Color > ;
template class CDmeTypedCurveInfo < Vector2D > ;
template class CDmeTypedCurveInfo < Vector > ;
template class CDmeTypedCurveInfo < Vector4D > ;
template class CDmeTypedCurveInfo < QAngle > ;
template class CDmeTypedCurveInfo < Quaternion > ;
template class CDmeTypedCurveInfo < VMatrix > ;
template class CDmeTypedCurveInfo < CUtlString > ;
//-----------------------------------------------------------------------------
// Class factory
//-----------------------------------------------------------------------------
IMPLEMENT_ABSTRACT_ELEMENT ( DmeLog , CDmeLog ) ;
2023-05-11 21:08:32 +03:00
/*
2020-04-22 12:56:21 -04:00
IMPLEMENT_ELEMENT_FACTORY ( DmeIntLog , CDmeIntLog ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeFloatLog , CDmeFloatLog ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeBoolLog , CDmeBoolLog ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeColorLog , CDmeColorLog ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeVector2Log , CDmeVector2Log ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeVector3Log , CDmeVector3Log ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeVector4Log , CDmeVector4Log ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeQAngleLog , CDmeQAngleLog ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeQuaternionLog , CDmeQuaternionLog ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeVMatrixLog , CDmeVMatrixLog ) ;
IMPLEMENT_ELEMENT_FACTORY ( DmeStringLog , CDmeStringLog ) ;
2023-05-11 21:08:32 +03:00
*/
2020-04-22 12:56:21 -04:00
//-----------------------------------------------------------------------------
// explicit template instantiation
//-----------------------------------------------------------------------------
template class CDmeTypedLog < int > ;
template class CDmeTypedLog < float > ;
template class CDmeTypedLog < bool > ;
template class CDmeTypedLog < Color > ;
template class CDmeTypedLog < Vector2D > ;
template class CDmeTypedLog < Vector > ;
template class CDmeTypedLog < Vector4D > ;
template class CDmeTypedLog < QAngle > ;
template class CDmeTypedLog < Quaternion > ;
template class CDmeTypedLog < VMatrix > ;
template class CDmeTypedLog < CUtlString > ;
//-----------------------------------------------------------------------------
// instantiate and initialize static vars
//-----------------------------------------------------------------------------
2023-05-11 21:08:32 +03:00
/*
2020-04-22 12:56:21 -04:00
float CDmeIntLog : : s_defaultThreshold = 0.0f ;
float CDmeFloatLog : : s_defaultThreshold = 0.0f ;
float CDmeBoolLog : : s_defaultThreshold = 0.0f ;
float CDmeColorLog : : s_defaultThreshold = 0.0f ;
float CDmeVector2Log : : s_defaultThreshold = 0.0f ;
float CDmeVector3Log : : s_defaultThreshold = 0.0f ;
float CDmeVector4Log : : s_defaultThreshold = 0.0f ;
float CDmeQAngleLog : : s_defaultThreshold = 0.0f ;
float CDmeQuaternionLog : : s_defaultThreshold = 0.0f ;
float CDmeVMatrixLog : : s_defaultThreshold = 0.0f ;
float CDmeStringLog : : s_defaultThreshold = 0.0f ;
2023-05-11 21:08:32 +03:00
*/
2020-04-22 12:56:21 -04:00
void CDmeLogLayer : : OnConstruction ( )
{
m_pOwnerLog = NULL ;
m_lastKey = 0 ;
m_times . Init ( this , " times " ) ;
m_CurveTypes . Init ( this , " curvetypes " ) ;
}
void CDmeLogLayer : : OnDestruction ( )
{
}
CDmeLog * CDmeLogLayer : : GetOwnerLog ( )
{
return m_pOwnerLog ;
}
const CDmeLog * CDmeLogLayer : : GetOwnerLog ( ) const
{
return m_pOwnerLog ;
}
DmeTime_t CDmeLogLayer : : GetBeginTime ( ) const
{
if ( m_times . Count ( ) = = 0 )
return DmeTime_t : : MinTime ( ) ;
return DmeTime_t ( m_times [ 0 ] ) ;
}
DmeTime_t CDmeLogLayer : : GetEndTime ( ) const
{
uint tn = m_times . Count ( ) ;
if ( tn = = 0 )
return DmeTime_t : : MaxTime ( ) ;
return DmeTime_t ( m_times [ tn - 1 ] ) ;
}
// Validates that all keys are correctly sorted in time
bool CDmeLogLayer : : ValidateKeys ( ) const
{
int nCount = m_times . Count ( ) ;
for ( int i = 1 ; i < nCount ; + + i )
{
if ( m_times [ i ] < = m_times [ i - 1 ] )
{
Warning ( " Error in log %s! Key times are out of order [keys %d->%d: %d->%d]! \n " ,
GetName ( ) , i - 1 , i , m_times [ i - 1 ] , m_times [ i ] ) ;
return false ;
}
}
return true ;
}
int CDmeLogLayer : : FindKey ( DmeTime_t time ) const
{
int tn = m_times . Count ( ) ;
if ( m_lastKey > = 0 & & m_lastKey < tn )
{
if ( time > = DmeTime_t ( m_times [ m_lastKey ] ) )
{
// common case - playing forward
for ( ; m_lastKey < tn - 1 ; + + m_lastKey )
{
if ( time < DmeTime_t ( m_times [ m_lastKey + 1 ] ) )
return m_lastKey ;
}
// if time past the end, return the last key
return m_lastKey ;
}
else
{
tn = m_lastKey ;
}
}
for ( int ti = tn - 1 ; ti > = 0 ; - - ti )
{
if ( time > = DmeTime_t ( m_times [ ti ] ) )
{
m_lastKey = ti ;
return ti ;
}
}
return - 1 ;
}
//-----------------------------------------------------------------------------
// Returns the number of keys
//-----------------------------------------------------------------------------
int CDmeLogLayer : : GetKeyCount ( ) const
{
return m_times . Count ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : nKeyIndex -
// keyTime -
//-----------------------------------------------------------------------------
void CDmeLogLayer : : SetKeyTime ( int nKeyIndex , DmeTime_t keyTime )
{
m_times . Set ( nKeyIndex , keyTime . GetTenthsOfMS ( ) ) ;
}
//-----------------------------------------------------------------------------
// Returns a specific key's value
//-----------------------------------------------------------------------------
DmeTime_t CDmeLogLayer : : GetKeyTime ( int nKeyIndex ) const
{
return DmeTime_t ( m_times [ nKeyIndex ] ) ;
}
//-----------------------------------------------------------------------------
// Scale + bias key times
//-----------------------------------------------------------------------------
void CDmeLogLayer : : ScaleBiasKeyTimes ( double flScale , DmeTime_t nBias )
{
// Don't waste time on the identity transform
if ( ( nBias = = DMETIME_ZERO ) & & ( fabs ( flScale - 1.0 ) < 1e-5 ) )
return ;
int nCount = GetKeyCount ( ) ;
for ( int i = 0 ; i < nCount ; + + i )
{
DmeTime_t t = GetKeyTime ( i ) ;
t . SetSeconds ( t . GetSeconds ( ) * flScale ) ;
t + = nBias ;
SetKeyTime ( i , t ) ;
}
}
//-----------------------------------------------------------------------------
// Returns the index of a particular key
//-----------------------------------------------------------------------------
int CDmeLogLayer : : FindKeyWithinTolerance ( DmeTime_t nTime , DmeTime_t nTolerance )
{
int nClosest = - 1 ;
DmeTime_t nClosestTolerance = DmeTime_t : : MaxTime ( ) ;
DmeTime_t nCurrTolerance ;
int start = 0 , end = GetKeyCount ( ) - 1 ;
while ( start < = end )
{
int mid = ( start + end ) > > 1 ;
DmeTime_t nDelta = nTime - DmeTime_t ( m_times [ mid ] ) ;
if ( nDelta > DmeTime_t ( 0 ) )
{
nCurrTolerance = nDelta ;
start = mid + 1 ;
}
else if ( nDelta < DmeTime_t ( 0 ) )
{
nCurrTolerance = - nDelta ;
end = mid - 1 ;
}
else
{
return mid ;
}
if ( nCurrTolerance < nClosestTolerance )
{
nClosest = mid ;
nClosestTolerance = nCurrTolerance ;
}
}
if ( nClosestTolerance > nTolerance )
return - 1 ;
return nClosest ;
}
void CDmeLogLayer : : OnUsingCurveTypesChanged ( )
{
if ( g_pDataModel - > IsUnserializing ( ) )
return ;
if ( ! IsUsingCurveTypes ( ) )
{
m_CurveTypes . RemoveAll ( ) ;
}
else
{
m_CurveTypes . RemoveAll ( ) ;
// Fill in an array with the default curve type for
int c = m_times . Count ( ) ;
for ( int i = 0 ; i < c ; + + i )
{
m_CurveTypes . AddToTail ( GetDefaultCurveType ( ) ) ;
}
}
}
bool CDmeLogLayer : : IsUsingCurveTypes ( ) const
{
return GetOwnerLog ( ) ? GetOwnerLog ( ) - > IsUsingCurveTypes ( ) : false ;
}
int CDmeLogLayer : : GetDefaultCurveType ( ) const
{
return GetOwnerLog ( ) - > GetDefaultCurveType ( ) ;
}
void CDmeLogLayer : : SetKeyCurveType ( int nKeyIndex , int curveType )
{
Assert ( GetOwnerLog ( ) ) ;
if ( ! GetOwnerLog ( ) )
return ;
Assert ( GetOwnerLog ( ) - > IsUsingCurveTypes ( ) ) ;
Assert ( m_CurveTypes . IsValidIndex ( nKeyIndex ) ) ;
if ( ! m_CurveTypes . IsValidIndex ( nKeyIndex ) )
return ;
m_CurveTypes . Set ( nKeyIndex , curveType ) ;
}
int CDmeLogLayer : : GetKeyCurveType ( int nKeyIndex ) const
{
Assert ( GetOwnerLog ( ) ) ;
if ( ! GetOwnerLog ( ) )
return CURVE_DEFAULT ;
Assert ( GetOwnerLog ( ) - > IsUsingCurveTypes ( ) ) ;
Assert ( m_CurveTypes . IsValidIndex ( nKeyIndex ) ) ;
if ( ! m_CurveTypes . IsValidIndex ( nKeyIndex ) )
return GetOwnerLog ( ) - > GetDefaultCurveType ( ) ;
return m_CurveTypes [ nKeyIndex ] ;
}
//-----------------------------------------------------------------------------
// Removes all keys outside the specified time range
//-----------------------------------------------------------------------------
void CDmeLogLayer : : RemoveKeysOutsideRange ( DmeTime_t tStart , DmeTime_t tEnd )
{
int i ;
int nKeysToRemove = 0 ;
int nKeyCount = m_times . Count ( ) ;
for ( i = 0 ; i < nKeyCount ; + + i , + + nKeysToRemove )
{
if ( m_times [ i ] > = tStart . GetTenthsOfMS ( ) )
break ;
}
if ( nKeysToRemove )
{
RemoveKey ( 0 , nKeysToRemove ) ;
}
nKeyCount = m_times . Count ( ) ;
for ( i = 0 ; i < nKeyCount ; + + i )
{
if ( m_times [ i ] > tEnd . GetTenthsOfMS ( ) )
break ;
}
nKeysToRemove = nKeyCount - i ;
if ( nKeysToRemove )
{
RemoveKey ( i , nKeysToRemove ) ;
}
}
template < class T >
class CUndoLayerAdded : public CUndoElement
{
typedef CUndoElement BaseClass ;
public :
CUndoLayerAdded ( const char * desc , CDmeLog * pLog ) :
BaseClass ( desc ) ,
m_bNeedsCleanup ( false ) ,
m_hLog ( pLog )
{
Assert ( pLog & & pLog - > GetFileId ( ) ! = DMFILEID_INVALID ) ;
}
virtual ~ CUndoLayerAdded ( )
{
if ( m_bNeedsCleanup )
{
g_pDataModel - > DestroyElement ( m_hLayer ) ;
}
}
virtual void Undo ( )
{
m_bNeedsCleanup = true ;
m_hLayer = m_hLog - > RemoveLayerFromTail ( ) - > GetHandle ( ) ;
g_pDataModel - > MarkHandleInvalid ( m_hLayer ) ;
}
virtual void Redo ( )
{
m_bNeedsCleanup = false ;
g_pDataModel - > MarkHandleValid ( m_hLayer ) ;
m_hLog - > AddLayerToTail ( GetElement < CDmeTypedLogLayer < T > > ( m_hLayer ) ) ;
}
virtual const char * GetDesc ( )
{
static char sz [ 512 ] ;
int iLayer = m_hLog - > GetTopmostLayer ( ) ;
if ( iLayer > = 0 )
{
CDmeLogLayer * layer = m_hLog - > GetLayer ( iLayer ) ;
Q_snprintf ( sz , sizeof ( sz ) , " addlayer: log %p lc[%d], layer %p " ,
m_hLog . Get ( ) , m_hLog - > GetNumLayers ( ) , layer ) ;
}
else
{
Q_snprintf ( sz , sizeof ( sz ) , " addlayer: log %p lc[%d], layer NULL " ,
m_hLog . Get ( ) , m_hLog - > GetNumLayers ( ) ) ;
}
return sz ;
}
private :
CDmeHandle < CDmeLog > m_hLog ;
bool m_bNeedsCleanup ;
CDmeCountedHandle m_hLayer ;
} ;
template < class T >
class CUndoFlattenLayers : public CUndoElement
{
typedef CUndoElement BaseClass ;
public :
CUndoFlattenLayers ( const char * desc , CDmeTypedLog < T > * pLog , float threshold , int flags ) :
BaseClass ( desc ) ,
m_bNeedsCleanup ( true ) ,
m_hLog ( pLog ) ,
m_nFlags ( flags ) ,
m_flThreshold ( threshold )
{
Assert ( pLog & & pLog - > GetFileId ( ) ! = DMFILEID_INVALID ) ;
LatchCurrentLayers ( ) ;
}
virtual ~ CUndoFlattenLayers ( )
{
if ( m_bNeedsCleanup )
{
for ( int i = 0 ; i < m_hLayers . Count ( ) ; + + i )
{
m_hLayers [ i ] = DMELEMENT_HANDLE_INVALID ;
# ifdef _DEBUG
CDmElement * pElement = g_pDataModel - > GetElement ( m_hLayers [ i ] ) ;
Assert ( ! pElement | | pElement - > IsStronglyReferenced ( ) ) ;
# endif
}
}
}
virtual void Undo ( )
{
m_bNeedsCleanup = false ;
for ( int i = 0 ; i < m_hLayers . Count ( ) ; + + i )
{
if ( i = = 0 )
{
// Copy base layer in place so handles to the base layer remain valid
CDmeTypedLogLayer < T > * base = m_hLog - > GetLayer ( i ) ;
base - > CopyLayer ( GetElement < CDmeTypedLogLayer < T > > ( m_hLayers [ i ] ) ) ;
// Release it since we didn't txfer it over
g_pDataModel - > DestroyElement ( m_hLayers [ i ] ) ;
}
else
{
// This transfers ownership, so no Release needed
m_hLog - > AddLayerToTail ( GetElement < CDmeTypedLogLayer < T > > ( m_hLayers [ i ] ) ) ;
}
}
m_hLayers . RemoveAll ( ) ;
}
virtual void Redo ( )
{
m_bNeedsCleanup = true ;
Assert ( m_hLayers . Count ( ) = = 0 ) ;
LatchCurrentLayers ( ) ;
// Flatten them again (won't create undo records since we're in undo already)
m_hLog - > FlattenLayers ( m_flThreshold , m_nFlags ) ;
}
virtual const char * GetDesc ( )
{
static char sz [ 512 ] ;
Q_snprintf ( sz , sizeof ( sz ) , " flatten log %p lc[%d] " ,
m_hLog . Get ( ) , m_hLayers . Count ( ) ) ;
return sz ;
}
private :
void LatchCurrentLayers ( )
{
CDisableUndoScopeGuard guard ;
Assert ( m_hLayers . Count ( ) = = 0 ) ;
Assert ( m_hLog - > GetNumLayers ( ) > = 1 ) ;
// Entry 0 is the original "base" layer
for ( int i = 0 ; i < m_hLog - > GetNumLayers ( ) ; + + i )
{
CDmeTypedLogLayer < T > * pLayer = CastElement < CDmeTypedLogLayer < T > > ( CreateLayer < T > ( m_hLog ) ) ;
pLayer - > CopyLayer ( m_hLog - > GetLayer ( i ) ) ;
m_hLayers . AddToTail ( pLayer - > GetHandle ( ) ) ;
}
}
CDmeHandle < CDmeTypedLog < T > > m_hLog ;
bool m_bNeedsCleanup ;
CUtlVector < CDmeCountedHandle > m_hLayers ;
int m_nFlags ;
float m_flThreshold ;
} ;
//-----------------------------------------------------------------------------
// CDmeTypedLogLayer - a generic typed layer used by a log
//-----------------------------------------------------------------------------
template < class T >
void CDmeTypedLogLayer < T > : : OnConstruction ( )
{
// m_times.Init( this, "times" );
// m_CurveTypes.Init( this, "curvetypes" );
m_values . Init ( this , " values " ) ;
}
template < class T >
void CDmeTypedLogLayer < T > : : SetOwnerLog ( CDmeLog * owner )
{
Assert ( owner ) ;
Assert ( assert_cast < CDmeTypedLog < T > * > ( owner ) ) ;
m_pOwnerLog = owner ;
}
template < class T >
CDmeTypedLog < T > * CDmeTypedLogLayer < T > : : GetTypedOwnerLog ( )
{
return assert_cast < CDmeTypedLog < T > * > ( m_pOwnerLog ) ;
}
template < class T >
const CDmeTypedLog < T > * CDmeTypedLogLayer < T > : : GetTypedOwnerLog ( ) const
{
return assert_cast < CDmeTypedLog < T > * > ( m_pOwnerLog ) ;
}
template < class T >
void CDmeTypedLogLayer < T > : : OnDestruction ( )
{
}
template < class T >
void CDmeTypedLogLayer < T > : : RemoveKeys ( DmeTime_t starttime )
{
int ti = FindKey ( starttime ) ;
if ( ti < 0 )
return ;
if ( starttime > DmeTime_t ( m_times [ ti ] ) )
+ + ti ;
int nKeys = m_times . Count ( ) - ti ;
if ( nKeys = = 0 )
return ;
m_times . RemoveMultiple ( ti , nKeys ) ;
m_values . RemoveMultiple ( ti , nKeys ) ;
if ( IsUsingCurveTypes ( ) )
{
m_CurveTypes . RemoveMultiple ( ti , nKeys ) ;
}
if ( m_lastKey > = ti & & m_lastKey < ti + nKeys )
{
m_lastKey = ( ti > 0 ) ? ti - 1 : 0 ;
}
}
template < class T >
void CDmeTypedLogLayer < T > : : ClearKeys ( )
{
m_times . RemoveAll ( ) ;
m_values . RemoveAll ( ) ;
m_CurveTypes . RemoveAll ( ) ;
m_lastKey = 0 ;
}
template < class T >
void CDmeTypedLogLayer < T > : : RemoveKey ( int nKeyIndex , int nNumKeysToRemove /*= 1*/ )
{
m_times . RemoveMultiple ( nKeyIndex , nNumKeysToRemove ) ;
m_values . RemoveMultiple ( nKeyIndex , nNumKeysToRemove ) ;
if ( IsUsingCurveTypes ( ) )
{
m_CurveTypes . RemoveMultiple ( nKeyIndex , nNumKeysToRemove ) ;
}
}
//-----------------------------------------------------------------------------
// Sets a key, removes all keys after this time
// FIXME: This needs to account for interpolation!!!
//-----------------------------------------------------------------------------
template < class T >
void CDmeTypedLogLayer < T > : : SetKey ( DmeTime_t time , const T & value , int curveType /*=CURVE_DEFAULT*/ )
{
Assert ( m_values . Count ( ) = = m_times . Count ( ) ) ;
Assert ( ! IsUsingCurveTypes ( ) | | ( m_CurveTypes . Count ( ) = = m_times . Count ( ) ) ) ;
// Remove all keys after this time
RemoveKeys ( time ) ;
// Add the key and then check to see if the penultimate key is still necessary
m_times . AddToTail ( time . GetTenthsOfMS ( ) ) ;
m_values . AddToTail ( value ) ;
if ( IsUsingCurveTypes ( ) )
{
m_CurveTypes . AddToTail ( curveType ) ;
}
int nKeys = m_values . Count ( ) ;
if ( ( nKeys < 3 ) | |
( IsUsingCurveTypes ( ) & & ( curveType ! = m_CurveTypes [ nKeys - 1 ] | | ( curveType ! = m_CurveTypes [ nKeys - 2 ] ) ) )
)
{
return ;
}
// If adding the new means that the penultimate key's value was unneeded, then we will remove the penultimate key value
T check = GetValueSkippingKey ( nKeys - 2 ) ;
T oldPenultimateValue = m_values [ nKeys - 2 ] ;
if ( GetTypedOwnerLog ( ) - > ValuesDiffer ( oldPenultimateValue , check ) )
{
return ;
}
// Remove penultimate, it's not needed
m_times . Remove ( nKeys - 2 ) ;
m_values . Remove ( nKeys - 2 ) ;
if ( IsUsingCurveTypes ( ) )
{
m_CurveTypes . Remove ( nKeys - 2 ) ;
}
}
//-----------------------------------------------------------------------------
// Finds a key within tolerance, or adds one
//-----------------------------------------------------------------------------
template < class T >
int CDmeTypedLogLayer < T > : : FindOrAddKey ( DmeTime_t nTime , DmeTime_t nTolerance , const T & value , int curveType /*=CURVE_DEFAULT*/ )
{
Assert ( m_values . Count ( ) = = m_times . Count ( ) ) ;
Assert ( ! IsUsingCurveTypes ( ) | | ( m_CurveTypes . Count ( ) = = m_times . Count ( ) ) ) ;
// NOTE: This math must occur in 64bits because the max delta nDelta
// can be 33 bits large. Bleah.
int nClosest = - 1 ;
int64 nClosestTolerance = DmeTime_t : : MinTime ( ) . GetTenthsOfMS ( ) ;
int64 nCurrTolerance ;
int start = 0 , end = GetKeyCount ( ) - 1 ;
while ( start < = end )
{
int mid = ( start + end ) > > 1 ;
int64 nDelta = ( int64 ) nTime . GetTenthsOfMS ( ) - ( int64 ) m_times [ mid ] ;
if ( nDelta > 0 )
{
nCurrTolerance = nDelta ;
start = mid + 1 ;
}
else if ( nDelta < 0 )
{
nCurrTolerance = - nDelta ;
end = mid - 1 ;
}
else
{
nClosest = end = mid ;
nClosestTolerance = 0 ;
break ;
}
if ( nCurrTolerance < nClosestTolerance )
{
nClosest = mid ;
nClosestTolerance = nCurrTolerance ;
}
}
// At this point, end is the entry less than or equal to the entry
if ( nClosest = = - 1 | | nTolerance . GetTenthsOfMS ( ) < nClosestTolerance )
{
+ + end ;
nClosest = m_times . InsertBefore ( end , nTime . GetTenthsOfMS ( ) ) ;
m_values . InsertBefore ( end , value ) ;
if ( IsUsingCurveTypes ( ) )
{
m_CurveTypes . InsertBefore ( end , curveType ) ;
}
}
return nClosest ;
}
//-----------------------------------------------------------------------------
// This inserts a key. Unlike SetKey, this will *not* delete keys after the specified time
//-----------------------------------------------------------------------------
template < class T >
int CDmeTypedLogLayer < T > : : InsertKey ( DmeTime_t nTime , const T & value , int curveType /*=CURVE_DEFAULT*/ )
{
int idx = FindOrAddKey ( nTime , DmeTime_t ( 0 ) , value ) ;
m_times . Set ( idx , nTime . GetTenthsOfMS ( ) ) ;
m_values . Set ( idx , value ) ;
if ( IsUsingCurveTypes ( ) )
{
m_CurveTypes . Set ( idx , curveType ) ;
}
return idx ;
}
template < class T >
int CDmeTypedLogLayer < T > : : InsertKeyAtTime ( DmeTime_t nTime , int curveType /*=CURVE_DEFAULT*/ )
{
T curVal = GetValue ( nTime ) ;
return InsertKey ( nTime , curVal , curveType ) ;
}
static bool CanInterpolateType ( DmAttributeType_t attType )
{
switch ( attType )
{
default :
return false ;
case AT_FLOAT :
case AT_VECTOR3 :
case AT_QUATERNION :
break ;
}
return true ;
}
template < class T >
const T & CDmeTypedLogLayer < T > : : GetValue ( DmeTime_t time ) const
{
// Curve Interpolation only for 1-D float data right now!!!
if ( IsUsingCurveTypes ( ) & &
CanInterpolateType ( GetDataType ( ) ) )
{
static T out ;
GetValueUsingCurveInfo ( time , out ) ;
return out ;
}
int tc = m_times . Count ( ) ;
Assert ( m_values . Count ( ) = = tc ) ;
Assert ( ! IsUsingCurveTypes ( ) | | ( m_CurveTypes . Count ( ) = = tc ) ) ;
int ti = FindKey ( time ) ;
if ( ti < 0 )
{
if ( tc > 0 )
return m_values [ 0 ] ;
const CDmeTypedLog < T > * pOwner = GetTypedOwnerLog ( ) ;
if ( pOwner - > HasDefaultValue ( ) )
return pOwner - > GetDefaultValue ( ) ;
static T s_value ;
CDmAttributeInfo < T > : : SetDefaultValue ( s_value ) ; // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
return s_value ;
}
// Early out if we're at the end
if ( ti > = tc - 1 )
return m_values [ ti ] ;
if ( ! IsInterpolableType ( GetDataType ( ) ) )
return m_values [ ti ] ;
// Figure out the lerp factor
float t = GetFractionOfTimeBetween ( time , DmeTime_t ( m_times [ ti ] ) , DmeTime_t ( m_times [ ti + 1 ] ) ) ;
static T s_value ;
s_value = Interpolate ( t , m_values [ ti ] , m_values [ ti + 1 ] ) ; // Compute the lerp between ti and ti+1
return s_value ;
}
template < class T >
void CDmeTypedLogLayer < T > : : SetKey ( DmeTime_t time , const CDmAttribute * pAttr , uint index , int curveType /*= CURVE_DEFAULT*/ )
{
DmAttributeType_t type = pAttr - > GetType ( ) ;
if ( IsValueType ( type ) )
{
Assert ( pAttr - > GetType ( ) = = GetDataType ( ) ) ;
SetKey ( time , pAttr - > GetValue < T > ( ) , curveType ) ;
}
else if ( IsArrayType ( type ) )
{
Assert ( ArrayTypeToValueType ( type ) = = GetDataType ( ) ) ;
CDmrArrayConst < T > array ( pAttr ) ;
SetKey ( time , array [ index ] , curveType ) ;
}
else
{
Assert ( 0 ) ;
}
}
template < class T >
bool CDmeTypedLogLayer < T > : : SetDuplicateKeyAtTime ( DmeTime_t time )
{
int nKeys = m_times . Count ( ) ;
if ( nKeys = = 0 | | DmeTime_t ( m_times [ nKeys - 1 ] ) = = time )
return false ;
T value = GetValue ( time ) ;
// these two calls need to be separated (and we need to make an extra copy here) because
// CUtlVector has an assert to try to safeguard against inserting an existing value
// therefore, m_values.AddToTail( m_values[ i ] ) is illegal (or at least, triggers the assert)
SetKey ( time , value ) ;
return true ;
}
//-----------------------------------------------------------------------------
// Returns a specific key's value
//-----------------------------------------------------------------------------
template < class T >
const T & CDmeTypedLogLayer < T > : : GetKeyValue ( int nKeyIndex ) const
{
Assert ( m_values . Count ( ) = = m_times . Count ( ) ) ;
Assert ( ! IsUsingCurveTypes ( ) | | ( m_CurveTypes . Count ( ) = = m_times . Count ( ) ) ) ;
return m_values [ nKeyIndex ] ;
}
template < class T >
void CDmeTypedLogLayer < T > : : GetValue ( DmeTime_t time , CDmAttribute * pAttr , uint index ) const
{
DmAttributeType_t attrtype = pAttr - > GetType ( ) ;
if ( IsValueType ( attrtype ) )
{
Assert ( attrtype = = GetDataType ( ) ) ;
pAttr - > SetValue ( GetValue ( time ) ) ;
}
else if ( IsArrayType ( attrtype ) )
{
Assert ( ArrayTypeToValueType ( attrtype ) = = GetDataType ( ) ) ;
CDmrArray < T > array ( pAttr ) ;
array . Set ( index , GetValue ( time ) ) ;
}
else
{
Assert ( 0 ) ;
}
}
template < class T >
float CDmeTypedLogLayer < T > : : GetComponent ( DmeTime_t time , int componentIndex ) const
{
return : : GetComponent ( GetValue ( time ) , componentIndex ) ;
}
template < class T >
void CDmeTypedLogLayer < T > : : SetKeyValue ( int nKey , const T & value )
{
Assert ( nKey > = 0 ) ;
Assert ( nKey < m_values . Count ( ) ) ;
m_values . Set ( nKey , value ) ;
}
//-----------------------------------------------------------------------------
// resampling and filtering
//-----------------------------------------------------------------------------
template < class T >
void CDmeTypedLogLayer < T > : : Resample ( DmeFramerate_t samplerate )
{
// FIXME: Might have to revisit how to determine "curve types" for "resampled points...
Assert ( ! IsUsingCurveTypes ( ) ) ;
// make sure we resample to include _at_least_ the existing time range
DmeTime_t begin = GetBeginTime ( ) ;
DmeTime_t end = GetEndTime ( ) ;
int nSamples = 2 + FrameForTime ( end - begin , samplerate ) ;
CUtlVector < int > resampledTimes ;
CUtlVector < T > resampledValues ;
CUtlVector < int > resampledCurveTypes ;
resampledValues . EnsureCapacity ( nSamples ) ;
resampledTimes . EnsureCapacity ( nSamples ) ;
DmeTime_t time ( begin ) ;
for ( int i = 0 ; i < nSamples ; + + i )
{
resampledTimes . AddToTail ( time . GetTenthsOfMS ( ) ) ;
resampledValues . AddToTail ( GetValue ( time ) ) ;
if ( IsUsingCurveTypes ( ) )
{
resampledCurveTypes . AddToTail ( CURVE_DEFAULT ) ;
}
time = time . TimeAtNextFrame ( samplerate ) ;
}
m_times . SwapArray ( resampledTimes ) ;
m_values . SwapArray ( resampledValues ) ;
if ( IsUsingCurveTypes ( ) )
{
m_CurveTypes . SwapArray ( resampledCurveTypes ) ;
}
}
template < class T >
void CDmeTypedLogLayer < T > : : Filter ( int nSampleRadius )
{
// Doesn't mess with curvetypes!!!
const CUtlVector < T > & values = m_values . Get ( ) ;
CUtlVector < T > filteredValues ;
int nValues = values . Count ( ) ;
filteredValues . EnsureCapacity ( nValues ) ;
for ( int i = 0 ; i < nValues ; + + i )
{
int nSamples = min ( nSampleRadius , min ( i , nValues - i - 1 ) ) ;
filteredValues . AddToTail ( Average ( values . Base ( ) + i - nSamples , 2 * nSamples + 1 ) ) ;
}
m_values . SwapArray ( filteredValues ) ;
}
template < class T >
void CDmeTypedLogLayer < T > : : Filter2 ( DmeTime_t sampleRadius )
{
// Doesn't mess with curvetypes!!!
const CUtlVector < T > & values = m_values . Get ( ) ;
CUtlVector < T > filteredValues ;
int nValues = values . Count ( ) ;
filteredValues . EnsureCapacity ( nValues ) ;
DmeTime_t earliest = DMETIME_ZERO ;
if ( nValues > 0 )
{
earliest = DmeTime_t ( m_times [ 0 ] ) ;
}
for ( int i = 0 ; i < nValues ; + + i )
{
T vals [ 3 ] ;
DmeTime_t t = GetKeyTime ( i ) ;
DmeTime_t t0 = t - sampleRadius ;
DmeTime_t t1 = t + sampleRadius ;
if ( t0 > = earliest )
{
vals [ 0 ] = GetValue ( t0 ) ;
}
else
{
vals [ 0 ] = m_values [ 0 ] ;
}
vals [ 1 ] = GetValue ( t ) ;
vals [ 2 ] = GetValue ( t1 ) ;
if ( i = = 0 | | i = = nValues - 1 )
{
filteredValues . AddToTail ( values [ i ] ) ;
}
else
{
filteredValues . AddToTail ( Average ( vals , 3 ) ) ;
}
}
m_values . SwapArray ( filteredValues ) ;
}
template < class T >
const T & CDmeTypedLogLayer < T > : : GetValueSkippingKey ( int nKeyToSkip ) const
{
// Curve Interpolation only for 1-D float data right now!!!
if ( IsUsingCurveTypes ( ) & & CanInterpolateType ( GetDataType ( ) ) )
{
static T out ;
GetValueUsingCurveInfoSkippingKey ( nKeyToSkip , out ) ;
return out ;
}
Assert ( m_values . Count ( ) = = m_times . Count ( ) ) ;
Assert ( ! IsUsingCurveTypes ( ) | | ( m_CurveTypes . Count ( ) = = m_times . Count ( ) ) ) ;
DmeTime_t time = GetKeyTime ( nKeyToSkip ) ;
int prevKey = nKeyToSkip - 1 ;
int nextKey = nKeyToSkip + 1 ;
DmeTime_t prevTime ;
T prevValue ;
int prevCurveType ;
DmeTime_t nextTime ;
T nextValue ;
int nextCurveType ;
GetBoundedSample ( prevKey , prevTime , prevValue , prevCurveType ) ;
GetBoundedSample ( nextKey , nextTime , nextValue , nextCurveType ) ;
// Figure out the lerp factor
float t = GetFractionOfTimeBetween ( time , prevTime , nextTime ) ;
static T s_value ;
s_value = Interpolate ( t , prevValue , nextValue ) ;
return s_value ;
}
template < class T >
void CDmeTypedLog < T > : : RemoveRedundantKeys ( float threshold )
{
int bestLayer = GetTopmostLayer ( ) ;
if ( bestLayer < 0 )
return ;
GetLayer ( bestLayer ) - > RemoveRedundantKeys ( threshold ) ;
}
template < class T >
void CDmeTypedLogLayer < T > : : RemoveRedundantKeys ( float threshold )
{
Assert ( GetTypedOwnerLog ( ) ) ;
if ( ! GetTypedOwnerLog ( ) )
return ;
float saveThreshold ;
{
CDisableUndoScopeGuard sg ;
saveThreshold = GetTypedOwnerLog ( ) - > GetValueThreshold ( ) ;
GetTypedOwnerLog ( ) - > SetValueThreshold ( threshold ) ;
}
RemoveRedundantKeys ( ) ;
{
CDisableUndoScopeGuard sg ;
GetTypedOwnerLog ( ) - > SetValueThreshold ( saveThreshold ) ;
}
}
// Implementation of Douglas-Peucker curve simplification routine (hacked to only care about error against original curve (sort of 1D)
template < class T >
void CDmeTypedLogLayer < T > : : CurveSimplify_R ( float thresholdSqr , int startPoint , int endPoint , CDmeTypedLogLayer < T > * output )
{
if ( endPoint < = startPoint + 1 )
{
return ;
}
int maxPoint = startPoint ;
float maxDistanceSqr = 0.0f ;
for ( int i = startPoint + 1 ; i < endPoint ; + + i )
{
DmeTime_t keyTime = GetKeyTime ( i ) ;
T check = GetKeyValue ( i ) ;
T check2 = output - > GetValue ( keyTime ) ;
T dist = Subtract ( check , check2 ) ;
float distSqr = LengthOf ( dist ) * LengthOf ( dist ) ;
if ( distSqr < maxDistanceSqr )
continue ;
maxPoint = i ;
maxDistanceSqr = distSqr ;
}
if ( maxDistanceSqr > thresholdSqr )
{
output - > InsertKey ( GetKeyTime ( maxPoint ) , GetKeyValue ( maxPoint ) ) ;
CurveSimplify_R ( thresholdSqr , startPoint , maxPoint , output ) ;
CurveSimplify_R ( thresholdSqr , maxPoint , endPoint , output ) ;
}
}
template < > void CDmeTypedLogLayer < bool > : : CurveSimplify_R ( float thresholdSqr , int startPoint , int endPoint , CDmeTypedLogLayer < bool > * output ) { } ;
template < > void CDmeTypedLogLayer < int > : : CurveSimplify_R ( float thresholdSqr , int startPoint , int endPoint , CDmeTypedLogLayer < int > * output ) { } ;
template < > void CDmeTypedLogLayer < Color > : : CurveSimplify_R ( float thresholdSqr , int startPoint , int endPoint , CDmeTypedLogLayer < Color > * output ) { } ;
template < > void CDmeTypedLogLayer < Quaternion > : : CurveSimplify_R ( float thresholdSqr , int startPoint , int endPoint , CDmeTypedLogLayer < Quaternion > * output ) { } ;
template < > void CDmeTypedLogLayer < VMatrix > : : CurveSimplify_R ( float thresholdSqr , int startPoint , int endPoint , CDmeTypedLogLayer < VMatrix > * output ) { } ;
// We can't just walk the keys linearly since it'll accumulate too much error and give us a bad curve after simplification. We do a recursive subdivide which has a worst case of O(n^2) but
// probably is better than that in most cases.
template < class T >
void CDmeTypedLogLayer < T > : : RemoveRedundantKeys ( )
{
CDmeTypedLog < T > * pOwner = GetTypedOwnerLog ( ) ;
if ( ! pOwner )
return ;
int nKeys = GetKeyCount ( ) ;
if ( nKeys < = 2 )
return ;
float thresh = pOwner - > GetValueThreshold ( ) ;
if ( thresh < 0.0f )
return ;
CDmeTypedLogLayer < T > * save = 0 ;
{
CDisableUndoScopeGuard guard ;
save = CastElement < CDmeTypedLogLayer < T > > ( CreateLayer < T > ( pOwner ) ) ;
Assert ( save ) ;
save - > m_times . EnsureCapacity ( nKeys ) ;
save - > m_values . EnsureCapacity ( nKeys ) ;
// Insert start and end points as first "guess" at simplified curve
// Skip preceeding and ending keys that have the same value
int nFirstKey , nLastKey ;
for ( nFirstKey = 1 ; nFirstKey < nKeys ; + + nFirstKey )
{
// FIXME: Should we use a tolerance check here?
if ( GetKeyValue ( nFirstKey ) ! = GetKeyValue ( nFirstKey - 1 ) )
break ;
}
- - nFirstKey ;
for ( nLastKey = nKeys ; - - nLastKey > = 1 ; )
{
// FIXME: Should we use a tolerance check here?
if ( GetKeyValue ( nLastKey ) ! = GetKeyValue ( nLastKey - 1 ) )
break ;
}
if ( nLastKey < = nFirstKey )
{
save - > InsertKey ( GetKeyTime ( 0 ) , GetKeyValue ( 0 ) ) ;
}
else
{
if ( GetDataType ( ) = = AT_FLOAT )
{
save - > InsertKey ( GetKeyTime ( nFirstKey ) , GetKeyValue ( nFirstKey ) ) ;
save - > InsertKey ( GetKeyTime ( nLastKey ) , GetKeyValue ( nLastKey ) ) ;
// Recursively finds the point with the largest error from the "simplified curve" and subdivides the problem on both sides until the largest delta from the simplified
// curve is less than the tolerance (squared)
CurveSimplify_R ( thresh * thresh , nFirstKey , nLastKey , save ) ;
}
else
{
save - > InsertKey ( GetKeyTime ( nFirstKey ) , GetKeyValue ( nFirstKey ) ) ;
// copy over keys that differ from their prior or next keys - this keeps the first and last key of a run of same-valued keys
for ( int i = nFirstKey + 1 ; i < nLastKey ; + + i )
{
// prev is from the saved log to allow deleting runs of same-valued keys
const T & prev = save - > GetKeyValue ( save - > GetKeyCount ( ) - 1 ) ;
const T & curr = GetKeyValue ( i ) ;
const T & next = GetKeyValue ( i + 1 ) ;
if ( pOwner - > ValuesDiffer ( prev , curr ) | | pOwner - > ValuesDiffer ( curr , next ) )
{
save - > InsertKey ( GetKeyTime ( i ) , curr ) ;
}
}
save - > InsertKey ( GetKeyTime ( nLastKey ) , GetKeyValue ( nLastKey ) ) ;
}
}
}
// This operation is undoable
CopyLayer ( save ) ;
{
CDisableUndoScopeGuard guard ;
g_pDataModel - > DestroyElement ( save - > GetHandle ( ) ) ;
}
}
// curve info helpers
template < class T >
const CDmeTypedCurveInfo < T > * CDmeTypedLogLayer < T > : : GetTypedCurveInfo ( ) const
{
Assert ( GetTypedOwnerLog ( ) ) ;
return GetTypedOwnerLog ( ) - > GetTypedCurveInfo ( ) ;
}
template < class T >
CDmeTypedCurveInfo < T > * CDmeTypedLogLayer < T > : : GetTypedCurveInfo ( )
{
Assert ( GetTypedOwnerLog ( ) ) ;
return GetTypedOwnerLog ( ) - > GetTypedCurveInfo ( ) ;
}
template < class T >
bool CDmeTypedLogLayer < T > : : IsUsingEdgeInfo ( ) const
{
return GetTypedOwnerLog ( ) - > IsUsingEdgeInfo ( ) ;
}
template < class T >
const T & CDmeTypedLogLayer < T > : : GetDefaultEdgeZeroValue ( ) const
{
return GetTypedOwnerLog ( ) - > GetDefaultEdgeZeroValue ( ) ;
}
template < class T >
DmeTime_t CDmeTypedLogLayer < T > : : GetRightEdgeTime ( ) const
{
return GetTypedOwnerLog ( ) - > GetRightEdgeTime ( ) ;
}
template < class T >
void CDmeTypedLogLayer < T > : : GetEdgeInfo ( int edge , bool & active , T & val , int & curveType ) const
{
GetTypedOwnerLog ( ) - > GetEdgeInfo ( edge , active , val , curveType ) ;
}
template < class T >
int CDmeTypedLogLayer < T > : : GetEdgeCurveType ( int edge ) const
{
return GetTypedOwnerLog ( ) - > GetEdgeCurveType ( edge ) ;
}
template < class T >
void CDmeTypedLogLayer < T > : : GetZeroValue ( int side , T & val ) const
{
return GetTypedOwnerLog ( ) - > GetZeroValue ( side , val ) ;
}
template < class T >
void CDmeTypedLogLayer < T > : : GetBoundedSample ( int keyindex , DmeTime_t & time , T & val , int & curveType ) const
{
Assert ( GetOwnerLog ( ) ) ;
if ( ! GetOwnerLog ( ) )
{
time = DmeTime_t ( 0 ) ;
CDmAttributeInfo < T > : : SetDefaultValue ( val ) ;
curveType = CURVE_DEFAULT ;
return ;
}
if ( keyindex < 0 )
{
time = DmeTime_t ( 0 ) ;
GetZeroValue ( 0 , val ) ;
curveType = GetEdgeCurveType ( 0 ) ;
return ;
}
else if ( keyindex > = m_times . Count ( ) )
{
time = GetTypedOwnerLog ( ) - > GetRightEdgeTime ( ) ;
if ( time = = DmeTime_t ( 0 ) & & m_times . Count ( ) > 0 )
{
// Push it one msec past the final end time
time = DmeTime_t ( m_times [ m_times . Count ( ) - 1 ] ) + DmeTime_t ( 1 ) ;
}
GetTypedOwnerLog ( ) - > GetZeroValue ( 1 , val ) ;
curveType = GetTypedOwnerLog ( ) - > GetEdgeCurveType ( 1 ) ;
return ;
}
time = DmeTime_t ( m_times [ keyindex ] ) ;
val = m_values [ keyindex ] ;
if ( IsUsingCurveTypes ( ) )
{
curveType = m_CurveTypes [ keyindex ] ;
if ( curveType = = CURVE_DEFAULT )
{
curveType = GetTypedOwnerLog ( ) - > GetDefaultCurveType ( ) ;
}
}
}
template < >
void CDmeTypedLogLayer < float > : : GetValueUsingCurveInfoSkippingKey ( int nKeyToSkip , float & out ) const
{
Assert ( GetOwnerLog ( ) ) ;
if ( ! GetOwnerLog ( ) )
{
out = 0.0f ;
return ;
}
Assert ( CanInterpolateType ( GetDataType ( ) ) ) ;
Assert ( m_values . Count ( ) = = m_times . Count ( ) ) ;
Assert ( ! IsUsingCurveTypes ( ) | | ( m_CurveTypes . Count ( ) = = m_times . Count ( ) ) ) ;
Assert ( IsInterpolableType ( GetDataType ( ) ) ) ;
float v [ 4 ] ;
DmeTime_t t [ 4 ] ;
int curvetypes [ 4 ] ;
int ti = nKeyToSkip ;
DmeTime_t time = GetKeyTime ( nKeyToSkip ) ;
if ( ! IsUsingCurveTypes ( ) )
{
if ( ti < 0 )
{
CDmAttributeInfo < float > : : SetDefaultValue ( out ) ; // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
return ;
}
else if ( ti > = m_times . Count ( ) - 1 )
{
out = m_values [ ti + 1 ] ;
return ;
}
}
DmeTime_t finalTime = GetTypedOwnerLog ( ) - > GetRightEdgeTime ( ) ;
if ( finalTime ! = DmeTime_t ( 0 ) )
{
if ( time > finalTime )
{
GetZeroValue ( 1 , out ) ;
return ;
}
}
else
{
if ( ti > = m_times . Count ( ) - 1 )
{
out = m_values [ ti + 1 ] ;
return ;
}
}
GetBoundedSample ( ti - 2 , t [ 0 ] , v [ 0 ] , curvetypes [ 0 ] ) ;
GetBoundedSample ( ti - 1 , t [ 1 ] , v [ 1 ] , curvetypes [ 1 ] ) ;
GetBoundedSample ( ti + 1 , t [ 2 ] , v [ 2 ] , curvetypes [ 2 ] ) ;
GetBoundedSample ( ti + 2 , t [ 3 ] , v [ 3 ] , curvetypes [ 3 ] ) ;
float frac = 0.0f ;
if ( t [ 2 ] > t [ 1 ] )
{
frac = ( time . GetSeconds ( ) - t [ 1 ] . GetSeconds ( ) ) / ( float ) ( t [ 2 ] . GetSeconds ( ) - t [ 1 ] . GetSeconds ( ) ) ;
}
// Compute the lerp between ti and ti+1
out = Curve_Interpolate ( frac , t , v , curvetypes , GetOwnerLog ( ) - > GetMinValue ( ) , GetOwnerLog ( ) - > GetMaxValue ( ) ) ;
}
template < >
void CDmeTypedLogLayer < Vector > : : GetValueUsingCurveInfoSkippingKey ( int nKeyToSkip , Vector & out ) const
{
Assert ( GetOwnerLog ( ) ) ;
if ( ! GetOwnerLog ( ) )
{
CDmAttributeInfo < Vector > : : SetDefaultValue ( out ) ;
return ;
}
Assert ( CanInterpolateType ( GetDataType ( ) ) ) ;
Assert ( m_values . Count ( ) = = m_times . Count ( ) ) ;
Assert ( ! IsUsingCurveTypes ( ) | | ( m_CurveTypes . Count ( ) = = m_times . Count ( ) ) ) ;
Assert ( IsInterpolableType ( GetDataType ( ) ) ) ;
Vector v [ 4 ] ;
DmeTime_t t [ 4 ] ;
int curvetypes [ 4 ] ;
int ti = nKeyToSkip ;
DmeTime_t time = GetKeyTime ( nKeyToSkip ) ;
if ( ! IsUsingCurveTypes ( ) )
{
if ( ti < 0 )
{
CDmAttributeInfo < Vector > : : SetDefaultValue ( out ) ; // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
return ;
}
else if ( ti > = m_times . Count ( ) - 1 )
{
out = m_values [ ti + 1 ] ;
return ;
}
}
DmeTime_t finalTime = GetTypedOwnerLog ( ) - > GetRightEdgeTime ( ) ;
if ( finalTime ! = DmeTime_t ( 0 ) )
{
if ( time > finalTime )
{
CDmAttributeInfo < Vector > : : SetDefaultValue ( out ) ;
return ;
}
}
else
{
if ( ti > = m_times . Count ( ) - 1 )
{
out = m_values [ ti + 1 ] ;
return ;
}
}
GetBoundedSample ( ti - 2 , t [ 0 ] , v [ 0 ] , curvetypes [ 0 ] ) ;
GetBoundedSample ( ti - 1 , t [ 1 ] , v [ 1 ] , curvetypes [ 1 ] ) ;
GetBoundedSample ( ti + 1 , t [ 2 ] , v [ 2 ] , curvetypes [ 2 ] ) ;
GetBoundedSample ( ti + 2 , t [ 3 ] , v [ 3 ] , curvetypes [ 3 ] ) ;
float frac = 0.0f ;
if ( t [ 2 ] > t [ 1 ] )
{
frac = ( time . GetSeconds ( ) - t [ 1 ] . GetSeconds ( ) ) / ( float ) ( t [ 2 ] . GetSeconds ( ) - t [ 1 ] . GetSeconds ( ) ) ;
}
// Compute the lerp between ti and ti+1
out = Curve_Interpolate ( frac , t , v , curvetypes , GetOwnerLog ( ) - > GetMinValue ( ) , GetOwnerLog ( ) - > GetMaxValue ( ) ) ;
}
template < >
void CDmeTypedLogLayer < Quaternion > : : GetValueUsingCurveInfoSkippingKey ( int nKeyToSkip , Quaternion & out ) const
{
Assert ( GetOwnerLog ( ) ) ;
if ( ! GetOwnerLog ( ) )
{
CDmAttributeInfo < Quaternion > : : SetDefaultValue ( out ) ;
return ;
}
Assert ( CanInterpolateType ( GetDataType ( ) ) ) ;
Assert ( m_values . Count ( ) = = m_times . Count ( ) ) ;
Assert ( ! IsUsingCurveTypes ( ) | | ( m_CurveTypes . Count ( ) = = m_times . Count ( ) ) ) ;
Assert ( IsInterpolableType ( GetDataType ( ) ) ) ;
Quaternion v [ 4 ] ;
DmeTime_t t [ 4 ] ;
int curvetypes [ 4 ] ;
int ti = nKeyToSkip ;
DmeTime_t time = GetKeyTime ( nKeyToSkip ) ;
if ( ! IsUsingCurveTypes ( ) )
{
if ( ti < 0 )
{
CDmAttributeInfo < Quaternion > : : SetDefaultValue ( out ) ; // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
return ;
}
else if ( ti > = m_times . Count ( ) - 1 )
{
out = m_values [ ti + 1 ] ;
return ;
}
}
DmeTime_t finalTime = GetTypedOwnerLog ( ) - > GetRightEdgeTime ( ) ;
if ( finalTime ! = DmeTime_t ( 0 ) )
{
if ( time > finalTime )
{
CDmAttributeInfo < Quaternion > : : SetDefaultValue ( out ) ;
return ;
}
}
else
{
if ( ti > = m_times . Count ( ) - 1 )
{
out = m_values [ ti + 1 ] ;
return ;
}
}
GetBoundedSample ( ti - 2 , t [ 0 ] , v [ 0 ] , curvetypes [ 0 ] ) ;
GetBoundedSample ( ti - 1 , t [ 1 ] , v [ 1 ] , curvetypes [ 1 ] ) ;
GetBoundedSample ( ti + 1 , t [ 2 ] , v [ 2 ] , curvetypes [ 2 ] ) ;
GetBoundedSample ( ti + 2 , t [ 3 ] , v [ 3 ] , curvetypes [ 3 ] ) ;
float frac = 0.0f ;
if ( t [ 2 ] > t [ 1 ] )
{
frac = ( time . GetSeconds ( ) - t [ 1 ] . GetSeconds ( ) ) / ( float ) ( t [ 2 ] . GetSeconds ( ) - t [ 1 ] . GetSeconds ( ) ) ;
}
// Compute the lerp between ti and ti+1
out = Curve_Interpolate ( frac , t , v , curvetypes , GetOwnerLog ( ) - > GetMinValue ( ) , GetOwnerLog ( ) - > GetMaxValue ( ) ) ;
}
template < >
void CDmeTypedLogLayer < float > : : GetValueUsingCurveInfo ( DmeTime_t time , float & out ) const
{
Assert ( GetOwnerLog ( ) ) ;
if ( ! GetOwnerLog ( ) )
{
out = 0.0f ;
return ;
}
Assert ( CanInterpolateType ( GetDataType ( ) ) ) ;
Assert ( m_values . Count ( ) = = m_times . Count ( ) ) ;
Assert ( ! IsUsingCurveTypes ( ) | | ( m_CurveTypes . Count ( ) = = m_times . Count ( ) ) ) ;
Assert ( IsInterpolableType ( GetDataType ( ) ) ) ;
float v [ 4 ] ;
DmeTime_t t [ 4 ] ;
int curvetypes [ 4 ] ;
int ti = FindKey ( time ) ;
if ( ! IsUsingCurveTypes ( ) )
{
if ( ti < 0 )
{
CDmAttributeInfo < float > : : SetDefaultValue ( out ) ; // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
return ;
}
else if ( ti > = m_times . Count ( ) - 1 )
{
out = m_values [ ti ] ;
return ;
}
}
DmeTime_t finalTime = GetTypedOwnerLog ( ) - > GetRightEdgeTime ( ) ;
if ( finalTime ! = DmeTime_t ( 0 ) )
{
if ( time > finalTime )
{
GetZeroValue ( 1 , out ) ;
return ;
}
}
else
{
if ( ti > = m_times . Count ( ) - 1 )
{
out = m_values [ ti ] ;
return ;
}
}
GetBoundedSample ( ti - 1 , t [ 0 ] , v [ 0 ] , curvetypes [ 0 ] ) ;
GetBoundedSample ( ti + 0 , t [ 1 ] , v [ 1 ] , curvetypes [ 1 ] ) ;
GetBoundedSample ( ti + 1 , t [ 2 ] , v [ 2 ] , curvetypes [ 2 ] ) ;
GetBoundedSample ( ti + 2 , t [ 3 ] , v [ 3 ] , curvetypes [ 3 ] ) ;
float frac = 0.0f ;
if ( t [ 2 ] > t [ 1 ] )
{
frac = ( time . GetSeconds ( ) - t [ 1 ] . GetSeconds ( ) ) / ( float ) ( t [ 2 ] . GetSeconds ( ) - t [ 1 ] . GetSeconds ( ) ) ;
}
// Compute the lerp between ti and ti+1
out = Curve_Interpolate ( frac , t , v , curvetypes , GetOwnerLog ( ) - > GetMinValue ( ) , GetOwnerLog ( ) - > GetMaxValue ( ) ) ;
}
template < >
void CDmeTypedLogLayer < Vector > : : GetValueUsingCurveInfo ( DmeTime_t time , Vector & out ) const
{
Assert ( GetOwnerLog ( ) ) ;
if ( ! GetOwnerLog ( ) )
{
CDmAttributeInfo < Vector > : : SetDefaultValue ( out ) ;
return ;
}
Assert ( CanInterpolateType ( GetDataType ( ) ) ) ;
Assert ( m_values . Count ( ) = = m_times . Count ( ) ) ;
Assert ( ! IsUsingCurveTypes ( ) | | ( m_CurveTypes . Count ( ) = = m_times . Count ( ) ) ) ;
Assert ( IsInterpolableType ( GetDataType ( ) ) ) ;
Vector v [ 4 ] ;
DmeTime_t t [ 4 ] ;
int curvetypes [ 4 ] ;
int ti = FindKey ( time ) ;
if ( ! IsUsingCurveTypes ( ) )
{
if ( ti < 0 )
{
CDmAttributeInfo < Vector > : : SetDefaultValue ( out ) ; // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
return ;
}
else if ( ti > = m_times . Count ( ) - 1 )
{
out = m_values [ ti ] ;
return ;
}
}
DmeTime_t finalTime = GetTypedOwnerLog ( ) - > GetRightEdgeTime ( ) ;
if ( finalTime ! = DmeTime_t ( 0 ) )
{
if ( time > finalTime )
{
CDmAttributeInfo < Vector > : : SetDefaultValue ( out ) ;
return ;
}
}
else
{
if ( ti > = m_times . Count ( ) - 1 )
{
out = m_values [ ti ] ;
return ;
}
}
GetBoundedSample ( ti - 1 , t [ 0 ] , v [ 0 ] , curvetypes [ 0 ] ) ;
GetBoundedSample ( ti + 0 , t [ 1 ] , v [ 1 ] , curvetypes [ 1 ] ) ;
GetBoundedSample ( ti + 1 , t [ 2 ] , v [ 2 ] , curvetypes [ 2 ] ) ;
GetBoundedSample ( ti + 2 , t [ 3 ] , v [ 3 ] , curvetypes [ 3 ] ) ;
float frac = 0.0f ;
if ( t [ 2 ] > t [ 1 ] )
{
frac = ( time . GetSeconds ( ) - t [ 1 ] . GetSeconds ( ) ) / ( float ) ( t [ 2 ] . GetSeconds ( ) - t [ 1 ] . GetSeconds ( ) ) ;
}
// Compute the lerp between ti and ti+1
out = Curve_Interpolate ( frac , t , v , curvetypes , GetOwnerLog ( ) - > GetMinValue ( ) , GetOwnerLog ( ) - > GetMaxValue ( ) ) ;
}
template < >
void CDmeTypedLogLayer < Quaternion > : : GetValueUsingCurveInfo ( DmeTime_t time , Quaternion & out ) const
{
Assert ( GetOwnerLog ( ) ) ;
if ( ! GetOwnerLog ( ) )
{
CDmAttributeInfo < Quaternion > : : SetDefaultValue ( out ) ;
return ;
}
Assert ( CanInterpolateType ( GetDataType ( ) ) ) ;
Assert ( m_values . Count ( ) = = m_times . Count ( ) ) ;
Assert ( ! IsUsingCurveTypes ( ) | | ( m_CurveTypes . Count ( ) = = m_times . Count ( ) ) ) ;
Assert ( IsInterpolableType ( GetDataType ( ) ) ) ;
Quaternion v [ 4 ] ;
DmeTime_t t [ 4 ] ;
int curvetypes [ 4 ] ;
int ti = FindKey ( time ) ;
if ( ! IsUsingCurveTypes ( ) )
{
if ( ti < 0 )
{
CDmAttributeInfo < Quaternion > : : SetDefaultValue ( out ) ; // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
return ;
}
else if ( ti > = m_times . Count ( ) - 1 )
{
out = m_values [ ti ] ;
return ;
}
}
DmeTime_t finalTime = GetTypedOwnerLog ( ) - > GetRightEdgeTime ( ) ;
if ( finalTime ! = DmeTime_t ( 0 ) )
{
if ( time > finalTime )
{
CDmAttributeInfo < Quaternion > : : SetDefaultValue ( out ) ;
return ;
}
}
else
{
if ( ti > = m_times . Count ( ) - 1 )
{
out = m_values [ ti ] ;
return ;
}
}
GetBoundedSample ( ti - 1 , t [ 0 ] , v [ 0 ] , curvetypes [ 0 ] ) ;
GetBoundedSample ( ti + 0 , t [ 1 ] , v [ 1 ] , curvetypes [ 1 ] ) ;
GetBoundedSample ( ti + 1 , t [ 2 ] , v [ 2 ] , curvetypes [ 2 ] ) ;
GetBoundedSample ( ti + 2 , t [ 3 ] , v [ 3 ] , curvetypes [ 3 ] ) ;
float frac = 0.0f ;
if ( t [ 2 ] > t [ 1 ] )
{
frac = ( time . GetSeconds ( ) - t [ 1 ] . GetSeconds ( ) ) / ( float ) ( t [ 2 ] . GetSeconds ( ) - t [ 1 ] . GetSeconds ( ) ) ;
}
// Compute the lerp between ti and ti+1
out = Curve_Interpolate ( frac , t , v , curvetypes , GetOwnerLog ( ) - > GetMinValue ( ) , GetOwnerLog ( ) - > GetMaxValue ( ) ) ;
}
template < class T >
void CDmeTypedLogLayer < T > : : CopyLayer ( const CDmeLogLayer * src )
{
const CDmeTypedLogLayer < T > * pSrc = static_cast < const CDmeTypedLogLayer < T > * > ( src ) ;
m_times = pSrc - > m_times ;
m_lastKey = pSrc - > m_lastKey ;
m_values = pSrc - > m_values ;
m_CurveTypes = pSrc - > m_CurveTypes ;
}
template < class T >
void CDmeTypedLogLayer < T > : : InsertKeyFromLayer ( DmeTime_t keyTime , const CDmeLogLayer * src , DmeTime_t srcKeyTime )
{
const CDmeTypedLogLayer < T > * pSrc = static_cast < const CDmeTypedLogLayer < T > * > ( src ) ;
Assert ( pSrc ) ;
// NOTE: This copy is necessary if src == this
T value = pSrc - > GetValue ( srcKeyTime ) ;
InsertKey ( keyTime , value ) ;
}
template < class T >
void CDmeTypedLogLayer < T > : : ExplodeLayer ( const CDmeLogLayer * src , DmeTime_t startTime , DmeTime_t endTime , bool bRebaseTimestamps , DmeTime_t tResampleInterval )
{
const CDmeTypedLogLayer < T > * pSrc = static_cast < const CDmeTypedLogLayer < T > * > ( src ) ;
Assert ( pSrc ) ;
DmeTime_t tTimeOffset = DMETIME_ZERO ;
if ( bRebaseTimestamps )
{
tTimeOffset = - startTime ;
}
m_times . RemoveAll ( ) ;
m_values . RemoveAll ( ) ;
m_CurveTypes . RemoveAll ( ) ;
bool usecurvetypes = pSrc - > IsUsingCurveTypes ( ) ;
// Now copy the data for the later
for ( DmeTime_t t = startTime ; t + tResampleInterval < endTime ; t + = tResampleInterval )
{
DmeTime_t keyTime = DmeTime_t ( t ) ;
if ( keyTime > endTime )
{
keyTime = endTime ;
}
T val = pSrc - > GetValue ( keyTime ) ;
keyTime + = tTimeOffset ;
InsertKey ( keyTime , val , usecurvetypes ? GetDefaultCurveType ( ) : CURVE_DEFAULT ) ;
}
m_lastKey = m_times . Count ( ) - 1 ;
}
template < class T >
void CDmeTypedLogLayer < T > : : CopyPartialLayer ( const CDmeLogLayer * src , DmeTime_t startTime , DmeTime_t endTime , bool bRebaseTimestamps )
{
const CDmeTypedLogLayer < T > * pSrc = static_cast < const CDmeTypedLogLayer < T > * > ( src ) ;
Assert ( pSrc ) ;
int nTimeOffset = 0 ;
if ( bRebaseTimestamps )
{
nTimeOffset = - startTime . GetTenthsOfMS ( ) ;
}
m_times . RemoveAll ( ) ;
m_values . RemoveAll ( ) ;
m_CurveTypes . RemoveAll ( ) ;
bool usecurvetypes = pSrc - > IsUsingCurveTypes ( ) ;
// Now copy the data for the later
int c = pSrc - > m_times . Count ( ) ;
for ( int i = 0 ; i < c ; + + i )
{
DmeTime_t keyTime = DmeTime_t ( pSrc - > m_times [ i ] ) ;
if ( keyTime < startTime | | keyTime > endTime )
continue ;
m_times . AddToTail ( pSrc - > m_times [ i ] + nTimeOffset ) ;
m_values . AddToTail ( pSrc - > m_values [ i ] ) ;
if ( usecurvetypes )
{
m_CurveTypes . AddToTail ( pSrc - > m_CurveTypes [ i ] ) ;
}
}
m_lastKey = m_times . Count ( ) - 1 ;
}
//-----------------------------------------------------------------------------
// Creates a log of a specific type
//-----------------------------------------------------------------------------
template < class T >
CDmeLogLayer * CreateLayer < T > ( CDmeTypedLog < T > * pOwnerLog )
{
DmFileId_t fileid = pOwnerLog ? pOwnerLog - > GetFileId ( ) : DMFILEID_INVALID ;
CDmeLogLayer * layer = NULL ;
switch ( CDmAttributeInfo < T > : : AttributeType ( ) )
{
case AT_INT :
case AT_INT_ARRAY :
layer = CreateElement < CDmeIntLogLayer > ( " int log " , fileid ) ;
break ;
case AT_FLOAT :
case AT_FLOAT_ARRAY :
layer = CreateElement < CDmeFloatLogLayer > ( " float log " , fileid ) ;
break ;
case AT_BOOL :
case AT_BOOL_ARRAY :
layer = CreateElement < CDmeBoolLogLayer > ( " bool log " , fileid ) ;
break ;
case AT_COLOR :
case AT_COLOR_ARRAY :
layer = CreateElement < CDmeColorLogLayer > ( " color log " , fileid ) ;
break ;
case AT_VECTOR2 :
case AT_VECTOR2_ARRAY :
layer = CreateElement < CDmeVector2LogLayer > ( " vector2 log " , fileid ) ;
break ;
case AT_VECTOR3 :
case AT_VECTOR3_ARRAY :
layer = CreateElement < CDmeVector3LogLayer > ( " vector3 log " , fileid ) ;
break ;
case AT_VECTOR4 :
case AT_VECTOR4_ARRAY :
layer = CreateElement < CDmeVector4LogLayer > ( " vector4 log " , fileid ) ;
break ;
case AT_QANGLE :
case AT_QANGLE_ARRAY :
layer = CreateElement < CDmeQAngleLogLayer > ( " qangle log " , fileid ) ;
break ;
case AT_QUATERNION :
case AT_QUATERNION_ARRAY :
layer = CreateElement < CDmeQuaternionLogLayer > ( " quaternion log " , fileid ) ;
break ;
case AT_VMATRIX :
case AT_VMATRIX_ARRAY :
layer = CreateElement < CDmeVMatrixLogLayer > ( " vmatrix log " , fileid ) ;
break ;
case AT_STRING :
case AT_STRING_ARRAY :
layer = CreateElement < CDmeStringLogLayer > ( " string log " , fileid ) ;
break ;
}
if ( layer )
{
layer - > SetOwnerLog ( pOwnerLog ) ;
}
return layer ;
}
//-----------------------------------------------------------------------------
//
// CDmeCurveInfo - abstract base class
//
//-----------------------------------------------------------------------------
void CDmeCurveInfo : : OnConstruction ( )
{
m_DefaultCurveType . Init ( this , " defaultCurveType " ) ;
m_MinValue . InitAndSet ( this , " minvalue " , 0.0f ) ;
m_MaxValue . InitAndSet ( this , " maxvalue " , 1.0f ) ;
}
void CDmeCurveInfo : : OnDestruction ( )
{
}
// Global override for all keys unless overriden by specific key
void CDmeCurveInfo : : SetDefaultCurveType ( int curveType )
{
m_DefaultCurveType = curveType ;
}
int CDmeCurveInfo : : GetDefaultCurveType ( ) const
{
return m_DefaultCurveType . Get ( ) ;
}
void CDmeCurveInfo : : SetMinValue ( float val )
{
m_MinValue = val ;
}
float CDmeCurveInfo : : GetMinValue ( ) const
{
return m_MinValue ;
}
void CDmeCurveInfo : : SetMaxValue ( float val )
{
m_MaxValue = val ;
}
float CDmeCurveInfo : : GetMaxValue ( ) const
{
return m_MaxValue ;
}
//-----------------------------------------------------------------------------
//
// CDmeTypedCurveInfo - implementation class for all logs
//
//-----------------------------------------------------------------------------
template < class T >
void CDmeTypedCurveInfo < T > : : OnConstruction ( )
{
m_bUseEdgeInfo . Init ( this , " useEdgeInfo " ) ;
m_DefaultEdgeValue . Init ( this , " defaultEdgeZeroValue " ) ;
m_RightEdgeTime . Init ( this , " rightEdgeTime " ) ;
for ( int i = 0 ; i < 2 ; + + i )
{
char edgename [ 32 ] ;
Q_snprintf ( edgename , sizeof ( edgename ) , " %s " , i = = 0 ? " left " : " right " ) ;
char name [ 32 ] ;
Q_snprintf ( name , sizeof ( name ) , " %sEdgeActive " , edgename ) ;
m_bEdgeActive [ i ] . Init ( this , name ) ;
Q_snprintf ( name , sizeof ( name ) , " %sEdgeValue " , edgename ) ;
m_EdgeValue [ i ] . Init ( this , name ) ;
Q_snprintf ( name , sizeof ( name ) , " %sEdgeCurveType " , edgename ) ;
m_EdgeCurveType [ i ] . Init ( this , name ) ;
}
}
template < class T >
void CDmeTypedCurveInfo < T > : : OnDestruction ( )
{
}
template < class T >
void CDmeTypedCurveInfo < T > : : SetUseEdgeInfo ( bool state )
{
m_bUseEdgeInfo = state ;
}
template < class T >
bool CDmeTypedCurveInfo < T > : : IsUsingEdgeInfo ( ) const
{
return m_bUseEdgeInfo ;
}
template < class T >
void CDmeTypedCurveInfo < T > : : SetEdgeInfo ( int edge , bool active , const T & val , int curveType )
{
SetUseEdgeInfo ( true ) ;
Assert ( edge = = 0 | | edge = = 1 ) ;
m_bEdgeActive [ edge ] = active ;
m_EdgeValue [ edge ] = val ;
m_EdgeCurveType [ edge ] = curveType ;
}
template < class T >
void CDmeTypedCurveInfo < T > : : SetDefaultEdgeZeroValue ( const T & val )
{
m_DefaultEdgeValue = val ;
}
template < class T >
const T & CDmeTypedCurveInfo < T > : : GetDefaultEdgeZeroValue ( ) const
{
return m_DefaultEdgeValue ;
}
template < class T >
void CDmeTypedCurveInfo < T > : : SetRightEdgeTime ( DmeTime_t time )
{
m_RightEdgeTime = time . GetTenthsOfMS ( ) ;
}
template < class T >
DmeTime_t CDmeTypedCurveInfo < T > : : GetRightEdgeTime ( ) const
{
return DmeTime_t ( m_RightEdgeTime ) ;
}
template < class T >
void CDmeTypedCurveInfo < T > : : GetEdgeInfo ( int edge , bool & active , T & val , int & curveType ) const
{
Assert ( IsUsingEdgeInfo ( ) ) ;
Assert ( edge = = 0 | | edge = = 1 ) ;
active = m_bEdgeActive [ edge ] ;
val = m_EdgeValue [ edge ] ;
curveType = m_EdgeCurveType [ edge ] ;
}
template < class T >
int CDmeTypedCurveInfo < T > : : GetEdgeCurveType ( int edge ) const
{
Assert ( edge = = 0 | | edge = = 1 ) ;
if ( ! m_bEdgeActive [ edge ] )
{
return m_DefaultCurveType ;
}
if ( m_EdgeCurveType [ edge ] = = CURVE_DEFAULT )
{
return m_DefaultCurveType ;
}
return m_EdgeCurveType [ edge ] ;
}
template < >
void CDmeTypedCurveInfo < float > : : GetZeroValue ( int side , float & val ) const
{
if ( ! m_bUseEdgeInfo )
{
val = 0.0f ;
return ;
}
if ( m_bEdgeActive [ side ] )
{
val = m_EdgeValue [ side ] ;
return ;
}
val = m_DefaultEdgeValue ;
}
template < >
bool CDmeTypedCurveInfo < float > : : IsEdgeActive ( int edge ) const
{
return m_bEdgeActive [ edge ] ;
}
template < >
void CDmeTypedCurveInfo < float > : : GetEdgeValue ( int edge , float & value ) const
{
value = m_EdgeValue [ edge ] ;
}
template < >
void CDmeTypedCurveInfo < Vector > : : GetZeroValue ( int side , Vector & val ) const
{
if ( ! m_bUseEdgeInfo )
{
val = vec3_origin ;
return ;
}
if ( m_bEdgeActive [ side ] )
{
val = m_EdgeValue [ side ] ;
return ;
}
val = m_DefaultEdgeValue ;
}
template < >
void CDmeTypedCurveInfo < Quaternion > : : GetZeroValue ( int side , Quaternion & val ) const
{
if ( ! m_bUseEdgeInfo )
{
val . Init ( ) ;
return ;
}
if ( m_bEdgeActive [ side ] )
{
val = m_EdgeValue [ side ] ;
return ;
}
val = m_DefaultEdgeValue ;
}
//-----------------------------------------------------------------------------
//
// CDmeLog - abstract base class
//
//-----------------------------------------------------------------------------
void CDmeLog : : OnConstruction ( )
{
m_Layers . Init ( this , " layers " , FATTRIB_MUSTCOPY | FATTRIB_HAS_ARRAY_CALLBACK ) ;
m_CurveInfo . Init ( this , " curveinfo " , FATTRIB_MUSTCOPY | FATTRIB_HAS_CALLBACK ) ;
}
void CDmeLog : : OnDestruction ( )
{
}
int CDmeLog : : GetTopmostLayer ( ) const
{
return m_Layers . Count ( ) - 1 ;
}
int CDmeLog : : GetNumLayers ( ) const
{
return m_Layers . Count ( ) ;
}
CDmeLogLayer * CDmeLog : : GetLayer ( int index )
{
return m_Layers [ index ] ;
}
const CDmeLogLayer * CDmeLog : : GetLayer ( int index ) const
{
return m_Layers [ index ] ;
}
bool CDmeLog : : IsEmpty ( ) const
{
int c = m_Layers . Count ( ) ;
for ( int i = 0 ; i < c ; + + i )
{
CDmeLogLayer * layer = m_Layers [ i ] ;
if ( layer - > GetKeyCount ( ) > 0 )
return false ;
}
return true ;
}
void CDmeLog : : FindLayersForTime ( DmeTime_t time , CUtlVector < int > & list ) const
{
list . RemoveAll ( ) ;
int c = m_Layers . Count ( ) ;
// The base layer is always available!!!
if ( c > 0 )
{
list . AddToTail ( 0 ) ;
}
for ( int i = 1 ; i < c ; + + i )
{
CDmeLogLayer * layer = m_Layers [ i ] ;
DmeTime_t layerStart = layer - > GetBeginTime ( ) ;
if ( layerStart = = DmeTime_t : : MinTime ( ) )
continue ;
DmeTime_t layerEnd = layer - > GetEndTime ( ) ;
if ( layerEnd = = DmeTime_t : : MaxTime ( ) )
continue ;
if ( time > = layerStart & & time < = layerEnd )
{
list . AddToTail ( i ) ;
}
}
}
int CDmeLog : : FindLayerForTimeSkippingTopmost ( DmeTime_t time ) const
{
int c = m_Layers . Count ( ) - 1 ; // This makes it never consider the topmost layer!!!
for ( int i = c - 1 ; i > = 0 ; - - i )
{
CDmeLogLayer * layer = m_Layers [ i ] ;
DmeTime_t layerStart = layer - > GetBeginTime ( ) ;
if ( layerStart = = DmeTime_t : : MinTime ( ) )
continue ;
DmeTime_t layerEnd = layer - > GetEndTime ( ) ;
if ( layerEnd = = DmeTime_t : : MaxTime ( ) )
continue ;
if ( time > = layerStart & & time < = layerEnd )
return i ;
}
return ( c > 0 ) ? 0 : - 1 ;
}
int CDmeLog : : FindLayerForTime ( DmeTime_t time ) const
{
int c = m_Layers . Count ( ) ;
for ( int i = c - 1 ; i > = 0 ; - - i )
{
CDmeLogLayer * layer = m_Layers [ i ] ;
DmeTime_t layerStart = layer - > GetBeginTime ( ) ;
if ( layerStart = = DmeTime_t : : MinTime ( ) )
continue ;
DmeTime_t layerEnd = layer - > GetEndTime ( ) ;
if ( layerEnd = = DmeTime_t : : MaxTime ( ) )
continue ;
if ( time > = layerStart & & time < = layerEnd )
return i ;
}
return ( c > 0 ) ? 0 : - 1 ;
}
DmeTime_t CDmeLog : : GetBeginTime ( ) const
{
int c = m_Layers . Count ( ) ;
if ( c = = 0 )
return DmeTime_t : : MinTime ( ) ;
DmeTime_t bestMin = DmeTime_t : : MinTime ( ) ;
for ( int i = 0 ; i < c ; + + i )
{
CDmeLogLayer * layer = m_Layers [ i ] ;
DmeTime_t layerStart = layer - > GetBeginTime ( ) ;
if ( layerStart = = DmeTime_t : : MinTime ( ) )
continue ;
if ( bestMin = = DmeTime_t : : MinTime ( ) )
{
bestMin = layerStart ;
}
else if ( layerStart < bestMin )
{
bestMin = layerStart ;
}
}
return bestMin ;
}
DmeTime_t CDmeLog : : GetEndTime ( ) const
{
int c = m_Layers . Count ( ) ;
if ( c = = 0 )
return DmeTime_t : : MaxTime ( ) ;
DmeTime_t bestMax = DmeTime_t : : MaxTime ( ) ;
for ( int i = 0 ; i < c ; + + i )
{
CDmeLogLayer * layer = m_Layers [ i ] ;
DmeTime_t layerEnd = layer - > GetEndTime ( ) ;
if ( layerEnd = = DmeTime_t : : MaxTime ( ) )
continue ;
if ( bestMax = = DmeTime_t : : MaxTime ( ) )
{
bestMax = layerEnd ;
}
else if ( layerEnd > bestMax )
{
bestMax = layerEnd ;
}
}
return bestMax ;
}
//-----------------------------------------------------------------------------
// Returns the number of keys
//-----------------------------------------------------------------------------
int CDmeLog : : GetKeyCount ( ) const
{
int count = 0 ;
int c = m_Layers . Count ( ) ;
for ( int i = 0 ; i < c ; + + i )
{
CDmeLogLayer * layer = m_Layers [ i ] ;
int timecount = layer - > GetKeyCount ( ) ;
count + = timecount ;
}
return count ;
}
//-----------------------------------------------------------------------------
// Scale + bias key times
//-----------------------------------------------------------------------------
void CDmeLog : : ScaleBiasKeyTimes ( double flScale , DmeTime_t nBias )
{
// Don't waste time on the identity transform
if ( ( nBias = = DMETIME_ZERO ) & & ( fabs ( flScale - 1.0 ) < 1e-5 ) )
return ;
int nCount = GetNumLayers ( ) ;
for ( int i = 0 ; i < nCount ; + + i )
{
CDmeLogLayer * pLayer = GetLayer ( i ) ;
pLayer - > ScaleBiasKeyTimes ( flScale , nBias ) ;
}
}
//-----------------------------------------------------------------------------
// Resolve - keeps non-attribute data in sync with attribute data
//-----------------------------------------------------------------------------
void CDmeLog : : Resolve ( )
{
int c = m_Layers . Count ( ) ;
for ( int i = 0 ; i < c ; + + i )
{
CDmeLogLayer * layer = m_Layers [ i ] ;
layer - > SetOwnerLog ( this ) ;
}
}
void CDmeLog : : OnAttributeChanged ( CDmAttribute * pAttribute )
{
if ( pAttribute = = m_CurveInfo . GetAttribute ( ) )
{
OnUsingCurveTypesChanged ( ) ;
}
}
void CDmeLog : : OnUsingCurveTypesChanged ( )
{
int c = m_Layers . Count ( ) ;
for ( int i = 0 ; i < c ; + + i )
{
GetLayer ( i ) - > OnUsingCurveTypesChanged ( ) ;
}
}
// curve info helpers
bool CDmeLog : : IsUsingCurveTypes ( ) const
{
return m_CurveInfo . GetElement ( ) ! = NULL ;
}
const CDmeCurveInfo * CDmeLog : : GetCurveInfo ( ) const
{
return m_CurveInfo . GetElement ( ) ;
}
CDmeCurveInfo * CDmeLog : : GetCurveInfo ( )
{
return m_CurveInfo . GetElement ( ) ;
}
// accessors for CurveInfo data
int CDmeLog : : GetDefaultCurveType ( ) const
{
Assert ( IsUsingCurveTypes ( ) ) ;
return m_CurveInfo - > GetDefaultCurveType ( ) ;
}
// min/max accessors
float CDmeLog : : GetMinValue ( ) const
{
Assert ( IsUsingCurveTypes ( ) ) ;
return m_CurveInfo - > GetMinValue ( ) ;
}
void CDmeLog : : SetMinValue ( float val )
{
Assert ( IsUsingCurveTypes ( ) ) ;
m_CurveInfo - > SetMinValue ( val ) ;
}
float CDmeLog : : GetMaxValue ( ) const
{
Assert ( IsUsingCurveTypes ( ) ) ;
return m_CurveInfo - > GetMaxValue ( ) ;
}
void CDmeLog : : SetMaxValue ( float val )
{
Assert ( IsUsingCurveTypes ( ) ) ;
m_CurveInfo - > SetMaxValue ( val ) ;
}
void CDmeLog : : SetKeyCurveType ( int nKeyIndex , int curveType )
{
int bestLayer = GetTopmostLayer ( ) ;
if ( bestLayer < 0 )
return ;
GetLayer ( bestLayer ) - > SetKeyCurveType ( nKeyIndex , curveType ) ;
}
int CDmeLog : : GetKeyCurveType ( int nKeyIndex ) const
{
int bestLayer = GetTopmostLayer ( ) ;
if ( bestLayer < 0 )
return CURVE_DEFAULT ;
return GetLayer ( bestLayer ) - > GetKeyCurveType ( nKeyIndex ) ;
}
//-----------------------------------------------------------------------------
// Removes all keys in a certain time interval
//-----------------------------------------------------------------------------
bool CDmeLog : : RemoveKeys ( DmeTime_t tStartTime , DmeTime_t tEndTime )
{
CDmeLogLayer * pLayer = GetLayer ( GetTopmostLayer ( ) ) ;
int nKeyCount = pLayer - > GetKeyCount ( ) ;
int nFirstRemove = - 1 ;
int nLastRemove = - 1 ;
for ( int nKey = 0 ; nKey < nKeyCount ; + + nKey )
{
DmeTime_t tKeyTime = pLayer - > GetKeyTime ( nKey ) ;
if ( tKeyTime < tStartTime )
continue ;
if ( tKeyTime > tEndTime )
break ;
if ( nFirstRemove = = - 1 )
{
nFirstRemove = nKey ;
}
nLastRemove = nKey ;
}
if ( nFirstRemove ! = - 1 )
{
int nRemoveCount = nLastRemove - nFirstRemove + 1 ;
pLayer - > RemoveKey ( nFirstRemove , nRemoveCount ) ;
return true ;
}
return false ;
}
//-----------------------------------------------------------------------------
// CDmeTypedLog - implementation class for all logs
//-----------------------------------------------------------------------------
template < class T >
void CDmeTypedLog < T > : : OnConstruction ( )
{
if ( ! g_pDataModel - > IsUnserializing ( ) )
{
// Add the default layer!!!
AddNewLayer ( ) ;
Assert ( m_Layers . Count ( ) = = 1 ) ;
}
m_threshold = s_defaultThreshold ;
m_UseDefaultValue . InitAndSet ( this , " usedefaultvalue " , false ) ;
m_DefaultValue . Init ( this , " defaultvalue " ) ;
}
template < class T >
void CDmeTypedLog < T > : : OnDestruction ( )
{
}
template < class T >
void CDmeTypedLog < T > : : SetDefaultValue ( const T & value )
{
m_UseDefaultValue = true ;
m_DefaultValue . Set ( value ) ;
}
template < class T >
const T & CDmeTypedLog < T > : : GetDefaultValue ( ) const
{
Assert ( ( bool ) m_UseDefaultValue ) ;
return m_DefaultValue ;
}
template < class T >
bool CDmeTypedLog < T > : : HasDefaultValue ( ) const
{
return m_UseDefaultValue ;
}
template < class T >
void CDmeTypedLog < T > : : ClearDefaultValue ( )
{
m_UseDefaultValue = false ;
T out ;
CDmAttributeInfo < T > : : SetDefaultValue ( out ) ;
m_DefaultValue . Set ( out ) ;
}
// Only used by undo system!!!
template < class T >
void CDmeTypedLog < T > : : AddLayerToTail ( CDmeLogLayer * layer )
{
Assert ( layer ) ;
Assert ( ( static_cast < CDmeTypedLogLayer < T > * > ( layer ) ) - > GetTypedOwnerLog ( ) = = this ) ;
m_Layers . AddToTail ( layer ) ;
}
template < class T >
CDmeLogLayer * CDmeTypedLog < T > : : RemoveLayerFromTail ( )
{
Assert ( m_Layers . Count ( ) > = 1 ) ;
CDmeLogLayer * layer = m_Layers [ m_Layers . Count ( ) - 1 ] ;
m_Layers . Remove ( m_Layers . Count ( ) - 1 ) ;
return layer ;
}
template < class T >
CDmeLogLayer * CDmeTypedLog < T > : : RemoveLayer ( int iLayer )
{
Assert ( m_Layers . IsValidIndex ( iLayer ) ) ;
CDmeLogLayer * layer = m_Layers [ iLayer ] ;
m_Layers . Remove ( iLayer ) ;
return layer ;
}
template < class T >
CDmeLogLayer * CDmeTypedLog < T > : : AddNewLayer ( )
{
if ( g_pDataModel - > UndoEnabledForElement ( this ) )
{
CUndoLayerAdded < T > * pUndo = new CUndoLayerAdded < T > ( " AddNewLayer " , this ) ;
g_pDataModel - > AddUndoElement ( pUndo ) ;
}
CDisableUndoScopeGuard guard ;
// Now add the layer to the stack!!!
CDmeTypedLogLayer < T > * layer = static_cast < CDmeTypedLogLayer < T > * > ( CreateLayer < T > ( this ) ) ;
if ( layer )
{
layer - > SetOwnerLog ( this ) ;
m_Layers . AddToTail ( layer ) ;
}
return layer ;
}
// curve info helpers
template < class T >
const CDmeTypedCurveInfo < T > * CDmeTypedLog < T > : : GetTypedCurveInfo ( ) const
{
Assert ( ! m_CurveInfo . GetElement ( ) | | dynamic_cast < const CDmeTypedCurveInfo < T > * > ( m_CurveInfo . GetElement ( ) ) ) ;
return static_cast < const CDmeTypedCurveInfo < T > * > ( m_CurveInfo . GetElement ( ) ) ;
}
template < class T >
CDmeTypedCurveInfo < T > * CDmeTypedLog < T > : : GetTypedCurveInfo ( )
{
Assert ( ! m_CurveInfo . GetElement ( ) | | dynamic_cast < CDmeTypedCurveInfo < T > * > ( m_CurveInfo . GetElement ( ) ) ) ;
return static_cast < CDmeTypedCurveInfo < T > * > ( m_CurveInfo . GetElement ( ) ) ;
}
template < class T >
void CDmeTypedLog < T > : : SetCurveInfo ( CDmeCurveInfo * pCurveInfo )
{
Assert ( ! pCurveInfo | | dynamic_cast < CDmeTypedCurveInfo < T > * > ( pCurveInfo ) ) ;
m_CurveInfo = pCurveInfo ;
OnUsingCurveTypesChanged ( ) ; // FIXME: Is this really necessary? OnAttributeChanged should have already called this!
}
template < class T >
CDmeCurveInfo * CDmeTypedLog < T > : : GetOrCreateCurveInfo ( )
{
CDmeCurveInfo * pCurveInfo = m_CurveInfo . GetElement ( ) ;
if ( pCurveInfo )
return pCurveInfo ;
SetCurveInfo ( CreateElement < CDmeTypedCurveInfo < T > > ( " curveinfo " , GetFileId ( ) ) ) ;
return m_CurveInfo . GetElement ( ) ;
}
template < class T >
struct ActiveLayer_t
{
ActiveLayer_t ( ) :
bValid ( false ) ,
priority ( 0 ) ,
firstTime ( 0 ) ,
lastTime ( 0 ) ,
layer ( NULL )
{
}
static bool PriorityLessFunc ( ActiveLayer_t < T > * const & lhs , ActiveLayer_t < T > * const & rhs )
{
return lhs - > priority < rhs - > priority ;
}
int priority ; // higher wins
bool bValid ;
DmeTime_t firstTime ;
DmeTime_t lastTime ;
CDmeTypedLogLayer < T > * layer ;
} ;
template < class T >
struct LayerEvent_t
{
enum EventType_t
{
LE_START = 0 ,
LE_END
} ;
LayerEvent_t ( ) : m_pList ( NULL ) , m_Type ( LE_START ) , m_nLayer ( 0 ) , m_Time ( 0 )
{
}
static bool LessFunc ( const LayerEvent_t & lhs , const LayerEvent_t & rhs )
{
return lhs . m_Time < rhs . m_Time ;
}
CUtlVector < ActiveLayer_t < T > > * m_pList ;
EventType_t m_Type ;
int m_nLayer ;
DmeTime_t m_Time ;
T m_NeighborValue ;
} ;
template < class T >
static const T & GetActiveLayerValue ( CUtlVector < ActiveLayer_t < T > > & layerlist , DmeTime_t t , int nTopmostLayer )
{
int nCount = layerlist . Count ( ) ;
# ifdef _DEBUG
Assert ( nCount > = nTopmostLayer ) ;
# endif
for ( int i = nTopmostLayer ; i > = 0 ; - - i )
{
ActiveLayer_t < T > & layer = layerlist [ i ] ;
if ( layer . firstTime > t | | layer . lastTime < t )
continue ;
return layer . layer - > GetValue ( t ) ;
}
if ( nCount ! = 0 )
{
const CDmeTypedLog < T > * pOwner = layerlist [ 0 ] . layer - > GetTypedOwnerLog ( ) ;
if ( pOwner - > HasDefaultValue ( ) )
return pOwner - > GetDefaultValue ( ) ;
}
static T defaultVal ;
CDmAttributeInfo < T > : : SetDefaultValue ( defaultVal ) ;
return defaultVal ;
}
template < class T >
static void SpewEvents ( CUtlRBTree < LayerEvent_t < T > > & events )
{
for ( unsigned short idx = events . FirstInorder ( ) ; idx ! = events . InvalidIndex ( ) ; idx = events . NextInorder ( idx ) )
{
LayerEvent_t < T > * pEvent = & events [ idx ] ;
Msg ( " Event %u layer %i at time %i type %s \n " ,
( unsigned ) idx , pEvent - > m_nLayer , pEvent - > m_Time . GetTenthsOfMS ( ) , pEvent - > m_Type = = LayerEvent_t < T > : : LE_START ? " start " : " end " ) ;
}
}
template < class T >
inline void SpewKey ( const T & )
{
Msg ( " GenericType " ) ;
}
template < >
inline void SpewKey < float > ( const float & val )
{
Msg ( " %f " , val ) ;
}
template < >
inline void SpewKey < int > ( const int & val )
{
Msg ( " %d " , val ) ;
}
template < >
inline void SpewKey < Vector2D > ( const Vector2D & val )
{
Msg ( " %f,%f " , val . x , val . y ) ;
}
template < >
inline void SpewKey < Vector4D > ( const Vector4D & val )
{
Msg ( " %f,%f,%f,%f " , val . x , val . y , val . z , val . w ) ;
}
template < >
inline void SpewKey < DmeTime_t > ( const DmeTime_t & val )
{
Msg ( " %d " , val . GetTenthsOfMS ( ) ) ;
}
template < >
inline void SpewKey < bool > ( const bool & val )
{
Msg ( " %s " , val ? " true " : " false " ) ;
}
template < >
inline void SpewKey < Color > ( const Color & val )
{
Msg ( " %08x " , val . GetRawColor ( ) ) ;
}
template < >
inline void SpewKey ( const Vector & val )
{
Msg ( " [%f %f %f] " , val . x , val . y , val . z ) ;
}
template < >
inline void SpewKey ( const Quaternion & val )
{
Msg ( " [%f %f %f %f] " , val . x , val . y , val . z , val . w ) ;
}
template < class T >
static void SpewFlattenedKey ( CDmeTypedLogLayer < T > * pLogLayer , ActiveLayer_t < T > * pActiveLayer , DmeTime_t t , const T & val )
{
Msg ( " Layer %d: adding key at time %f [%d -> %d], value " ,
pActiveLayer - > priority , t . GetSeconds ( ) , pActiveLayer - > firstTime . GetTenthsOfMS ( ) , pActiveLayer - > lastTime . GetTenthsOfMS ( ) ) ;
SpewKey ( val ) ;
Msg ( " \n " ) ;
}
template < class T >
static void ComputeLayerEvents ( CDmeTypedLog < T > * pLog ,
CUtlVector < ActiveLayer_t < T > > & layerlist ,
CUtlRBTree < LayerEvent_t < T > > & events )
{
// Build a list of all known layers and a sorted list of layer "transitions"
for ( int i = 0 ; i < pLog - > GetNumLayers ( ) ; + + i )
{
ActiveLayer_t < T > layer ;
layer . priority = i ;
layer . layer = static_cast < CDmeTypedLogLayer < T > * > ( pLog - > GetLayer ( i ) ) ;
layer . firstTime = layer . layer - > GetBeginTime ( ) ;
layer . lastTime = layer . layer - > GetEndTime ( ) ;
layer . bValid = true ;
if ( ( layer . firstTime = = DMETIME_MINTIME | | layer . lastTime = = DMETIME_MAXTIME ) & & ( i > 0 ) ) // Base layer is always valid
{
layer . bValid = false ;
}
// Skip invalid layers
if ( ! layer . bValid )
continue ;
// Layer zero can capture everything from above...
if ( i = = 0 )
{
layer . firstTime = DmeTime_t : : MinTime ( ) ;
layer . lastTime = DmeTime_t : : MaxTime ( ) ;
}
// Add layer to global list
int nIndex = layerlist . AddToTail ( layer ) ;
// Add layer start/end events
DmeTime_t tNeighbor = ( layer . firstTime ! = DMETIME_MINTIME ) ? ( layer . firstTime - DMETIME_MINDELTA ) : DMETIME_MINTIME ;
LayerEvent_t < T > start ;
start . m_pList = & layerlist ;
start . m_nLayer = nIndex ;
start . m_Type = LayerEvent_t < T > : : LE_START ;
start . m_Time = layer . firstTime ;
start . m_NeighborValue = GetActiveLayerValue ( layerlist , tNeighbor , nIndex - 1 ) ;
events . Insert ( start ) ;
tNeighbor = ( layer . lastTime ! = DMETIME_MAXTIME ) ? ( layer . lastTime + DMETIME_MINDELTA ) : DMETIME_MAXTIME ;
LayerEvent_t < T > end ;
end . m_pList = & layerlist ;
end . m_nLayer = nIndex ;
end . m_Type = LayerEvent_t < T > : : LE_END ;
end . m_Time = layer . lastTime ;
end . m_NeighborValue = GetActiveLayerValue ( layerlist , tNeighbor , nIndex - 1 ) ;
events . Insert ( end ) ;
}
}
template < class T >
static void AddDiscontinitySample ( CDmeTypedLogLayer < T > * pTargetLayer , CDmeTypedLog < T > * pLog , DmeTime_t tKeyTime , const T & val , const char * pSpewLabel )
{
// Finally, add a helper key
if ( pLog - > IsUsingCurveTypes ( ) )
{
if ( pSpewLabel )
{
Msg ( " Adding %s helper key at %d value " , pSpewLabel , tKeyTime . GetTenthsOfMS ( ) ) ;
SpewKey ( val ) ;
Msg ( " [curvetype %s] \n " , Interpolator_NameForCurveType ( pLog - > GetDefaultCurveType ( ) , false ) ) ;
}
pTargetLayer - > SetKey ( tKeyTime , val , pLog - > GetDefaultCurveType ( ) ) ;
}
else
{
if ( pSpewLabel )
{
Msg ( " Adding %s helper key at %d value " , pSpewLabel , tKeyTime . GetTenthsOfMS ( ) ) ;
SpewKey ( val ) ;
Msg ( " \n " ) ;
}
pTargetLayer - > SetKey ( tKeyTime , val ) ;
}
}
template < class T >
static DmeTime_t ProcessStartLayerStartEvent (
bool bSpew ,
bool bFixupDiscontinuities ,
CDmeTypedLog < T > * pLog ,
LayerEvent_t < T > * pEvent ,
CUtlVector < ActiveLayer_t < T > > & layerlist ,
CUtlRBTree < ActiveLayer_t < T > * > & active ,
CDmeTypedLogLayer < T > * flattenedlayer )
{
Assert ( pEvent - > m_Type = = LayerEvent_t < T > : : LE_START ) ;
// Push it onto the active stack if it's not already on the stack
if ( active . Find ( & layerlist [ pEvent - > m_nLayer ] ) ! = active . InvalidIndex ( ) )
return pEvent - > m_Time ;
if ( bSpew )
{
Msg ( " adding layer %d to stack \n " , layerlist [ pEvent - > m_nLayer ] . priority ) ;
}
active . Insert ( & layerlist [ pEvent - > m_nLayer ] ) ;
if ( ! bFixupDiscontinuities | | ( pEvent - > m_Time = = DMETIME_MINTIME ) )
return pEvent - > m_Time ;
// We'll need to add 2 new "discontinuity" fixup samples.
// 1) A sample from the base layer @ start time - .1 msec
// 2) A sample from the new layer @ start time
int nActiveCount = active . Count ( ) ;
if ( nActiveCount > = 2 )
{
DmeTime_t tKeyTime = pEvent - > m_Time - DmeTime_t ( 1 ) ;
AddDiscontinitySample ( flattenedlayer , pLog , tKeyTime , pEvent - > m_NeighborValue , bSpew ? " start " : NULL ) ;
}
AddDiscontinitySample ( flattenedlayer , pLog , pEvent - > m_Time , GetActiveLayerValue ( layerlist , pEvent - > m_Time , pEvent - > m_nLayer ) , bSpew ? " start " : NULL ) ;
return pEvent - > m_Time ;
}
template < class T >
static DmeTime_t ProcessStartLayerEndEvent (
bool bSpew ,
bool bFixupDiscontinuities ,
CDmeTypedLog < T > * pLog ,
LayerEvent_t < T > * pEvent ,
CUtlVector < ActiveLayer_t < T > > & layerlist ,
CUtlRBTree < ActiveLayer_t < T > * > & active ,
CDmeTypedLogLayer < T > * pBaseLayer )
{
Assert ( pEvent - > m_Type = = LayerEvent_t < T > : : LE_END ) ;
// Push it onto the active stack if it's not already on the stack
if ( bSpew )
{
Msg ( " removing layer %d from stack \n " , layerlist [ pEvent - > m_nLayer ] . priority ) ;
}
// We'll need to add a "discontinuity" fixup sample from the
// 1) A sample from the ending layer @ start time
// 2) A sample from the new layer @ start time + .1 msec
// NOTE: This will cause problems if there are non-default value keys at max time
Assert ( active . Count ( ) > = 1 ) ;
if ( bFixupDiscontinuities & & ( pEvent - > m_Time ! = DMETIME_MAXTIME ) )
{
AddDiscontinitySample ( pBaseLayer , pLog , pEvent - > m_Time , GetActiveLayerValue ( layerlist , pEvent - > m_Time , pEvent - > m_nLayer ) , bSpew ? " end " : NULL ) ;
if ( active . Count ( ) > = 2 )
{
DmeTime_t keyTime = pEvent - > m_Time + DmeTime_t ( 1 ) ;
AddDiscontinitySample ( pBaseLayer , pLog , keyTime , pEvent - > m_NeighborValue , bSpew ? " end " : NULL ) ;
}
}
active . Remove ( & layerlist [ pEvent - > m_nLayer ] ) ;
return ( active . Count ( ) > = 2 ) ? pEvent - > m_Time + DmeTime_t ( 1 ) : pEvent - > m_Time ;
}
template < class T >
void CDmeTypedLog < T > : : FlattenLayers ( float threshold , int flags )
{
// Already flattened
if ( m_Layers . Count ( ) < = 1 )
return ;
if ( g_pDataModel - > UndoEnabledForElement ( this ) )
{
CUndoFlattenLayers < T > * pUndo = new CUndoFlattenLayers < T > ( " FlattenLayers " , this , threshold , flags ) ;
g_pDataModel - > AddUndoElement ( pUndo ) ;
}
bool bSpew = ( flags & FLATTEN_SPEW ) ! = 0 ;
bool bFixupDiscontinuities = true ; //( flags & FLATTEN_NODISCONTINUITY_FIXUP ) == 0;
// NOTE: UNDO IS DISABLED FOR THE REST OF THIS OPERATION (the above function does what we need to preserve the layers)
CDisableUndoScopeGuard guard ;
CDmeTypedLogLayer < T > * flattenedlayer = static_cast < CDmeTypedLogLayer < T > * > ( CreateLayer < T > ( this ) ) ;
flattenedlayer - > SetOwnerLog ( this ) ;
// Global list of layers
CUtlVector < ActiveLayer_t < T > > layerlist ;
// List of all start/end layer events, sorted by the time at which the event occurs ( we walk this list in order )
CUtlRBTree < LayerEvent_t < T > > events ( 0 , 0 , LayerEvent_t < T > : : LessFunc ) ;
// Stack of active events, sorted by event "priority", which means last item is the one writing data into the new base layer
CUtlRBTree < ActiveLayer_t < T > * > active ( 0 , 0 , ActiveLayer_t < T > : : PriorityLessFunc ) ;
// Build layer list and list of start/end events and times
ComputeLayerEvents ( this , layerlist , events ) ;
// Debuggins
if ( bSpew )
{
SpewEvents ( events ) ;
}
// Now walk from the earliest time in any layer until the latest time, going key by key and checking if the active layer should change as we go
DmeTime_t iCurrentKeyTime = DmeTime_t : : MinTime ( ) ;
unsigned short idx = events . FirstInorder ( ) ;
while ( 1 )
{
if ( idx = = events . InvalidIndex ( ) )
break ;
LayerEvent_t < T > * pEvent = & events [ idx ] ;
switch ( pEvent - > m_Type )
{
default :
iCurrentKeyTime = pEvent - > m_Time ;
Assert ( 0 ) ;
break ;
case LayerEvent_t < T > : : LE_START :
iCurrentKeyTime = ProcessStartLayerStartEvent ( bSpew , bFixupDiscontinuities , this , pEvent , layerlist , active , flattenedlayer ) ;
break ;
case LayerEvent_t < T > : : LE_END :
iCurrentKeyTime = ProcessStartLayerEndEvent ( bSpew , bFixupDiscontinuities , this , pEvent , layerlist , active , flattenedlayer ) ;
break ;
}
int nNextIndex = events . NextInorder ( idx ) ;
// We popped the last item off the stack
if ( nNextIndex = = events . InvalidIndex ( ) )
{
Assert ( active . Count ( ) = = 0 ) ;
break ;
}
// Walk from current time up to the time of the next relevant event
LayerEvent_t < T > * nextevent = & events [ nNextIndex ] ;
DmeTime_t layerFinishTime = nextevent - > m_Time ;
// The topmost layer is the active layer
int layernum = active . LastInorder ( ) ;
if ( layernum = = active . InvalidIndex ( ) )
break ;
ActiveLayer_t < T > * activeLayer = active [ layernum ] ;
CDmeTypedLogLayer < T > * loglayer = activeLayer - > layer ;
// Splat all keys betweeen the current head position and the next event time (layerFinishTime) into the flattened layer
int keyCount = loglayer - > GetKeyCount ( ) ;
for ( int j = 0 ; j < keyCount ; + + j )
{
DmeTime_t keyTime = loglayer - > GetKeyTime ( j ) ;
// Key is too early, skip
if ( keyTime < iCurrentKeyTime )
continue ;
// Done with this layer, set time exactly equal to end time so next layer can take over
// at the correct spot
if ( keyTime > = layerFinishTime )
{
iCurrentKeyTime = layerFinishTime ;
break ;
}
// Advance the head position
iCurrentKeyTime = keyTime ;
// Because it's a key, the interpolated value should == the actual value (not true for certain 4 point curve types, but we shouldn't support them
// for this type of operation anyway)
const T & val = loglayer - > GetKeyValue ( j ) ;
// Debugging spew
if ( bSpew )
{
SpewFlattenedKey ( loglayer , activeLayer , iCurrentKeyTime , val ) ;
}
// Now set the key into the flattened layer
flattenedlayer - > SetKey ( iCurrentKeyTime , val , loglayer - > IsUsingCurveTypes ( ) ? loglayer - > GetKeyCurveType ( j ) : CURVE_DEFAULT ) ;
}
idx = nNextIndex ;
}
// Blow away all of the existing layers except the original base layer
while ( GetNumLayers ( ) > 1 )
{
CDmeTypedLogLayer < T > * layer = static_cast < CDmeTypedLogLayer < T > * > ( RemoveLayerFromTail ( ) ) ;
g_pDataModel - > DestroyElement ( layer - > GetHandle ( ) ) ;
}
// Compress the flattened layer
flattenedlayer - > RemoveRedundantKeys ( threshold ) ;
// Copy the flattened layer over the existing base layer
GetLayer ( 0 ) - > CopyLayer ( flattenedlayer ) ;
g_pDataModel - > DestroyElement ( flattenedlayer - > GetHandle ( ) ) ;
}
template < class T >
void CDmeTypedLog < T > : : StampKeyAtHead ( DmeTime_t tHeadPosition , DmeTime_t tPreviousHeadPosition , const DmeLog_TimeSelection_t & params , const CDmAttribute * pAttr , uint index /*= 0*/ )
{
DmAttributeType_t type = pAttr - > GetType ( ) ;
if ( IsValueType ( type ) )
{
Assert ( pAttr - > GetType ( ) = = GetDataType ( ) ) ;
StampKeyAtHead ( tHeadPosition , tPreviousHeadPosition , params , pAttr - > GetValue < T > ( ) ) ;
}
else if ( IsArrayType ( type ) )
{
Assert ( ArrayTypeToValueType ( type ) = = GetDataType ( ) ) ;
CDmrArrayConst < T > array ( pAttr ) ;
StampKeyAtHead ( tHeadPosition , tPreviousHeadPosition , params , array [ index ] ) ;
}
else
{
Assert ( 0 ) ;
}
}
template < class T >
void CDmeTypedLog < T > : : FinishTimeSelection ( DmeTime_t tHeadPosition , DmeLog_TimeSelection_t & params )
{
bool bWasAdvancing = params . IsTimeAdvancing ( ) ;
params . ResetTimeAdvancing ( ) ;
if ( ! params . m_bAttachedMode )
return ;
if ( ! bWasAdvancing )
return ;
// Should be in "layer recording" mode!!!
Assert ( GetNumLayers ( ) > = 2 ) ;
int nBestLayer = GetTopmostLayer ( ) ; // Topmost should be at least layer # 1 (0 is the base layer)
if ( nBestLayer < 1 )
return ;
CDmeTypedLogLayer < T > * pWriteLayer = GetLayer ( nBestLayer ) ;
Assert ( pWriteLayer ) ;
if ( ! pWriteLayer )
return ;
int nKeyCount = pWriteLayer - > GetKeyCount ( ) ;
if ( nKeyCount < = 0 )
return ;
// The head is considered to be at the "last" value
T headValue = pWriteLayer - > GetKeyValue ( nKeyCount - 1 ) ;
_StampKeyAtHeadResample ( tHeadPosition , params , headValue , true , false ) ;
}
template < >
float CDmeTypedLog < float > : : ClampValue ( const float & value )
{
float retval ;
if ( ! IsUsingCurveTypes ( ) )
{
retval = clamp ( value , 0.0f , 1.0f ) ;
}
else
{
retval = clamp ( value , GetMinValue ( ) , GetMaxValue ( ) ) ;
}
return retval ;
}
template < class T >
void CDmeTypedLog < T > : : StampKeyAtHead ( DmeTime_t tHeadPosition , DmeTime_t tPreviousHeadPosition , const DmeLog_TimeSelection_t & params , const T & value )
{
//T useValue = ClampValue( value );
// This gets set if time ever starts moving (even if the user pauses time while still holding a slider)
if ( params . IsTimeAdvancing ( ) )
{
// This uses the time selection as a "filter" to decide whether to stamp a new key at the current position
_StampKeyAtHeadFilteredByTimeSelection ( tHeadPosition , tPreviousHeadPosition , params , value ) ;
}
else
{
Assert ( params . m_bResampleMode ) ;
_StampKeyAtHeadResample ( tHeadPosition , params , value , false , true ) ;
}
}
/*
template < >
void CDmeTypedLog < float > : : _StampKeyAtHeadResample ( const DmeLog_TimeSelection_t & params , const float & value ) ;
template < >
void CDmeTypedLog < bool > : : _StampKeyAtHeadResample ( const DmeLog_TimeSelection_t & params , const bool & value ) ;
template < >
void CDmeTypedLog < Color > : : _StampKeyAtHeadResample ( const DmeLog_TimeSelection_t & params , const Color & value ) ;
template < >
void CDmeTypedLog < Vector4D > : : _StampKeyAtHeadResample ( const DmeLog_TimeSelection_t & params , const Vector4D & value ) ;
template < >
void CDmeTypedLog < Vector2D > : : _StampKeyAtHeadResample ( const DmeLog_TimeSelection_t & params , const Vector2D & value ) ;
template < >
void CDmeTypedLog < VMatrix > : : _StampKeyAtHeadResample ( const DmeLog_TimeSelection_t & params , const VMatrix & value ) ;
template < >
void CDmeTypedLog < Quaternion > : : _StampKeyAtHeadResample ( const DmeLog_TimeSelection_t & params , const Quaternion & value ) ;
template < >
void CDmeTypedLog < QAngle > : : _StampKeyAtHeadResample ( const DmeLog_TimeSelection_t & params , const QAngle & value ) ;
*/
//-----------------------------------------------------------------------------
// Helper class used to compute falloff blend factors
//-----------------------------------------------------------------------------
template < class T >
struct LogClampHelper_t
{
public :
LogClampHelper_t ( ) : m_tLastTime ( DMETIME_MINTIME ) { }
DmeTime_t m_tLastTime ;
T m_LastUnclampedValue ;
} ;
template < class T >
class CLogFalloffBlend
{
public :
void Init ( CDmeTypedLog < T > * pLog , DmeTime_t tFalloff , DmeTime_t tHold , bool bLeftFalloff , int nInterpolatorType , const T & delta ) ;
void Init ( CDmeTypedLog < T > * pLog , const T & delta ) ;
float ComputeBlendFactor ( DmeTime_t tTime , const T & oldVal , bool bUsingInterpolation ) const ;
const T & GetDelta ( ) const ;
void StampKey ( CDmeTypedLogLayer < T > * pWriteLayer , DmeTime_t t , const CDmeTypedLogLayer < T > * pReadLayer , float flIntensity , LogClampHelper_t < T > & helper , bool bSpew , const T * pInterpTarget ) ;
void UpdateClampHelper ( DmeTime_t t , const CDmeTypedLogLayer < T > * pReadLayer , float flIntensity , LogClampHelper_t < T > & helper , const T * pInterpTarget ) ;
private :
void ComputeDelta ( CDmeTypedLog < T > * pLog , const T & delta , const T & holdValue ) ;
void InsertClampTransitionPoints ( CDmeTypedLogLayer < T > * pWriteLayer , DmeTime_t t , LogClampHelper_t < T > & clampHelper , const T & val , bool bSpew ) ;
void ComputeBounds ( CDmeTypedLog < T > * pLog ) ;
T m_BaseValue ;
T m_Delta ;
DmeTime_t m_tBaseTime ;
DmeTime_t m_tHoldTime ;
float m_flOOTime ;
int m_nTestSign ;
int m_nInterpolatorType ;
int m_nCurveType ;
T m_MinValue ;
T m_MaxValue ;
bool m_bHold ;
} ;
template < class T >
void CLogFalloffBlend < T > : : Init ( CDmeTypedLog < T > * pLog , DmeTime_t tFalloffTime , DmeTime_t tHoldTime , bool bLeftFalloff , int nInterpolatorType , const T & delta )
{
m_tBaseTime = tFalloffTime ;
m_tHoldTime = tHoldTime ;
m_BaseValue = pLog - > GetValueSkippingTopmostLayer ( tFalloffTime ) ;
T holdValue = pLog - > GetValueSkippingTopmostLayer ( tHoldTime ) ;
m_nTestSign = bLeftFalloff ? 1 : - 1 ;
m_nInterpolatorType = nInterpolatorType ;
m_bHold = false ;
m_nCurveType = pLog - > IsUsingCurveTypes ( ) ? pLog - > GetDefaultCurveType ( ) : CURVE_DEFAULT ;
float flDuration = tHoldTime . GetSeconds ( ) - tFalloffTime . GetSeconds ( ) ;
m_flOOTime = ( flDuration ! = 0.0f ) ? 1.0f / flDuration : 0.0f ;
ComputeBounds ( pLog ) ;
ComputeDelta ( pLog , delta , holdValue ) ;
}
template < class T >
void CLogFalloffBlend < T > : : Init ( CDmeTypedLog < T > * pLog , const T & delta )
{
m_nTestSign = 0 ;
m_nInterpolatorType = INTERPOLATE_DEFAULT ;
m_bHold = true ;
m_nCurveType = pLog - > IsUsingCurveTypes ( ) ? pLog - > GetDefaultCurveType ( ) : CURVE_DEFAULT ;
m_Delta = delta ;
ComputeBounds ( pLog ) ;
}
template < class T >
void CLogFalloffBlend < T > : : ComputeBounds ( CDmeTypedLog < T > * pLog )
{
}
template < >
void CLogFalloffBlend < float > : : ComputeBounds ( CDmeTypedLog < float > * pLog )
{
m_MinValue = pLog - > IsUsingCurveTypes ( ) ? pLog - > GetMinValue ( ) : 0.0f ;
m_MaxValue = pLog - > IsUsingCurveTypes ( ) ? pLog - > GetMaxValue ( ) : 1.0f ;
}
template < class T >
void CLogFalloffBlend < T > : : ComputeDelta ( CDmeTypedLog < T > * pLog , const T & delta , const T & holdValue )
{
// By default, no clamping
m_Delta = delta ;
}
template < >
void CLogFalloffBlend < float > : : ComputeDelta ( CDmeTypedLog < float > * pLog , const float & delta , const float & holdValue )
{
if ( LengthOf ( delta ) > 0.0f )
{
m_Delta = min ( delta , m_MaxValue - holdValue ) ; // Max amount we can move up...
}
else
{
m_Delta = max ( delta , m_MinValue - holdValue ) ; // Amount we can move down...
}
}
template < class T >
float CLogFalloffBlend < T > : : ComputeBlendFactor ( DmeTime_t tTime , const T & oldVal , bool bUsingInterpolation ) const
{
if ( m_bHold )
return 1.0f ;
// Clamp inside region; hold time beats base time (for zero width regions)
if ( ( tTime - m_tHoldTime ) * m_nTestSign > = DMETIME_ZERO )
return 1.0f ;
if ( ( tTime - m_tBaseTime ) * m_nTestSign < = DMETIME_ZERO )
return 0.0f ;
float flFactor = ( tTime . GetSeconds ( ) - m_tBaseTime . GetSeconds ( ) ) * m_flOOTime ;
return ComputeInterpolationFactor ( flFactor , m_nInterpolatorType ) ;
}
template < class T >
const T & CLogFalloffBlend < T > : : GetDelta ( ) const
{
return m_Delta ;
}
//-----------------------------------------------------------------------------
// Insert points where clamping begins or ends
//-----------------------------------------------------------------------------
template < class T >
void CLogFalloffBlend < T > : : InsertClampTransitionPoints ( CDmeTypedLogLayer < T > * pWriteLayer ,
DmeTime_t t , LogClampHelper_t < T > & clampHelper , const T & val , bool bSpew )
{
// NOTE: By default, nothing clamps, so no transition points are needed
}
template < >
void CLogFalloffBlend < float > : : InsertClampTransitionPoints ( CDmeTypedLogLayer < float > * pWriteLayer ,
DmeTime_t t , LogClampHelper_t < float > & clampHelper , const float & val , bool bSpew )
{
bool bLastLess , bLastGreater , bCurrLess , bCurrGreater ;
DmeTime_t tCrossing , tDuration ;
double flOODv ;
// First time through? cache last values.
if ( clampHelper . m_tLastTime = = DMETIME_MINTIME )
goto cacheLastValues ;
bLastLess = clampHelper . m_LastUnclampedValue < m_MinValue ;
bLastGreater = clampHelper . m_LastUnclampedValue > m_MaxValue ;
bCurrLess = val < m_MinValue ;
bCurrGreater = val > m_MaxValue ;
if ( bLastLess = = bCurrLess & & bLastGreater = = bCurrGreater )
goto cacheLastValues ;
// NOTE: The check above means val != m_LastUnclampedValue
flOODv = 1.0 / ( val - clampHelper . m_LastUnclampedValue ) ;
tDuration = t - clampHelper . m_tLastTime ;
// NOTE: Clamp semantics here favor keeping the non-clamped value
// That's why when we start outside + end inside, we never overwrite the dest
// and why when we start inside + end outside, we never overwrite the start
// These two checks deal with starting outside + heading inside
if ( bLastLess & & ! bCurrLess )
{
// Insert at min crossing
double flFactor = ( m_MinValue - clampHelper . m_LastUnclampedValue ) * flOODv ;
tCrossing = clampHelper . m_tLastTime + tDuration * flFactor ;
tCrossing . Clamp ( clampHelper . m_tLastTime , t - DMETIME_MINDELTA ) ;
pWriteLayer - > InsertKey ( tCrossing , m_MinValue , m_nCurveType ) ;
if ( bSpew )
{
Msg ( " Clamp Crossing Key: %d %f \n " , tCrossing . GetTenthsOfMS ( ) , m_MinValue ) ;
}
}
else if ( bLastGreater & & ! bCurrGreater )
{
// Insert at max crossing
double flFactor = ( m_MaxValue - clampHelper . m_LastUnclampedValue ) * flOODv ;
tCrossing = clampHelper . m_tLastTime + tDuration * flFactor ;
tCrossing . Clamp ( clampHelper . m_tLastTime , t - DMETIME_MINDELTA ) ;
pWriteLayer - > InsertKey ( tCrossing , m_MaxValue , m_nCurveType ) ;
if ( bSpew )
{
Msg ( " Clamp Crossing Key: %d %f \n " , tCrossing . GetTenthsOfMS ( ) , m_MaxValue ) ;
}
}
// These two checks deal with starting inside + heading outside
if ( ! bLastLess & & bCurrLess )
{
// Insert at min crossing
// NOTE: Clamp semantics here favor keeping the non-clamped value
double flFactor = ( m_MinValue - clampHelper . m_LastUnclampedValue ) * flOODv ;
tCrossing = clampHelper . m_tLastTime + tDuration * flFactor ;
tCrossing . Clamp ( clampHelper . m_tLastTime + DMETIME_MINDELTA , t ) ;
pWriteLayer - > InsertKey ( tCrossing , m_MinValue , m_nCurveType ) ;
if ( bSpew )
{
Msg ( " Clamp Crossing Key: %d %f \n " , tCrossing . GetTenthsOfMS ( ) , m_MinValue ) ;
}
}
else if ( ! bLastGreater & & bCurrGreater )
{
// Insert at max crossing
double flFactor = ( m_MaxValue - clampHelper . m_LastUnclampedValue ) * flOODv ;
tCrossing = clampHelper . m_tLastTime + tDuration * flFactor ;
tCrossing . Clamp ( clampHelper . m_tLastTime + DMETIME_MINDELTA , t ) ;
pWriteLayer - > InsertKey ( tCrossing , m_MaxValue , m_nCurveType ) ;
if ( bSpew )
{
Msg ( " Clamp Crossing Key: %d %f \n " , tCrossing . GetTenthsOfMS ( ) , m_MaxValue ) ;
}
}
// Cache off the last values
cacheLastValues :
clampHelper . m_tLastTime = t ;
clampHelper . m_LastUnclampedValue = val ;
}
//-----------------------------------------------------------------------------
// Stamp the key at the specified time
//-----------------------------------------------------------------------------
template < class T >
void CLogFalloffBlend < T > : : StampKey ( CDmeTypedLogLayer < T > * pWriteLayer , DmeTime_t t ,
const CDmeTypedLogLayer < T > * pReadLayer , float flIntensity , LogClampHelper_t < T > & clampHelper , bool bSpew , const T * pInterpTarget )
{
// Stamp the key at the current time
T oldVal = pReadLayer - > GetValue ( t ) ;
// In the falloff area
float flFactor = ComputeBlendFactor ( t , oldVal , ( pInterpTarget ! = NULL ) ) ;
flFactor * = flIntensity ;
T newVal ;
if ( ! pInterpTarget )
{
newVal = ScaleValue ( m_Delta , flFactor ) ;
newVal = Add ( oldVal , newVal ) ;
}
else
{
newVal = Interpolate ( flFactor , oldVal , * pInterpTarget ) ;
}
InsertClampTransitionPoints ( pWriteLayer , t , clampHelper , newVal , bSpew ) ;
T clampedVal = pWriteLayer - > GetTypedOwnerLog ( ) - > ClampValue ( newVal ) ;
// Add a key to the new "layer" at this time with this value
pWriteLayer - > InsertKey ( t , clampedVal , m_nCurveType ) ;
if ( bSpew )
{
Msg ( " Key: %d " , t . GetTenthsOfMS ( ) ) ;
SpewKey ( clampedVal ) ;
Msg ( " [ " ) ;
SpewKey ( newVal ) ;
Msg ( " ] \n " ) ;
}
}
//-----------------------------------------------------------------------------
// Stamp the key at the specified time
//-----------------------------------------------------------------------------
template < class T >
void CLogFalloffBlend < T > : : UpdateClampHelper ( DmeTime_t t , const CDmeTypedLogLayer < T > * pReadLayer ,
float flIntensity , LogClampHelper_t < T > & clampHelper , const T * pInterpTarget )
{
// Stamp the key at the current time
T oldVal = pReadLayer - > GetValue ( t ) ;
// In the falloff area
float flFactor = ComputeBlendFactor ( t , oldVal , ( pInterpTarget ! = NULL ) ) ;
flFactor * = flIntensity ;
T val ;
if ( ! pInterpTarget )
{
val = ScaleValue ( m_Delta , flFactor ) ;
val = Add ( oldVal , val ) ;
}
else
{
val = Interpolate ( flFactor , oldVal , * pInterpTarget ) ;
}
clampHelper . m_tLastTime = t ;
clampHelper . m_LastUnclampedValue = val ;
}
//-----------------------------------------------------------------------------
// This is used to modify the entire portion of the curve under the time selection
//-----------------------------------------------------------------------------
static inline DmeTime_t ComputeResampleStartTime ( const DmeLog_TimeSelection_t & params , int nSide )
{
// NOTE: This logic will place the resampled points centered in the falloff regions
DmeTimeSelectionTimes_t start = ( nSide = = 0 ) ? TS_LEFT_FALLOFF : TS_RIGHT_HOLD ;
DmeTimeSelectionTimes_t end = ( nSide = = 0 ) ? TS_LEFT_HOLD : TS_RIGHT_FALLOFF ;
if ( params . m_nFalloffInterpolatorTypes [ nSide ] ! = INTERPOLATE_LINEAR_INTERP )
{
DmeTime_t tDuration = params . m_nTimes [ end ] - params . m_nTimes [ start ] ;
if ( tDuration > params . m_nResampleInterval )
{
int nFactor = tDuration . GetTenthsOfMS ( ) / params . m_nResampleInterval . GetTenthsOfMS ( ) ;
tDuration - = params . m_nResampleInterval * nFactor ;
tDuration / = 2 ;
return params . m_nTimes [ start ] + tDuration ;
}
}
return DMETIME_MAXTIME ;
}
//-----------------------------------------------------------------------------
// This is used to modify the entire portion of the curve under the time selection
//-----------------------------------------------------------------------------
template < class T >
void CDmeTypedLog < T > : : _StampKeyAtHeadResample ( DmeTime_t tHeadPosition , const DmeLog_TimeSelection_t & params , const T & value , bool bSkipToHead , bool bClearPreviousKeys )
{
Assert ( params . m_nResampleInterval > DmeTime_t ( 0 ) ) ;
if ( params . m_nResampleInterval < DmeTime_t ( 0 ) )
return ;
// Should be in "layer recording" mode!!!
Assert ( GetNumLayers ( ) > = 2 ) ;
int nBestLayer = GetTopmostLayer ( ) ; // Topmost should be at least layer # 1 (0 is the base layer)
if ( nBestLayer < 1 )
return ;
CDmeTypedLogLayer < T > * pWriteLayer = GetLayer ( nBestLayer ) ;
Assert ( pWriteLayer ) ;
if ( ! pWriteLayer )
return ;
if ( bClearPreviousKeys )
{
pWriteLayer - > ClearKeys ( ) ;
}
bool bSpew = false ;
// NOTE: The headDelta is only used when not blending toward a preset
// When not blending toward a preset, just add the head delta onto everything.
// When blending toward a preset, lerp towards the preset.
T oldHeadValue = GetValueSkippingTopmostLayer ( tHeadPosition ) ;
T headDelta = Subtract ( value , oldHeadValue ) ;
// When dragging preset fader, eveything get's blended in by the amount of the preset being applied
bool bUsePresetRules = ( RECORD_PRESET = = params . GetRecordingMode ( ) ) ;
bool bIsStampingQuaternions = ( CDmAttributeInfo < T > : : ATTRIBUTE_TYPE = = AT_QUATERNION ) ;
bool bPerformInterpolation = bUsePresetRules | | bIsStampingQuaternions ;
// FIXME: Preset value should never be NULL. We need to grab it from the attribute
bool bUsePresetValue = bUsePresetRules & & params . m_pPresetValue & & params . m_pPresetValue - > GetType ( ) = = CDmAttributeInfo < T > : : ATTRIBUTE_TYPE ;
const T & interpTarget = bUsePresetValue ? params . m_pPresetValue - > GetValue < T > ( ) : value ;
// Compute falloff region blend factors
CLogFalloffBlend < T > blend [ 3 ] ;
blend [ 0 ] . Init ( this , params . m_nTimes [ TS_FALLOFF ( 0 ) ] , params . m_nTimes [ TS_HOLD ( 0 ) ] , true , params . m_nFalloffInterpolatorTypes [ 0 ] , headDelta ) ;
blend [ 1 ] . Init ( this , headDelta ) ;
blend [ 2 ] . Init ( this , params . m_nTimes [ TS_FALLOFF ( 1 ) ] , params . m_nTimes [ TS_HOLD ( 1 ) ] , false , params . m_nFalloffInterpolatorTypes [ 1 ] , headDelta ) ;
// The algorithm we're going to use is to add samples in the following places:
// 1) At each time selection transition point (start, end of falloff regions)
// NOTE: If a falloff region has 0 size, we'll add points right outside the transition
// 2) At the resample point (we're going to base this so the resamples always occur at the same spots)
// 3) At any existing sample position
// 4) Any time we switch from clamped to not clamped
// By doing this, we will guarantee no bogus slope changes
// First, compute times for transition regions
DmeTime_t tTransitionTimes [ TS_TIME_COUNT ] ;
memcpy ( & tTransitionTimes , & params . m_nTimes , sizeof ( params . m_nTimes ) ) ;
if ( tTransitionTimes [ TS_LEFT_FALLOFF ] = = tTransitionTimes [ TS_LEFT_HOLD ] )
{
tTransitionTimes [ TS_LEFT_FALLOFF ] - = DMETIME_MINDELTA ;
}
if ( tTransitionTimes [ TS_RIGHT_FALLOFF ] = = tTransitionTimes [ TS_RIGHT_HOLD ] )
{
tTransitionTimes [ TS_RIGHT_FALLOFF ] + = DMETIME_MINDELTA ;
}
DmeTime_t tStartTime = params . m_nTimes [ TS_LEFT_FALLOFF ] ;
// Next, compute the first resample time for each region
DmeTime_t tResampleStartTime [ TS_TIME_COUNT ] ;
tResampleStartTime [ TS_LEFT_FALLOFF ] = DMETIME_MAXTIME ;
tResampleStartTime [ TS_LEFT_HOLD ] = ComputeResampleStartTime ( params , 0 ) ;
tResampleStartTime [ TS_RIGHT_HOLD ] = DMETIME_MAXTIME ;
tResampleStartTime [ TS_RIGHT_FALLOFF ] = ComputeResampleStartTime ( params , 1 ) ;
// Finally, figure out which layer we're reading from,
// where the next key is, and when we must stop reading from it
int nReadLayer = FindLayerForTimeSkippingTopmost ( tStartTime ) ;
CDmeTypedLogLayer < T > * pReadLayer = GetLayer ( nReadLayer ) ;
int nLayerSampleIndex = pReadLayer - > FindKey ( tStartTime ) + 1 ;
DmeTime_t tLayerEndTime = pReadLayer - > GetEndTime ( ) ;
// NOTE: This can happen after reading off the end of layer 0
if ( tLayerEndTime < = tStartTime )
{
tLayerEndTime = DMETIME_MAXTIME ;
}
DmeTime_t tNextSampleTime = nLayerSampleIndex > = pReadLayer - > GetKeyCount ( ) ? tLayerEndTime : pReadLayer - > GetKeyTime ( nLayerSampleIndex ) ;
if ( tNextSampleTime > tLayerEndTime )
{
tNextSampleTime = tLayerEndTime ;
}
// Now keep going until we've hit the end point
// NOTE: We use tTransitionTimes, *not* params.m_nTimes, so that we can get a single
// sample before zero-width left falloff regions
DmeTime_t tCurrent = tTransitionTimes [ TS_LEFT_FALLOFF ] ;
int nNextTransition = TS_LEFT_HOLD ;
DmeTime_t tResampleTime = tResampleStartTime [ nNextTransition ] ;
const T * pInterpTarget = bPerformInterpolation ? & interpTarget : NULL ;
if ( bSpew )
{
Msg ( " Stamp key at head resample: %s \n " , GetName ( ) ) ;
}
LogClampHelper_t < T > clampHelper ;
while ( nNextTransition < TS_TIME_COUNT )
{
// Stamp the key at the current time
if ( ! bSkipToHead | | ( tCurrent > = tHeadPosition ) )
{
blend [ nNextTransition - 1 ] . StampKey ( pWriteLayer , tCurrent , pReadLayer , params . m_flIntensity , clampHelper , bSpew , pInterpTarget ) ;
}
// Update the read layer sample
if ( tCurrent = = tNextSampleTime )
{
+ + nLayerSampleIndex ;
tNextSampleTime = nLayerSampleIndex > = pReadLayer - > GetKeyCount ( ) ? tLayerEndTime : pReadLayer - > GetKeyTime ( nLayerSampleIndex ) ;
}
// Update the read layer
if ( tCurrent = = tLayerEndTime )
{
nReadLayer = FindLayerForTimeSkippingTopmost ( tCurrent + DMETIME_MINDELTA ) ;
pReadLayer = GetLayer ( nReadLayer ) ;
nLayerSampleIndex = pReadLayer - > FindKey ( tCurrent ) + 1 ;
tLayerEndTime = pReadLayer - > GetEndTime ( ) ;
// NOTE: This can happen after reading off the end of layer 0
if ( tLayerEndTime < = tCurrent )
{
tLayerEndTime = DMETIME_MAXTIME ;
}
tNextSampleTime = nLayerSampleIndex > = pReadLayer - > GetKeyCount ( ) ? tLayerEndTime : pReadLayer - > GetKeyTime ( nLayerSampleIndex ) ;
if ( tNextSampleTime > tLayerEndTime )
{
tNextSampleTime = tLayerEndTime ;
}
}
// Update the transition time
if ( tCurrent = = tTransitionTimes [ nNextTransition ] )
{
// NOTE: This is necessary because each blend region has different 'deltas'
// to avoid overdriving in the falloff regions. Therefore, the 'previous value'
// used in the clamping operation will be different
if ( nNextTransition < ARRAYSIZE ( blend ) )
{
blend [ nNextTransition ] . UpdateClampHelper ( tCurrent , pReadLayer , params . m_flIntensity , clampHelper , pInterpTarget ) ;
}
// Also need to update the 'previous' value stored in the
+ + nNextTransition ;
if ( nNextTransition > = ARRAYSIZE ( tResampleStartTime ) )
break ;
// Update the first resample time
tResampleTime = tResampleStartTime [ nNextTransition ] ;
if ( bSpew )
{
Msg ( " Entering region %d \n " , nNextTransition - 1 ) ;
}
}
// Update the resample time
if ( tCurrent = = tResampleTime )
{
tResampleTime + = params . m_nResampleInterval ;
}
// Now that the key is stamped, update current time.
tCurrent = tTransitionTimes [ nNextTransition ] ;
if ( tResampleTime < tCurrent )
{
tCurrent = tResampleTime ;
}
if ( tNextSampleTime < tCurrent )
{
tCurrent = tNextSampleTime ;
}
}
}
//-----------------------------------------------------------------------------
// In this case, we actually stamp a key right at the head position unlike the above method
//-----------------------------------------------------------------------------
template < class T >
void CDmeTypedLog < T > : : _StampKeyFilteredByTimeSelection ( CDmeTypedLogLayer < T > * pWriteLayer , DmeTime_t t , const DmeLog_TimeSelection_t & params , const T & value , bool bForce )
{
// Found a key which needs to be modulated upward
float flFraction = params . GetAmountForTime ( t ) * params . m_flIntensity ;
if ( flFraction < = 0.0f & & ! bForce )
return ;
// When dragging preset fader, eveything get's blended in by the amount of the preset being applied
bool bUsePresetRules = ( RECORD_PRESET = = params . GetRecordingMode ( ) ) ;
// FIXME: Preset value should never be NULL. We need to grab it from the attribute
const T & interpTarget = ( bUsePresetRules & & params . m_pPresetValue ) ? params . m_pPresetValue - > GetValue < T > ( ) : value ;
T oldVal = GetValueSkippingTopmostLayer ( t ) ;
T newVal = Interpolate ( flFraction , oldVal , interpTarget ) ;
T writeVal = ClampValue ( newVal ) ;
pWriteLayer - > InsertKey ( t , writeVal , IsUsingCurveTypes ( ) ? GetDefaultCurveType ( ) : CURVE_DEFAULT ) ;
}
//-----------------------------------------------------------------------------
// In this case, we actually stamp a key right at the head position unlike the above method
//-----------------------------------------------------------------------------
template < class T >
void CDmeTypedLog < T > : : _StampKeyAtHeadFilteredByTimeSelection ( DmeTime_t tHeadPosition , DmeTime_t tPreviousHeadPosition , const DmeLog_TimeSelection_t & params , const T & value )
{
// Should be in "layer recording" mode!!!
Assert ( GetNumLayers ( ) > = 2 ) ;
int nBestLayer = GetTopmostLayer ( ) ; // Topmost should be at least layer # 1 (0 is the base layer)
if ( nBestLayer < 1 )
return ;
CDmeTypedLogLayer < T > * pWriteLayer = GetLayer ( nBestLayer ) ;
Assert ( pWriteLayer ) ;
if ( ! pWriteLayer )
return ;
// NOTE: This little trickery is necessary to generate samples right outside the
// transition region in the case of zero length falloff regions
DmeLog_TimeSelection_t tempParams = params ;
if ( tempParams . m_nTimes [ TS_LEFT_FALLOFF ] = = tempParams . m_nTimes [ TS_LEFT_HOLD ] )
{
tempParams . m_nTimes [ TS_LEFT_FALLOFF ] - = DMETIME_MINDELTA ;
}
if ( tempParams . m_nTimes [ TS_RIGHT_FALLOFF ] = = tempParams . m_nTimes [ TS_RIGHT_HOLD ] )
{
tempParams . m_nTimes [ TS_RIGHT_FALLOFF ] + = DMETIME_MINDELTA ;
}
int nPrevRegion = tempParams . ComputeRegionForTime ( tPreviousHeadPosition ) ;
int nCurrRegion = tempParams . ComputeRegionForTime ( tHeadPosition ) ;
// Test for backward performance!
if ( nCurrRegion < nPrevRegion )
{
V_swap ( nCurrRegion , nPrevRegion ) ;
}
// Insert samples at each transition point we skipped over
for ( int i = nPrevRegion ; i < nCurrRegion ; + + i )
{
_StampKeyFilteredByTimeSelection ( pWriteLayer , tempParams . m_nTimes [ i ] , params , value , true ) ;
}
_StampKeyFilteredByTimeSelection ( pWriteLayer , tHeadPosition , params , value ) ;
}
template < class T >
void CDmeTypedLog < T > : : RemoveKeys ( DmeTime_t starttime )
{
int bestLayer = GetTopmostLayer ( ) ;
if ( bestLayer < 0 )
return ;
GetLayer ( bestLayer ) - > RemoveKeys ( starttime ) ;
}
template < class T >
void CDmeTypedLog < T > : : RemoveKey ( int nKeyIndex , int nNumKeysToRemove /*= 1*/ )
{
int bestLayer = GetTopmostLayer ( ) ;
if ( bestLayer < 0 )
return ;
GetLayer ( bestLayer ) - > RemoveKey ( nKeyIndex , nNumKeysToRemove ) ;
}
template < class T >
void CDmeTypedLog < T > : : ClearKeys ( )
{
int bestLayer = GetTopmostLayer ( ) ;
if ( bestLayer < 0 )
return ;
GetLayer ( bestLayer ) - > ClearKeys ( ) ;
}
//-----------------------------------------------------------------------------
// Returns a specific key's value
//-----------------------------------------------------------------------------
template < class T >
DmeTime_t CDmeTypedLog < T > : : GetKeyTime ( int nKeyIndex ) const
{
int bestLayer = GetTopmostLayer ( ) ;
if ( bestLayer < 0 )
return DmeTime_t : : MinTime ( ) ;
return GetLayer ( bestLayer ) - > GetKeyTime ( nKeyIndex ) ;
}
template < class T >
void CDmeTypedLog < T > : : SetKeyTime ( int nKeyIndex , DmeTime_t keyTime )
{
int bestLayer = GetTopmostLayer ( ) ;
if ( bestLayer < 0 )
return ;
return GetLayer ( bestLayer ) - > SetKeyTime ( nKeyIndex , keyTime ) ;
}
//-----------------------------------------------------------------------------
// Returns the index of a particular key
//-----------------------------------------------------------------------------
template < class T >
int CDmeTypedLog < T > : : FindKeyWithinTolerance ( DmeTime_t nTime , DmeTime_t nTolerance )
{
int bestLayer = GetTopmostLayer ( ) ;
if ( bestLayer < 0 )
return - 1 ;
return GetLayer ( bestLayer ) - > FindKeyWithinTolerance ( nTime , nTolerance ) ;
}
//-----------------------------------------------------------------------------
// tests whether two values differ by more than the threshold
//-----------------------------------------------------------------------------
template < >
bool CDmeTypedLog < Vector > : : ValuesDiffer ( const Vector & a , const Vector & b ) const
{
return a . DistToSqr ( b ) > m_threshold * m_threshold ;
}
template < >
bool CDmeTypedLog < QAngle > : : ValuesDiffer ( const QAngle & a , const QAngle & b ) const
{
return ( a - b ) . LengthSqr ( ) > m_threshold * m_threshold ;
}
template < >
bool CDmeTypedLog < Quaternion > : : ValuesDiffer ( const Quaternion & a , const Quaternion & b ) const
{
return QuaternionAngleDiff ( a , b ) > m_threshold ;
}
template < >
bool CDmeTypedLog < float > : : ValuesDiffer ( const float & a , const float & b ) const
{
return fabs ( a - b ) > m_threshold ;
}
template < class T >
bool CDmeTypedLog < T > : : ValuesDiffer ( const T & a , const T & b ) const
{
return a ! = b ;
}
//-----------------------------------------------------------------------------
// Sets a key, removes all keys after this time
//-----------------------------------------------------------------------------
template < class T >
void CDmeTypedLog < T > : : SetKey ( DmeTime_t time , const T & value , int curveType /*=CURVE_DEFAULT*/ )
{
int bestLayer = GetTopmostLayer ( ) ;
if ( bestLayer < 0 )
return ;
GetLayer ( bestLayer ) - > SetKey ( time , value , curveType ) ;
}
template < class T >
CDmeTypedLogLayer < T > * CDmeTypedLog < T > : : GetLayer ( int index )
{
if ( index < 0 )
return NULL ;
return static_cast < CDmeTypedLogLayer < T > * > ( m_Layers [ index ] ) ;
}
template < class T >
const CDmeTypedLogLayer < T > * CDmeTypedLog < T > : : GetLayer ( int index ) const
{
if ( index < 0 )
return NULL ;
return static_cast < CDmeTypedLogLayer < T > * > ( m_Layers [ index ] ) ;
}
//-----------------------------------------------------------------------------
// Finds a key within tolerance, or adds one
//-----------------------------------------------------------------------------
template < class T >
int CDmeTypedLog < T > : : FindOrAddKey ( DmeTime_t nTime , DmeTime_t nTolerance , const T & value , int curveType /*=CURVE_DEFAULT*/ )
{
int bestLayer = GetTopmostLayer ( ) ;
if ( bestLayer = = - 1 )
return - 1 ;
return GetLayer ( bestLayer ) - > FindOrAddKey ( nTime , nTolerance , value , curveType ) ;
}
//-----------------------------------------------------------------------------
// This inserts a key. Unlike SetKey, this will *not* delete keys after the specified time
//-----------------------------------------------------------------------------
template < class T >
int CDmeTypedLog < T > : : InsertKey ( DmeTime_t nTime , const T & value , int curveType /*=CURVE_DEFAULT*/ )
{
int bestLayer = GetTopmostLayer ( ) ;
if ( bestLayer = = - 1 )
return - 1 ;
return GetLayer ( bestLayer ) - > InsertKey ( nTime , value , curveType ) ;
}
template < class T >
int CDmeTypedLog < T > : : InsertKeyAtTime ( DmeTime_t nTime , int curveType /*=CURVE_DEFAULT*/ )
{
int bestLayer = GetTopmostLayer ( ) ;
if ( bestLayer = = - 1 )
return - 1 ;
return GetLayer ( bestLayer ) - > InsertKeyAtTime ( nTime , curveType ) ;
}
template < class T >
const T & CDmeTypedLog < T > : : GetValue ( DmeTime_t time ) const
{
int bestLayer = FindLayerForTime ( time ) ;
if ( bestLayer < 0 )
{
static T s_value ;
CDmAttributeInfo < T > : : SetDefaultValue ( s_value ) ; // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
return s_value ;
}
return GetLayer ( bestLayer ) - > GetValue ( time ) ;
}
template < class T >
const T & CDmeTypedLog < T > : : GetValueSkippingTopmostLayer ( DmeTime_t time ) const
{
int nLayer = FindLayerForTimeSkippingTopmost ( time ) ;
if ( nLayer < 0 )
return GetValue ( time ) ;
return GetLayer ( nLayer ) - > GetValue ( time ) ;
}
template < class T >
void CDmeTypedLog < T > : : SetKey ( DmeTime_t time , const CDmAttribute * pAttr , uint index , int curveType /*= CURVE_DEFAULT*/ )
{
int bestLayer = GetTopmostLayer ( ) ;
if ( bestLayer = = - 1 )
return ;
GetLayer ( bestLayer ) - > SetKey ( time , pAttr , index , curveType ) ;
}
template < class T >
bool CDmeTypedLog < T > : : SetDuplicateKeyAtTime ( DmeTime_t time )
{
int bestLayer = GetTopmostLayer ( ) ;
if ( bestLayer = = - 1 )
return false ;
return GetLayer ( bestLayer ) - > SetDuplicateKeyAtTime ( time ) ;
}
//-----------------------------------------------------------------------------
// Returns a specific key's value
//-----------------------------------------------------------------------------
template < class T >
const T & CDmeTypedLog < T > : : GetKeyValue ( int nKeyIndex ) const
{
int bestLayer = GetTopmostLayer ( ) ;
if ( bestLayer = = - 1 )
{
static T s_value ;
CDmAttributeInfo < T > : : SetDefaultValue ( s_value ) ; // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
return s_value ;
}
return GetLayer ( bestLayer ) - > GetKeyValue ( nKeyIndex ) ;
}
template < class T >
void CDmeTypedLog < T > : : GetValue ( DmeTime_t time , CDmAttribute * pAttr , uint index ) const
{
int bestLayer = FindLayerForTime ( time ) ;
if ( bestLayer < 0 )
{
T value ;
CDmAttributeInfo < T > : : SetDefaultValue ( value ) ; // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
pAttr - > SetValue ( CDmAttributeInfo < T > : : AttributeType ( ) , & value ) ;
}
return GetLayer ( bestLayer ) - > GetValue ( time , pAttr , index ) ;
}
template < class T >
void CDmeTypedLog < T > : : GetValueSkippingTopmostLayer ( DmeTime_t time , CDmAttribute * pAttr , uint index = 0 ) const
{
CUtlVector < int > layers ;
FindLayersForTime ( time , layers ) ;
int layerCount = layers . Count ( ) ;
if ( layerCount < = 1 )
{
return GetValue ( time , pAttr , index ) ;
}
int topMostLayer = GetTopmostLayer ( ) ;
int useLayer = layers [ layerCount - 1 ] ;
if ( topMostLayer = = useLayer )
{
useLayer = layers [ layerCount - 2 ] ;
}
Assert ( useLayer > = 0 ) ;
return GetLayer ( useLayer ) - > GetValue ( time , pAttr , index ) ;
}
template < class T >
float CDmeTypedLog < T > : : GetComponent ( DmeTime_t time , int componentIndex ) const
{
return : : GetComponent ( GetValue ( time ) , componentIndex ) ;
}
//-----------------------------------------------------------------------------
// resampling and filtering
//-----------------------------------------------------------------------------
template < class T >
void CDmeTypedLog < T > : : Resample ( DmeFramerate_t samplerate )
{
int c = m_Layers . Count ( ) ;
for ( int i = 0 ; i < c ; + + i )
{
GetLayer ( i ) - > Resample ( samplerate ) ;
}
}
template < class T >
void CDmeTypedLog < T > : : Filter ( int nSampleRadius )
{
int c = m_Layers . Count ( ) ;
for ( int i = 0 ; i < c ; + + i )
{
GetLayer ( i ) - > Filter ( nSampleRadius ) ;
}
}
template < class T >
void CDmeTypedLog < T > : : Filter2 ( DmeTime_t sampleRadius )
{
int c = m_Layers . Count ( ) ;
for ( int i = 0 ; i < c ; + + i )
{
GetLayer ( i ) - > Filter2 ( sampleRadius ) ;
}
}
template < class T >
void CDmeTypedLog < T > : : OnAttributeArrayElementAdded ( CDmAttribute * pAttribute , int nFirstElem , int nLastElem )
{
BaseClass : : OnAttributeArrayElementAdded ( pAttribute , nFirstElem , nLastElem ) ;
if ( pAttribute = = m_Layers . GetAttribute ( ) )
{
for ( int i = nFirstElem ; i < = nLastElem ; + + i )
{
m_Layers [ i ] - > SetOwnerLog ( this ) ;
}
return ;
}
}
template < class T >
void CDmeTypedLog < T > : : SetUseEdgeInfo ( bool state )
{
Assert ( IsUsingCurveTypes ( ) ) ;
GetTypedCurveInfo ( ) - > SetUseEdgeInfo ( state ) ;
}
template < class T >
bool CDmeTypedLog < T > : : IsUsingEdgeInfo ( ) const
{
Assert ( IsUsingCurveTypes ( ) ) ;
return GetTypedCurveInfo ( ) - > IsUsingEdgeInfo ( ) ;
}
template < class T >
void CDmeTypedLog < T > : : SetEdgeInfo ( int edge , bool active , const T & val , int curveType )
{
Assert ( IsUsingCurveTypes ( ) ) ;
GetTypedCurveInfo ( ) - > SetEdgeInfo ( edge , active , val , curveType ) ;
}
template < class T >
void CDmeTypedLog < T > : : SetDefaultEdgeZeroValue ( const T & val )
{
Assert ( IsUsingCurveTypes ( ) ) ;
GetTypedCurveInfo ( ) - > SetDefaultEdgeZeroValue ( val ) ;
}
template < class T >
const T & CDmeTypedLog < T > : : GetDefaultEdgeZeroValue ( ) const
{
Assert ( IsUsingCurveTypes ( ) ) ;
return GetTypedCurveInfo ( ) - > GetDefaultEdgeZeroValue ( ) ;
}
template < class T >
void CDmeTypedLog < T > : : SetRightEdgeTime ( DmeTime_t time )
{
Assert ( IsUsingCurveTypes ( ) ) ;
GetTypedCurveInfo ( ) - > SetRightEdgeTime ( time ) ;
}
template < class T >
DmeTime_t CDmeTypedLog < T > : : GetRightEdgeTime ( ) const
{
Assert ( IsUsingCurveTypes ( ) ) ;
return GetTypedCurveInfo ( ) - > GetRightEdgeTime ( ) ;
}
template < class T >
void CDmeTypedLog < T > : : GetEdgeInfo ( int edge , bool & active , T & val , int & curveType ) const
{
Assert ( IsUsingCurveTypes ( ) ) ;
GetTypedCurveInfo ( ) - > GetEdgeInfo ( edge , active , val , curveType ) ;
}
template < class T >
int CDmeTypedLog < T > : : GetEdgeCurveType ( int edge ) const
{
Assert ( IsUsingCurveTypes ( ) ) ;
return GetTypedCurveInfo ( ) - > GetEdgeCurveType ( edge ) ;
}
template < class T >
void CDmeTypedLog < T > : : GetZeroValue ( int side , T & val ) const
{
Assert ( IsUsingCurveTypes ( ) ) ;
GetTypedCurveInfo ( ) - > GetZeroValue ( side , val ) ;
}
template < class T >
bool CDmeTypedLog < T > : : IsEdgeActive ( int edge ) const
{
Assert ( IsUsingCurveTypes ( ) ) ;
return GetTypedCurveInfo ( ) - > IsEdgeActive ( edge ) ;
}
template < class T >
void CDmeTypedLog < T > : : GetEdgeValue ( int edge , T & val ) const
{
Assert ( IsUsingCurveTypes ( ) ) ;
GetTypedCurveInfo ( ) - > GetEdgeValue ( edge , val ) ;
}
template < class T >
void CDmeTypedLog < T > : : BlendTimesUsingTimeSelection ( const CDmeLogLayer * firstLayer , const CDmeLogLayer * secondLayer , CDmeLogLayer * outputLayer , const DmeLog_TimeSelection_t & params , DmeTime_t tStartOffset )
{
const CDmeTypedLogLayer < T > * topLayer = static_cast < const CDmeTypedLogLayer < T > * > ( secondLayer ) ;
if ( ! topLayer )
return ;
const CDmeTypedLogLayer < T > * baseLayer = static_cast < const CDmeTypedLogLayer < T > * > ( firstLayer ) ;
if ( ! baseLayer )
return ;
CDmeTypedLogLayer < T > * newLayer = static_cast < CDmeTypedLogLayer < T > * > ( outputLayer ) ;
if ( ! newLayer )
return ;
Assert ( topLayer - > GetKeyCount ( ) = = baseLayer - > GetKeyCount ( ) ) ;
int i ;
// Resample everything in the base layer first
int kc = baseLayer - > GetKeyCount ( ) ;
newLayer - > ClearKeys ( ) ;
for ( i = 0 ; i < kc ; + + i )
{
DmeTime_t baseKeyTime = baseLayer - > GetKeyTime ( i ) ;
DmeTime_t checkTime = baseKeyTime + tStartOffset ;
if ( checkTime < params . m_nTimes [ TS_LEFT_FALLOFF ] )
continue ;
if ( checkTime > params . m_nTimes [ TS_RIGHT_FALLOFF ] )
break ;
float frac = params . GetAmountForTime ( checkTime ) ;
float frac2 = params . m_flIntensity ;
float flInterp = frac2 * frac ;
DmeTime_t targetKeyTime = topLayer - > GetKeyTime ( i ) ;
DmeTime_t blendedKeyTime = Lerp ( flInterp , baseKeyTime , targetKeyTime ) + tStartOffset ;
T baseVal = baseLayer - > GetKeyValue ( i ) ;
newLayer - > InsertKey ( blendedKeyTime , baseVal ) ;
}
}
template < class T >
void CDmeTypedLog < T > : : BlendLayersUsingTimeSelection ( const CDmeLogLayer * firstLayer , const CDmeLogLayer * secondLayer , CDmeLogLayer * outputLayer , const DmeLog_TimeSelection_t & params , bool bUseBaseLayerSamples , DmeTime_t tStartOffset )
{
const CDmeTypedLogLayer < T > * topLayer = static_cast < const CDmeTypedLogLayer < T > * > ( secondLayer ) ;
if ( ! topLayer )
return ;
const CDmeTypedLogLayer < T > * baseLayer = static_cast < const CDmeTypedLogLayer < T > * > ( firstLayer ) ;
if ( ! baseLayer )
return ;
CDmeTypedLogLayer < T > * newLayer = static_cast < CDmeTypedLogLayer < T > * > ( outputLayer ) ;
if ( ! newLayer )
return ;
int i ;
// Resample everything in the base layer first
int kc = baseLayer - > GetKeyCount ( ) ;
if ( bUseBaseLayerSamples )
{
for ( i = 0 ; i < kc ; + + i )
{
DmeTime_t keyTime = baseLayer - > GetKeyTime ( i ) ;
if ( keyTime < params . m_nTimes [ TS_LEFT_FALLOFF ] )
continue ;
if ( keyTime > params . m_nTimes [ TS_RIGHT_FALLOFF ] )
break ;
float frac = params . GetAmountForTime ( keyTime ) ;
float frac2 = params . m_flIntensity ;
T baseVal = baseLayer - > GetKeyValue ( i ) ;
T newVal = topLayer - > GetValue ( keyTime ) ;
T blended = Interpolate ( frac2 * frac , baseVal , newVal ) ;
newLayer - > SetKey ( keyTime + tStartOffset , blended ) ;
}
}
kc = topLayer - > GetKeyCount ( ) ;
for ( i = 0 ; i < kc ; + + i )
{
DmeTime_t keyTime = topLayer - > GetKeyTime ( i ) ;
DmeTime_t finalKeyTime = keyTime + tStartOffset ;
if ( finalKeyTime < params . m_nTimes [ TS_LEFT_FALLOFF ] )
continue ;
if ( finalKeyTime > params . m_nTimes [ TS_RIGHT_FALLOFF ] )
break ;
float frac = params . GetAmountForTime ( finalKeyTime ) ;
float frac2 = params . m_flIntensity ;
T baseVal = baseLayer - > GetValue ( keyTime ) ;
T newVal = topLayer - > GetKeyValue ( i ) ;
T blended = Interpolate ( frac2 * frac , baseVal , newVal ) ;
newLayer - > InsertKey ( finalKeyTime , blended ) ;
}
if ( g_pDmElementFramework - > GetPhase ( ) = = PH_EDIT )
{
newLayer - > RemoveRedundantKeys ( params . m_flThreshold ) ;
}
}
template < class T >
void CDmeTypedLog < T > : : BlendLayersUsingTimeSelection ( const DmeLog_TimeSelection_t & params )
{
Assert ( GetNumLayers ( ) > = 2 ) ;
int bestLayer = GetTopmostLayer ( ) ; // Topmost should be at least layer # 1 (0 is the base layer)
if ( bestLayer < = 0 )
return ;
Assert ( params . m_nResampleInterval > DmeTime_t ( 0 ) ) ;
if ( params . m_nResampleInterval < DmeTime_t ( 0 ) )
return ;
CDmeTypedLogLayer < T > * topLayer = GetLayer ( bestLayer ) ;
Assert ( topLayer ) ;
if ( ! topLayer )
return ;
CDmeTypedLogLayer < T > * baseLayer = GetLayer ( 0 ) ;
if ( ! baseLayer )
return ;
CDmeTypedLogLayer < T > * newLayer = static_cast < CDmeTypedLogLayer < T > * > ( CreateLayer < T > ( this ) ) ;
if ( ! newLayer )
return ;
BlendLayersUsingTimeSelection ( baseLayer , topLayer , newLayer , params , true , DMETIME_ZERO ) ;
// Store it back into the new topmost layer
topLayer - > CopyLayer ( newLayer ) ;
g_pDataModel - > DestroyElement ( newLayer - > GetHandle ( ) ) ;
}
template < class T >
void CDmeTypedLog < T > : : RevealUsingTimeSelection ( const DmeLog_TimeSelection_t & params , CDmeLogLayer * savedLayer )
{
CDmeTypedLogLayer < T > * saved = static_cast < CDmeTypedLogLayer < T > * > ( savedLayer ) ;
if ( ! saved )
return ;
Assert ( GetNumLayers ( ) > = 2 ) ;
int bestLayer = GetTopmostLayer ( ) ; // Topmost should be at least layer # 1 (0 is the base layer)
if ( bestLayer < = 0 )
return ;
Assert ( params . m_nResampleInterval > DmeTime_t ( 0 ) ) ;
if ( params . m_nResampleInterval < DmeTime_t ( 0 ) )
return ;
CDmeTypedLogLayer < T > * writeLayer = static_cast < CDmeTypedLogLayer < T > * > ( GetLayer ( bestLayer ) ) ;
Assert ( writeLayer ) ;
if ( ! writeLayer )
return ;
CDmeLogLayer * baseLayer = GetLayer ( 0 ) ;
if ( ! baseLayer )
return ;
DmeTime_t resample = 0.5f * params . m_nResampleInterval ;
// Do a second pass where we bis the keys in the falloff area back toward the original value
for ( int t = params . m_nTimes [ TS_LEFT_FALLOFF ] . GetTenthsOfMS ( ) ; t < params . m_nTimes [ TS_RIGHT_FALLOFF ] . GetTenthsOfMS ( ) + resample . GetTenthsOfMS ( ) ; t + = resample . GetTenthsOfMS ( ) )
{
DmeTime_t curtime = DmeTime_t ( t ) ;
if ( curtime > params . m_nTimes [ TS_RIGHT_FALLOFF ] )
curtime = params . m_nTimes [ TS_RIGHT_FALLOFF ] ;
float frac = params . GetAmountForTime ( curtime ) ;
frac * = params . m_flIntensity ;
if ( frac < = 0.0f )
continue ;
// Get current value in layer
T curValue = GetValueSkippingTopmostLayer ( curtime ) ;
T revealValue = saved - > GetValue ( curtime ) ;
T newValue = Interpolate ( frac , curValue , revealValue ) ;
// Overwrite key
writeLayer - > InsertKey ( curtime , newValue , IsUsingCurveTypes ( ) ? GetDefaultCurveType ( ) : CURVE_DEFAULT ) ;
}
if ( g_pDmElementFramework - > GetPhase ( ) = = PH_EDIT )
{
writeLayer - > RemoveRedundantKeys ( params . m_flThreshold ) ;
}
}
template < class T >
void RandomValue ( const T & average , const T & oldValue , T & newValue )
{
newValue = oldValue ;
}
template < > void RandomValue ( const Vector & average , const Vector & oldValue , Vector & newValue )
{
newValue = oldValue ;
for ( int i = 0 ; i < 3 ; + + i )
{
newValue [ i ] + = RandomFloat ( - fabs ( average [ i ] ) , fabs ( average [ i ] ) ) ;
}
}
template < > void RandomValue ( const Quaternion & average , const Quaternion & oldValue , Quaternion & newValue )
{
newValue = oldValue ;
for ( int i = 0 ; i < 4 ; + + i )
{
newValue [ i ] + = RandomFloat ( - fabs ( average [ i ] ) , fabs ( average [ i ] ) ) ;
}
}
template < > void RandomValue ( const Vector4D & average , const Vector4D & oldValue , Vector4D & newValue )
{
newValue = oldValue ;
for ( int i = 0 ; i < 4 ; + + i )
{
newValue [ i ] + = RandomFloat ( - fabs ( average [ i ] ) , fabs ( average [ i ] ) ) ;
}
}
template < > void RandomValue ( const Vector2D & average , const Vector2D & oldValue , Vector2D & newValue )
{
newValue = oldValue ;
for ( int i = 0 ; i < 2 ; + + i )
{
newValue [ i ] + = RandomFloat ( - fabs ( average [ i ] ) , fabs ( average [ i ] ) ) ;
}
}
template < > void RandomValue ( const float & average , const float & oldValue , float & newValue )
{
newValue = oldValue + RandomFloat ( - average , average ) ;
}
template < > void RandomValue ( const int & average , const int & oldValue , int & newValue )
{
newValue = oldValue + RandomInt ( - average , average ) ;
}
// Builds a layer with samples matching the times in reference layer, from the data in pDataLayer, putting the resulting keys into pOutputLayer
template < class T >
void CDmeTypedLog < T > : : BuildCorrespondingLayer ( const CDmeLogLayer * pReferenceLayer , const CDmeLogLayer * pDataLayer , CDmeLogLayer * pOutputLayer )
{
const CDmeTypedLogLayer < T > * ref = static_cast < const CDmeTypedLogLayer < T > * > ( pReferenceLayer ) ;
const CDmeTypedLogLayer < T > * data = static_cast < const CDmeTypedLogLayer < T > * > ( pDataLayer ) ;
CDmeTypedLogLayer < T > * out = static_cast < CDmeTypedLogLayer < T > * > ( pOutputLayer ) ;
if ( ! ref | | ! data | | ! out )
{
Assert ( 0 ) ;
return ;
}
bool usecurvetypes = ref - > IsUsingCurveTypes ( ) ;
out - > ClearKeys ( ) ;
int kc = ref - > GetKeyCount ( ) ;
for ( int i = 0 ; i < kc ; + + i )
{
DmeTime_t keyTime = ref - > GetKeyTime ( i ) ;
T value = data - > GetValue ( keyTime ) ;
out - > InsertKey ( keyTime , value , usecurvetypes ? GetDefaultCurveType ( ) : CURVE_DEFAULT ) ;
}
}
template < class T >
void CDmeTypedLog < T > : : StaggerUsingTimeSelection ( const DmeLog_TimeSelection_t & params , DmeTime_t tStaggerAmount , const CDmeLogLayer * pBaseLayer , CDmeLogLayer * pWriteLayer )
{
CDmeTypedLogLayer < T > * writeLayer = static_cast < CDmeTypedLogLayer < T > * > ( pWriteLayer ) ;
Assert ( writeLayer ) ;
if ( ! writeLayer )
return ;
const CDmeTypedLogLayer < T > * baseLayer = static_cast < const CDmeTypedLogLayer < T > * > ( pBaseLayer ) ;
if ( ! baseLayer )
return ;
writeLayer - > ClearKeys ( ) ;
DmeLog_TimeSelection_t newParams ;
newParams = params ;
// Move the hold area by the stagger amount
float flScaleFactor [ 2 ] = { 1.0f , 1.0f } ;
newParams . m_nTimes [ TS_LEFT_HOLD ] + = tStaggerAmount ;
newParams . m_nTimes [ TS_RIGHT_HOLD ] + = tStaggerAmount ;
for ( int i = 0 ; i < 2 ; + + i )
{
DmeTime_t dt = params . m_nTimes [ 2 * i + 1 ] - params . m_nTimes [ 2 * i ] ;
if ( dt > DMETIME_ZERO )
{
DmeTime_t newDt = newParams . m_nTimes [ 2 * i + 1 ] - newParams . m_nTimes [ 2 * i ] ;
flScaleFactor [ i ] = newDt / dt ;
}
}
int kc = baseLayer - > GetKeyCount ( ) ;
for ( int i = 0 ; i < kc ; + + i )
{
DmeTime_t curtime = baseLayer - > GetKeyTime ( i ) ;
T oldValue = baseLayer - > GetKeyValue ( i ) ;
// Classify time
if ( curtime < = params . m_nTimes [ TS_LEFT_HOLD ] )
{
curtime = curtime * flScaleFactor [ 0 ] ;
}
else if ( curtime > = params . m_nTimes [ TS_RIGHT_HOLD ] )
{
curtime = params . m_nTimes [ TS_RIGHT_FALLOFF ] - ( params . m_nTimes [ TS_RIGHT_FALLOFF ] - curtime ) * flScaleFactor [ 1 ] ;
}
else
{
curtime + = tStaggerAmount ;
}
writeLayer - > InsertKey ( curtime , oldValue , IsUsingCurveTypes ( ) ? GetDefaultCurveType ( ) : CURVE_DEFAULT ) ;
}
}
template < class T >
void CDmeTypedLog < T > : : FilterUsingTimeSelection ( IUniformRandomStream * random , const DmeLog_TimeSelection_t & params , int filterType , bool bResample , bool bApplyFalloff )
{
Assert ( GetNumLayers ( ) > = 2 ) ;
int bestLayer = GetTopmostLayer ( ) ; // Topmost should be at least layer # 1 (0 is the base layer)
if ( bestLayer < = 0 )
return ;
CDmeTypedLogLayer < T > * writeLayer = GetLayer ( bestLayer ) ;
Assert ( writeLayer ) ;
if ( ! writeLayer )
return ;
CDmeTypedLogLayer < T > * baseLayer = GetLayer ( 0 ) ;
if ( ! baseLayer )
return ;
FilterUsingTimeSelection ( random , 1.0f , params , filterType , bResample , bApplyFalloff , baseLayer , writeLayer ) ;
}
template < class T >
void CDmeTypedLog < T > : : FilterUsingTimeSelection ( IUniformRandomStream * random , float flScale , const DmeLog_TimeSelection_t & params , int filterType , bool bResample , bool bApplyFalloff , const CDmeLogLayer * pBaseLayer , CDmeLogLayer * pWriteLayer )
{
Assert ( params . m_nResampleInterval > DmeTime_t ( 0 ) ) ;
if ( params . m_nResampleInterval < DmeTime_t ( 0 ) )
return ;
CDmeTypedLogLayer < T > * writeLayer = static_cast < CDmeTypedLogLayer < T > * > ( pWriteLayer ) ;
Assert ( writeLayer ) ;
if ( ! writeLayer )
return ;
const CDmeTypedLogLayer < T > * baseLayer = static_cast < const CDmeTypedLogLayer < T > * > ( pBaseLayer ) ;
if ( ! baseLayer )
return ;
writeLayer - > ClearKeys ( ) ;
DmeTime_t resample = 0.5f * params . m_nResampleInterval ;
switch ( filterType )
{
default :
case FILTER_SMOOTH :
{
int t ;
if ( bResample )
{
for ( t = params . m_nTimes [ TS_LEFT_FALLOFF ] . GetTenthsOfMS ( ) ; t < params . m_nTimes [ TS_RIGHT_FALLOFF ] . GetTenthsOfMS ( ) + resample . GetTenthsOfMS ( ) ; t + = resample . GetTenthsOfMS ( ) )
{
DmeTime_t curtime = DmeTime_t ( t ) ;
if ( curtime > params . m_nTimes [ TS_RIGHT_FALLOFF ] )
curtime = params . m_nTimes [ TS_RIGHT_FALLOFF ] ;
T curValue = baseLayer - > GetValue ( curtime ) ;
writeLayer - > SetKey ( curtime , curValue , IsUsingCurveTypes ( ) ? GetDefaultCurveType ( ) : CURVE_DEFAULT ) ;
}
}
else
{
// Do a second pass where we bias the keys in the falloff area back toward the original value
int kc = baseLayer - > GetKeyCount ( ) ;
for ( int i = 0 ; i < kc ; + + i )
{
DmeTime_t curtime = baseLayer - > GetKeyTime ( i ) ;
if ( curtime < params . m_nTimes [ TS_LEFT_FALLOFF ] )
continue ;
if ( curtime > params . m_nTimes [ TS_RIGHT_FALLOFF ] )
continue ;
T oldValue = baseLayer - > GetKeyValue ( i ) ;
writeLayer - > InsertKey ( curtime , oldValue , IsUsingCurveTypes ( ) ? GetDefaultCurveType ( ) : CURVE_DEFAULT ) ;
}
}
writeLayer - > Filter2 ( params . m_nResampleInterval * 0.95f * flScale ) ;
if ( bApplyFalloff )
{
if ( bResample )
{
// Do a second pass where we bias the keys in the falloff area back toward the original value
for ( t = params . m_nTimes [ TS_LEFT_FALLOFF ] . GetTenthsOfMS ( ) ; t < params . m_nTimes [ TS_RIGHT_FALLOFF ] . GetTenthsOfMS ( ) + resample . GetTenthsOfMS ( ) ; t + = resample . GetTenthsOfMS ( ) )
{
DmeTime_t curtime = DmeTime_t ( t ) ;
if ( curtime > params . m_nTimes [ TS_RIGHT_FALLOFF ] )
curtime = params . m_nTimes [ TS_RIGHT_FALLOFF ] ;
T oldValue = baseLayer - > GetValue ( curtime ) ;
if ( curtime > = params . m_nTimes [ TS_LEFT_HOLD ] & & curtime < = params . m_nTimes [ TS_RIGHT_HOLD ] )
continue ;
// Modulate these keys back down toward the original value
T newValue = writeLayer - > GetValue ( curtime ) ;
float frac = bApplyFalloff ? params . GetAmountForTime ( curtime ) : 1.0f ;
newValue = Interpolate ( frac , oldValue , newValue ) ;
// Overwrite key
writeLayer - > InsertKey ( curtime , newValue , IsUsingCurveTypes ( ) ? GetDefaultCurveType ( ) : CURVE_DEFAULT ) ;
}
}
else
{
// Do a second pass where we bias the keys in the falloff area back toward the original value
int kc = writeLayer - > GetKeyCount ( ) ;
for ( int i = 0 ; i < kc ; + + i )
{
DmeTime_t curtime = writeLayer - > GetKeyTime ( i ) ;
if ( curtime < params . m_nTimes [ TS_LEFT_FALLOFF ] )
continue ;
if ( curtime > params . m_nTimes [ TS_RIGHT_FALLOFF ] )
continue ;
if ( curtime > = params . m_nTimes [ TS_LEFT_HOLD ] & & curtime < = params . m_nTimes [ TS_RIGHT_HOLD ] )
continue ;
T oldValue = baseLayer - > GetValue ( curtime ) ;
// Modulate these keys back down toward the original value
T newValue = writeLayer - > GetValue ( curtime ) ;
float frac = bApplyFalloff ? params . GetAmountForTime ( curtime ) : 1.0f ;
newValue = Interpolate ( frac , oldValue , newValue ) ;
// Overwrite key
writeLayer - > InsertKey ( curtime , newValue , IsUsingCurveTypes ( ) ? GetDefaultCurveType ( ) : CURVE_DEFAULT ) ;
}
}
}
if ( bResample )
{
writeLayer - > RemoveRedundantKeys ( params . m_flThreshold ) ;
}
}
break ;
case FILTER_JITTER :
{
// Compute average value in entire log
T average = Average ( baseLayer - > m_values . Base ( ) , baseLayer - > m_values . Count ( ) ) ;
average = ScaleValue ( average , 0.05f * flScale ) ;
if ( bResample )
{
int t ;
for ( t = params . m_nTimes [ TS_LEFT_FALLOFF ] . GetTenthsOfMS ( ) ; t < params . m_nTimes [ TS_RIGHT_FALLOFF ] . GetTenthsOfMS ( ) + resample . GetTenthsOfMS ( ) ; t + = resample . GetTenthsOfMS ( ) )
{
DmeTime_t curtime = DmeTime_t ( t ) ;
if ( curtime > params . m_nTimes [ TS_RIGHT_FALLOFF ] )
curtime = params . m_nTimes [ TS_RIGHT_FALLOFF ] ;
float frac = bApplyFalloff ? params . GetAmountForTime ( curtime ) : 1.0f ;
T oldValue = baseLayer - > GetValue ( curtime ) ;
T newValue ;
RandomValue ( average , oldValue , newValue ) ;
newValue = Interpolate ( frac , oldValue , newValue ) ;
writeLayer - > SetKey ( curtime , newValue , IsUsingCurveTypes ( ) ? GetDefaultCurveType ( ) : CURVE_DEFAULT ) ;
}
}
else
{
int kc = baseLayer - > GetKeyCount ( ) ;
for ( int i = 0 ; i < kc ; + + i )
{
DmeTime_t curtime = baseLayer - > GetKeyTime ( i ) ;
if ( curtime < params . m_nTimes [ TS_LEFT_FALLOFF ] )
continue ;
if ( curtime > params . m_nTimes [ TS_RIGHT_FALLOFF ] )
continue ;
float frac = bApplyFalloff ? params . GetAmountForTime ( curtime ) : 1.0f ;
T oldValue = baseLayer - > GetValue ( curtime ) ;
T newValue ;
RandomValue ( average , oldValue , newValue ) ;
newValue = Interpolate ( frac , oldValue , newValue ) ;
writeLayer - > InsertKey ( curtime , newValue , IsUsingCurveTypes ( ) ? GetDefaultCurveType ( ) : CURVE_DEFAULT ) ;
}
}
}
break ;
case FILTER_SHARPEN :
case FILTER_SOFTEN :
{
writeLayer - > ClearKeys ( ) ;
bool bSharpen = filterType = = FILTER_SHARPEN ;
int kc = baseLayer - > GetKeyCount ( ) ;
for ( int i = 0 ; i < kc ; + + i )
{
DmeTime_t curtime = baseLayer - > GetKeyTime ( i ) ;
if ( curtime < params . m_nTimes [ TS_LEFT_FALLOFF ] )
continue ;
if ( curtime > params . m_nTimes [ TS_RIGHT_FALLOFF ] )
continue ;
float frac = bApplyFalloff ? params . GetAmountForTime ( curtime ) : 1.0f ;
T oldValue = baseLayer - > GetValue ( curtime ) ;
T newValue = oldValue ;
if ( frac ! = 1.0f )
{
T crossingValue [ 2 ] = { oldValue , oldValue } ;
if ( curtime < = params . m_nTimes [ TS_LEFT_HOLD ] )
{
// Get the value at the crossing point (either green edge for sharpen, or left edge for soften...)
crossingValue [ 0 ] = baseLayer - > GetValue ( params . m_nTimes [ TS_LEFT_FALLOFF ] ) ;
crossingValue [ 1 ] = baseLayer - > GetValue ( params . m_nTimes [ TS_LEFT_HOLD ] ) ;
}
else if ( curtime > = params . m_nTimes [ TS_RIGHT_HOLD ] )
{
crossingValue [ 0 ] = baseLayer - > GetValue ( params . m_nTimes [ TS_RIGHT_FALLOFF ] ) ;
crossingValue [ 1 ] = baseLayer - > GetValue ( params . m_nTimes [ TS_RIGHT_HOLD ] ) ;
}
else
{
Assert ( 0 ) ;
}
T dynamicRange = Subtract ( crossingValue [ 1 ] , crossingValue [ 0 ] ) ;
int iType = bSharpen ? INTERPOLATE_EASE_IN : INTERPOLATE_EASE_OUT ;
Vector points [ 4 ] ;
points [ 0 ] . Init ( ) ;
points [ 1 ] . Init ( 0.0 , 0.0 , 0.0f ) ;
points [ 2 ] . Init ( 1.0f , 1.0f , 0.0f ) ;
points [ 3 ] . Init ( ) ;
Vector out ;
Interpolator_CurveInterpolate
(
iType ,
points [ 0 ] , // unused
points [ 1 ] ,
points [ 2 ] ,
points [ 3 ] , // unused
frac ,
out
) ;
float flBias = clamp ( out . y , 0.0f , 1.0f ) ;
float dFrac = flScale * ( frac - flBias ) ;
newValue = Add ( oldValue , ScaleValue ( dynamicRange , dFrac ) ) ;
}
writeLayer - > InsertKey ( curtime , newValue , IsUsingCurveTypes ( ) ? GetDefaultCurveType ( ) : CURVE_DEFAULT ) ;
}
}
break ;
}
}
enum PasteState_t
{
PASTE_STATE_BEFORE = - 1 ,
PASTE_STATE_RAMP_IN = 0 ,
PASTE_STATE_HOLD ,
PASTE_STATE_RAMP_OUT ,
PASTE_STATE_COUNT ,
PASTE_STATE_AFTER = PASTE_STATE_COUNT ,
} ;
template < class T >
static void CountClipboardSamples ( int * pCount , CDmeTypedLogLayer < T > * pClipboard , const DmeLog_TimeSelection_t & params )
{
pCount [ 0 ] = pCount [ 1 ] = pCount [ 2 ] = 0 ;
int nKeyCount = pClipboard - > GetKeyCount ( ) ;
for ( int i = 0 ; i < nKeyCount ; + + i )
{
DmeTime_t tKeyTime = pClipboard - > GetKeyTime ( i ) ;
int nIndex = params . ComputeRegionForTime ( tKeyTime ) - 1 ;
if ( nIndex < 0 | | nIndex > 2 )
continue ;
// Only count interstitial samples.. don't count ones that land exactly on boundaries
if ( tKeyTime ! = params . m_nTimes [ nIndex ] & & tKeyTime ! = params . m_nTimes [ nIndex + 1 ] )
{
pCount [ nIndex ] + + ;
}
}
}
//-----------------------------------------------------------------------------
// Used by PasteAndRescaleSamples to determine if it should skip a transition or not
//-----------------------------------------------------------------------------
static inline bool ShouldSkipTransition ( int nTransition , int nZeroField )
{
// NOTE: This is pretty tricky. The bits of the 'zero field' are set to true
// for each region whose source + dest region size is exactly 0 seconds.
// Here's the table this logic is reproducing:
// 0,1,2,3 are the time selection m_nTimes, and A,B,C are the regions
// 0 1 2 3
// | A | B | C |
//
// nZeroField bits
// C B A Skip transitions
// 0 0 0 none
// 0 0 1 2
// 0 1 0 2
// 0 1 1 1, 2
// 1 0 0 1
// 1 0 1 1, 2
// 1 1 0 1, 2
// 1 1 1 1, 2, 3
switch ( nTransition )
{
default : case 0 : return false ;
case 1 : return ( ( ( nZeroField & 0x1 ) ! = 0 ) | | nZeroField > = 5 ) ;
case 2 : return ( nZeroField > = 2 ) ;
case 3 : return ( nZeroField = = 7 ) ;
}
}
template < class T >
void CDmeTypedLog < T > : : PasteAndRescaleSamples (
const CDmeLogLayer * pBase ,
const CDmeLogLayer * pDataLayer ,
CDmeLogLayer * pOutputLayer ,
const DmeLog_TimeSelection_t & srcParams ,
const DmeLog_TimeSelection_t & destParams ,
bool bBlendAreaInFalloffRegion )
{
Assert ( GetNumLayers ( ) > = 2 ) ;
if ( GetNumLayers ( ) < 2 )
return ;
CDmeTypedLogLayer < T > * pClipboard = CastElement < CDmeTypedLogLayer < T > > ( const_cast < CDmeLogLayer * > ( pDataLayer ) ) ;
// Could have passed in layer with wrong attribute type?!
Assert ( pClipboard ) ;
if ( ! pClipboard )
return ;
CDmeTypedLogLayer < T > * pBaseLayer = CastElement < CDmeTypedLogLayer < T > > ( const_cast < CDmeLogLayer * > ( pBase ) ) ;
CDmeTypedLogLayer < T > * pWriteLayer = CastElement < CDmeTypedLogLayer < T > > ( pOutputLayer ) ;
Assert ( pBaseLayer ) ;
Assert ( pWriteLayer ) ;
// NOTE: Array index 0 is src (pClipboard), index 1 is dest (pWriteLayer)
DmeTime_t tStartTime [ PASTE_STATE_COUNT + 1 ] [ 2 ] =
{
{ DmeTime_t ( srcParams . m_nTimes [ 0 ] ) , DmeTime_t ( destParams . m_nTimes [ 0 ] ) } ,
{ DmeTime_t ( srcParams . m_nTimes [ 1 ] ) , DmeTime_t ( destParams . m_nTimes [ 1 ] ) } ,
{ DmeTime_t ( srcParams . m_nTimes [ 2 ] ) , DmeTime_t ( destParams . m_nTimes [ 2 ] ) } ,
{ DmeTime_t ( srcParams . m_nTimes [ 3 ] ) , DmeTime_t ( destParams . m_nTimes [ 3 ] ) } ,
} ;
// compute rescaling factors
int pDuration [ PASTE_STATE_COUNT ] [ 2 ] ;
double pScaleFactor [ PASTE_STATE_COUNT ] ;
int nZeroField = 0 ;
for ( int i = 0 ; i < PASTE_STATE_COUNT ; + + i )
{
for ( int s = 0 ; s < 2 ; + + s )
{
pDuration [ i ] [ s ] = tStartTime [ i + 1 ] [ s ] . GetTenthsOfMS ( ) - tStartTime [ i ] [ s ] . GetTenthsOfMS ( ) ;
}
// We're building up a bitfield to find which regions have src + dest durations of 0
// for use in determining which regions to completely skip processing
if ( pDuration [ i ] [ 0 ] = = 0 & & pDuration [ i ] [ 1 ] = = 0 )
{
nZeroField | = ( 1 < < i ) ;
}
pScaleFactor [ i ] = 1.0 ;
if ( pDuration [ i ] [ 0 ] > 0 )
{
pScaleFactor [ i ] = 1.0 / ( double ) pDuration [ i ] [ 0 ] ;
}
}
// Compute values used to paste into selection state transitions
T pStartValue [ PASTE_STATE_COUNT + 1 ] =
{
bBlendAreaInFalloffRegion ? pBaseLayer - > GetValue ( tStartTime [ PASTE_STATE_RAMP_IN ] [ 1 ] ) : pClipboard - > GetValue ( tStartTime [ PASTE_STATE_RAMP_IN ] [ 0 ] ) ,
pClipboard - > GetValue ( tStartTime [ PASTE_STATE_HOLD ] [ 0 ] ) ,
pClipboard - > GetValue ( tStartTime [ PASTE_STATE_RAMP_OUT ] [ 0 ] ) ,
bBlendAreaInFalloffRegion ? pBaseLayer - > GetValue ( tStartTime [ PASTE_STATE_AFTER ] [ 1 ] ) : pClipboard - > GetValue ( tStartTime [ PASTE_STATE_AFTER ] [ 0 ] )
} ;
// Compute state necessary to blend in the ramp in + ramp out regions
// NOTE: These computations are only used if bBlendAreaInFalloffRegion is true
T pBlendBase [ 2 ] ;
float pOOBlendLength [ 2 ] ;
DmeTime_t pBlendTime [ 2 ] ;
for ( int s = 0 ; s < 2 ; + + s )
{
pBlendTime [ s ] = destParams . m_nTimes [ TS_FALLOFF ( s ) ] ;
pBlendBase [ s ] = pBaseLayer - > GetValue ( pBlendTime [ s ] ) ;
T holdValue = pBaseLayer - > GetValue ( destParams . m_nTimes [ TS_HOLD ( s ) ] ) ;
Vector2D vec ;
vec . x = destParams . m_nTimes [ TS_HOLD ( s ) ] . GetSeconds ( ) - pBlendTime [ s ] . GetSeconds ( ) ;
vec . y = LengthOf ( Subtract ( holdValue , pBlendBase [ s ] ) ) ;
pOOBlendLength [ s ] = vec . Length ( ) ;
if ( pOOBlendLength [ s ] ! = 0.0f )
{
pOOBlendLength [ s ] = 1.0f / pOOBlendLength [ s ] ;
}
}
// Count the number of samples on the clipboard in the various regions
int pKeyCount [ PASTE_STATE_COUNT ] ;
CountClipboardSamples ( pKeyCount , pClipboard , srcParams ) ;
// Walk the samples in the clipboard
int nKeyCount = pClipboard - > GetKeyCount ( ) ;
int nPrevState = PASTE_STATE_BEFORE ;
DmeTime_t tLastWrittenTime = DMETIME_MINTIME ;
DmeTime_t tMaxKeyTime = DMETIME_MAXTIME ;
bool bCollapseSamples = false ;
for ( int j = 0 ; j < nKeyCount ; + + j )
{
DmeTime_t tKeyTime = pClipboard - > GetKeyTime ( j ) ;
T val = pClipboard - > GetKeyValue ( j ) ;
// Determine which state we're in
// NOTE: Don't use ComputeRegionForTime here because it includes
// the endpoint of the hold region into the hold region.
int nState ;
for ( nState = nPrevState ; nState < PASTE_STATE_COUNT ; + + nState )
{
if ( tKeyTime < tStartTime [ nState + 1 ] [ 0 ] )
break ;
}
// This logic inserts a key if there is no sample in the clipboard at the transition time
bool bForceKey = false ;
if ( nPrevState < nState )
{
nState = + + nPrevState ;
// This logic will prevent samples at the hold start + end if
// the source + dest regions are 0 width and will only do the first and last
// if we're squeezing the entire time selection down to a single point.
bForceKey = true ;
if ( nState ! = PASTE_STATE_AFTER )
{
bCollapseSamples = ( pKeyCount [ nState ] > = pDuration [ nState ] [ 1 ] ) ;
tMaxKeyTime = bCollapseSamples ? tStartTime [ nState ] [ 1 ] : ( tStartTime [ nState + 1 ] [ 1 ] - DmeTime_t ( pKeyCount [ nState ] + 1 ) ) ;
}
else
{
bCollapseSamples = false ;
tMaxKeyTime = DMETIME_MAXTIME ;
}
// NOTE: This has to occur after collapse samples + max key time has been set
if ( ShouldSkipTransition ( nState , nZeroField ) )
{
- - j ;
continue ;
}
// Don't insert an extra key if the current one we're looking at is right at that point
if ( tKeyTime ! = tStartTime [ nPrevState ] [ 0 ] )
{
tKeyTime = tStartTime [ nPrevState ] [ 0 ] ;
val = pStartValue [ nPrevState ] ;
// We want to re-do this key, since we inserted a key beforehand
- - j ;
}
}
if ( nState = = PASTE_STATE_BEFORE )
continue ;
if ( nState = = PASTE_STATE_AFTER & & ! bForceKey )
return ;
// Compute destination time based on scale + offset
double flFactor = ( tKeyTime - tStartTime [ nState ] [ 0 ] ) . GetTenthsOfMS ( ) * pScaleFactor [ nState ] ;
// FIXME: Fix the algorithm, then uncomment to get time-scaled falloff regions
// if ( nState == PASTE_STATE_RAMP_IN || nState == PASTE_STATE_RAMP_OUT )
// {
// int s = ( nState == PASTE_STATE_RAMP_IN ) ? 0 : 1;
// flFactor = ComputeInterpolationFactor( flFactor, destParams.m_nFalloffInterpolatorTypes[s] );
// }
double flTempTime = flFactor * pDuration [ nState ] [ 1 ] ;
DmeTime_t tDestTime ( ( int ) ( flTempTime + 0.5 ) ) ;
tDestTime + = tStartTime [ nState ] [ 1 ] ;
// Clamp necessary to not lose samples
// NOTE: The !bForceKey check here makes it so we don't clamp points
// in time corresponding to transitions of the time selection
if ( ! bForceKey & & ( tDestTime > tMaxKeyTime ) )
{
tDestTime = tMaxKeyTime ;
}
if ( tMaxKeyTime ! = DMETIME_MAXTIME )
{
tMaxKeyTime + = DMETIME_MINDELTA ;
}
// This logic will cause *all* samples to appear if we have enough room for them
if ( ! bCollapseSamples )
{
bForceKey = true ;
}
// If we'd go outside our region and we're not forcing the key, then skip
if ( ! bForceKey & & tDestTime > = tStartTime [ nState + 1 ] [ 1 ] )
continue ;
// Perform blending on ramp in + ramp out regions
if ( bBlendAreaInFalloffRegion & & ( nState ! = PASTE_STATE_HOLD ) )
{
int nBlendIndex = ( nState < PASTE_STATE_HOLD ) ? 0 : 1 ;
T baseValue = pBaseLayer - > GetValue ( tDestTime ) ;
Vector2D oldDist ;
oldDist . x = tDestTime . GetSeconds ( ) - pBlendTime [ nBlendIndex ] . GetSeconds ( ) ;
oldDist . y = LengthOf ( Subtract ( baseValue , pBlendBase [ nBlendIndex ] ) ) ;
float flDistance = oldDist . Length ( ) ;
float flFactorBlend = flDistance * pOOBlendLength [ nBlendIndex ] ;
flFactorBlend = destParams . AdjustFactorForInterpolatorType ( flFactorBlend , nBlendIndex ) ;
val = Interpolate ( flFactorBlend , baseValue , val ) ;
}
// Force key insertion when we transition between states
if ( bForceKey & & ( tLastWrittenTime > = tDestTime ) )
{
tDestTime = tLastWrittenTime + DMETIME_MINDELTA ;
}
// Insert the key into the log
if ( tLastWrittenTime < tDestTime )
{
pWriteLayer - > InsertKey ( tDestTime , val ) ;
tLastWrittenTime = tDestTime ;
}
}
}
template < class T >
void CDmeTypedLog < T > : : PasteAndRescaleSamples (
const CDmeLogLayer * src , // clipboard data
const DmeLog_TimeSelection_t & srcParams , // clipboard time selection
const DmeLog_TimeSelection_t & destParams , // current time selection
bool bBlendAreaInFalloffRegion ) // blending behavior in falloff area of current time selection
{
CDmeLogLayer * pBaseLayer = GetLayer ( 0 ) ;
CDmeLogLayer * pWriteLayer = GetLayer ( GetTopmostLayer ( ) ) ;
PasteAndRescaleSamples ( pBaseLayer , src , pWriteLayer , srcParams , destParams , bBlendAreaInFalloffRegion ) ;
}
template < >
void CDmeTypedLog < Vector > : : BuildNormalizedLayer ( CDmeTypedLogLayer < float > * target )
{
Assert ( target ) ;
Assert ( GetDataType ( ) ! = AT_FLOAT ) ;
CDmeTypedLogLayer < Vector > * baseLayer = static_cast < CDmeTypedLogLayer < Vector > * > ( GetLayer ( 0 ) ) ;
if ( ! baseLayer )
return ;
float flMin = FLT_MAX ;
float flMax = FLT_MIN ;
int kc = baseLayer - > GetKeyCount ( ) ;
for ( int i = 0 ; i < kc ; + + i )
{
DmeTime_t keyTime = baseLayer - > GetKeyTime ( i ) ;
Vector keyValue = baseLayer - > GetKeyValue ( i ) ;
float len = keyValue . Length ( ) ;
if ( len < flMin )
{
flMin = len ;
}
if ( len > flMax )
{
flMax = len ;
}
target - > InsertKey ( keyTime , len ) ;
}
for ( int i = 0 ; i < kc ; + + i )
{
float keyValue = target - > GetKeyValue ( i ) ;
float normalized = RemapVal ( keyValue , flMin , flMax , 0.0f , 1.0f ) ;
target - > SetKeyValue ( i , normalized ) ;
}
if ( HasDefaultValue ( ) )
{
target - > GetTypedOwnerLog ( ) - > SetDefaultValue ( RemapVal ( GetDefaultValue ( ) . Length ( ) , flMin , flMax , 0.0f , 1.0f ) ) ;
}
}
template < >
void CDmeTypedLog < Vector2D > : : BuildNormalizedLayer ( CDmeTypedLogLayer < float > * target )
{
Assert ( target ) ;
Assert ( GetDataType ( ) ! = AT_FLOAT ) ;
CDmeTypedLogLayer < Vector2D > * baseLayer = static_cast < CDmeTypedLogLayer < Vector2D > * > ( GetLayer ( 0 ) ) ;
if ( ! baseLayer )
return ;
float flMin = FLT_MAX ;
float flMax = FLT_MIN ;
int kc = baseLayer - > GetKeyCount ( ) ;
for ( int i = 0 ; i < kc ; + + i )
{
DmeTime_t keyTime = baseLayer - > GetKeyTime ( i ) ;
Vector2D keyValue = baseLayer - > GetKeyValue ( i ) ;
float len = keyValue . Length ( ) ;
if ( len < flMin )
{
flMin = len ;
}
if ( len > flMax )
{
flMax = len ;
}
target - > InsertKey ( keyTime , len ) ;
}
for ( int i = 0 ; i < kc ; + + i )
{
float keyValue = target - > GetKeyValue ( i ) ;
float normalized = RemapVal ( keyValue , flMin , flMax , 0.0f , 1.0f ) ;
target - > SetKeyValue ( i , normalized ) ;
}
if ( HasDefaultValue ( ) )
{
target - > GetTypedOwnerLog ( ) - > SetDefaultValue ( RemapVal ( GetDefaultValue ( ) . Length ( ) , flMin , flMax , 0.0f , 1.0f ) ) ;
}
}
template < >
void CDmeTypedLog < Vector4D > : : BuildNormalizedLayer ( CDmeTypedLogLayer < float > * target )
{
Assert ( target ) ;
Assert ( GetDataType ( ) ! = AT_FLOAT ) ;
CDmeTypedLogLayer < Vector4D > * baseLayer = static_cast < CDmeTypedLogLayer < Vector4D > * > ( GetLayer ( 0 ) ) ;
if ( ! baseLayer )
return ;
float flMin = FLT_MAX ;
float flMax = FLT_MIN ;
int kc = baseLayer - > GetKeyCount ( ) ;
for ( int i = 0 ; i < kc ; + + i )
{
DmeTime_t keyTime = baseLayer - > GetKeyTime ( i ) ;
Vector4D keyValue = baseLayer - > GetKeyValue ( i ) ;
float len = keyValue . Length ( ) ;
if ( len < flMin )
{
flMin = len ;
}
if ( len > flMax )
{
flMax = len ;
}
target - > InsertKey ( keyTime , len ) ;
}
for ( int i = 0 ; i < kc ; + + i )
{
float keyValue = target - > GetKeyValue ( i ) ;
float normalized = RemapVal ( keyValue , flMin , flMax , 0.0f , 1.0f ) ;
target - > SetKeyValue ( i , normalized ) ;
}
if ( HasDefaultValue ( ) )
{
target - > GetTypedOwnerLog ( ) - > SetDefaultValue ( RemapVal ( GetDefaultValue ( ) . Length ( ) , flMin , flMax , 0.0f , 1.0f ) ) ;
}
}
template < >
void CDmeTypedLog < int > : : BuildNormalizedLayer ( CDmeTypedLogLayer < float > * target )
{
Assert ( target ) ;
Assert ( GetDataType ( ) ! = AT_FLOAT ) ;
CDmeTypedLogLayer < int > * baseLayer = static_cast < CDmeTypedLogLayer < int > * > ( GetLayer ( 0 ) ) ;
if ( ! baseLayer )
return ;
float flMin = FLT_MAX ;
float flMax = FLT_MIN ;
int kc = baseLayer - > GetKeyCount ( ) ;
for ( int i = 0 ; i < kc ; + + i )
{
DmeTime_t keyTime = baseLayer - > GetKeyTime ( i ) ;
int keyValue = baseLayer - > GetKeyValue ( i ) ;
float len = ( float ) keyValue ;
if ( len < flMin )
{
flMin = len ;
}
if ( len > flMax )
{
flMax = len ;
}
target - > InsertKey ( keyTime , len ) ;
}
for ( int i = 0 ; i < kc ; + + i )
{
float keyValue = target - > GetKeyValue ( i ) ;
float normalized = RemapVal ( keyValue , flMin , flMax , 0.0f , 1.0f ) ;
target - > SetKeyValue ( i , normalized ) ;
}
if ( HasDefaultValue ( ) )
{
target - > GetTypedOwnerLog ( ) - > SetDefaultValue ( RemapVal ( GetDefaultValue ( ) , flMin , flMax , 0.0f , 1.0f ) ) ;
}
}
template < >
void CDmeTypedLog < float > : : BuildNormalizedLayer ( CDmeTypedLogLayer < float > * target )
{
Assert ( target ) ;
Assert ( GetDataType ( ) ! = AT_FLOAT ) ;
CDmeTypedLogLayer < float > * baseLayer = static_cast < CDmeTypedLogLayer < float > * > ( GetLayer ( 0 ) ) ;
if ( ! baseLayer )
return ;
float flMin = FLT_MAX ;
float flMax = FLT_MIN ;
int kc = baseLayer - > GetKeyCount ( ) ;
for ( int i = 0 ; i < kc ; + + i )
{
DmeTime_t keyTime = baseLayer - > GetKeyTime ( i ) ;
int keyValue = baseLayer - > GetKeyValue ( i ) ;
float len = ( float ) keyValue ;
if ( len < flMin )
{
flMin = len ;
}
if ( len > flMax )
{
flMax = len ;
}
target - > InsertKey ( keyTime , len ) ;
}
for ( int i = 0 ; i < kc ; + + i )
{
float keyValue = target - > GetKeyValue ( i ) ;
float normalized = RemapVal ( keyValue , flMin , flMax , 0.0f , 1.0f ) ;
target - > SetKeyValue ( i , normalized ) ;
}
if ( HasDefaultValue ( ) )
{
target - > GetTypedOwnerLog ( ) - > SetDefaultValue ( RemapVal ( GetDefaultValue ( ) , flMin , flMax , 0.0f , 1.0f ) ) ;
}
}
//-----------------------------------------------------------------------------
// Creates a log of a specific type
//-----------------------------------------------------------------------------
CDmeLog * CDmeLog : : CreateLog ( DmAttributeType_t type , DmFileId_t fileid )
{
switch ( type )
{
case AT_INT :
case AT_INT_ARRAY :
return CreateElement < CDmeIntLog > ( " int log " , fileid ) ;
case AT_FLOAT :
case AT_FLOAT_ARRAY :
return CreateElement < CDmeFloatLog > ( " float log " , fileid ) ;
case AT_BOOL :
case AT_BOOL_ARRAY :
return CreateElement < CDmeBoolLog > ( " bool log " , fileid ) ;
case AT_COLOR :
case AT_COLOR_ARRAY :
return CreateElement < CDmeColorLog > ( " color log " , fileid ) ;
case AT_VECTOR2 :
case AT_VECTOR2_ARRAY :
return CreateElement < CDmeVector2Log > ( " vector2 log " , fileid ) ;
case AT_VECTOR3 :
case AT_VECTOR3_ARRAY :
return CreateElement < CDmeVector3Log > ( " vector3 log " , fileid ) ;
case AT_VECTOR4 :
case AT_VECTOR4_ARRAY :
return CreateElement < CDmeVector4Log > ( " vector4 log " , fileid ) ;
case AT_QANGLE :
case AT_QANGLE_ARRAY :
return CreateElement < CDmeQAngleLog > ( " qangle log " , fileid ) ;
case AT_QUATERNION :
case AT_QUATERNION_ARRAY :
return CreateElement < CDmeQuaternionLog > ( " quaternion log " , fileid ) ;
case AT_VMATRIX :
case AT_VMATRIX_ARRAY :
return CreateElement < CDmeVMatrixLog > ( " vmatrix log " , fileid ) ;
case AT_STRING :
case AT_STRING_ARRAY :
return CreateElement < CDmeStringLog > ( " string log " , fileid ) ;
}
return NULL ;
}
// Disallowed methods for types
//template<> void CDmeTypedLog< bool >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const bool& value ) { Assert( 0 ); }
//template<> void CDmeTypedLog< bool >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const bool& value ) { Assert( 0 ); }
//template<> void CDmeTypedLog< bool >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ ) { Assert( 0 ); }
//template<> void CDmeTypedLog< bool >::FinishTimeSelection( DmeLog_TimeSelection_t& params ) { Assert( 0 ); }
//
//template<> void CDmeTypedLog< Color >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const Color& value ) { Assert( 0 ); }
//template<> void CDmeTypedLog< Color >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const Color& value ) { Assert( 0 ); }
//template<> void CDmeTypedLog< Color >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ ) { Assert( 0 ); }
//template<> void CDmeTypedLog< Color >::FinishTimeSelection( DmeLog_TimeSelection_t& params ) { Assert( 0 ); }
//
//template<> void CDmeTypedLog< Vector4D >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const Vector4D& value ) { Assert( 0 ); }
//template<> void CDmeTypedLog< Vector4D >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const Vector4D& value ) { Assert( 0 ); }
//template<> void CDmeTypedLog< Vector4D >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ ) { Assert( 0 ); }
//template<> void CDmeTypedLog< Vector4D >::FinishTimeSelection( DmeLog_TimeSelection_t& params ) { Assert( 0 ); }
//
//template<> void CDmeTypedLog< Vector2D >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const Vector2D& value ) { Assert( 0 ); }
//template<> void CDmeTypedLog< Vector2D >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const Vector2D& value ) { Assert( 0 ); }
//template<> void CDmeTypedLog< Vector2D >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ ) { Assert( 0 ); }
//template<> void CDmeTypedLog< Vector2D >::FinishTimeSelection( DmeLog_TimeSelection_t& params ) { Assert( 0 ); }
//template<> void CDmeTypedLog< Vector >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const Vector& value ) { Assert( 0 ); }
//template<> void CDmeTypedLog< Vector >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const Vector& value ) { Assert( 0 ); }
//template<> void CDmeTypedLog< Vector >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ ) { Assert( 0 ); }
//template<> void CDmeTypedLog< Vector >::FinishTimeSelection( DmeLog_TimeSelection_t& params ) { Assert( 0 ); }
//template<> void CDmeTypedLog< VMatrix >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const VMatrix& value ) { Assert( 0 ); }
//template<> void CDmeTypedLog< VMatrix >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const VMatrix& value ) { Assert( 0 ); }
//template<> void CDmeTypedLog< VMatrix >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ ) { Assert( 0 ); }
//template<> void CDmeTypedLog< VMatrix >::FinishTimeSelection( DmeLog_TimeSelection_t& params ) { Assert( 0 ); }
//
//template<> void CDmeTypedLog< Quaternion >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const Quaternion& value ) { Assert( 0 ); }
//template<> void CDmeTypedLog< Quaternion >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const Quaternion& value ) { Assert( 0 ); }
//template<> void CDmeTypedLog< Quaternion >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ ) { Assert( 0 ); }
//template<> void CDmeTypedLog< Quaternion >::FinishTimeSelection( DmeLog_TimeSelection_t& params ) { Assert( 0 ); }
//
//template<> void CDmeTypedLog< QAngle >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const QAngle& value ) { Assert( 0 ); }
//template<> void CDmeTypedLog< QAngle >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const QAngle& value ) { Assert( 0 ); }
//template<> void CDmeTypedLog< QAngle >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ ) { Assert( 0 ); }
//template<> void CDmeTypedLog< QAngle >::FinishTimeSelection( DmeLog_TimeSelection_t& params ) { Assert( 0 ); }
//-----------------------------------------------------------------------------
// Helpers for particular types of log layers
//-----------------------------------------------------------------------------
void GenerateRotationLog ( CDmeQuaternionLogLayer * pLayer , const Vector & vecAxis , DmeTime_t pTime [ 4 ] , float pRevolutionsPerSec [ 4 ] )
{
for ( int i = 1 ; i < 4 ; + + i )
{
if ( pTime [ i ] < pTime [ i - 1 ] )
{
Warning ( " Bogus times passed into GenerateRotationLog \n " ) ;
return ;
}
}
// Gets the initial value
matrix3x4_t initial ;
Quaternion q = pLayer - > GetValue ( pTime [ 0 ] ) ;
QuaternionMatrix ( q , initial ) ;
// Find the max rps, and compute the total rotation in degrees
// by the time we reach the transition points. The total rotation =
// integral from 0 to t of 360 * ( rate[i] - rate[i-1] ) t / tl + rate[i-1] )
// == 360 * ( ( rate[i] - rate[i-1] ) t^2 / 2 + rate[i-1] t )
float pTotalRotation [ 4 ] ;
float flMaxRPS = pRevolutionsPerSec [ 0 ] ;
pTotalRotation [ 0 ] = 0.0f ;
for ( int i = 1 ; i < 4 ; + + i )
{
if ( pRevolutionsPerSec [ i ] > flMaxRPS )
{
flMaxRPS = pRevolutionsPerSec [ i ] ;
}
float dt = pTime [ i ] . GetSeconds ( ) - pTime [ i - 1 ] . GetSeconds ( ) ;
float dRot = pRevolutionsPerSec [ i ] - pRevolutionsPerSec [ i - 1 ] ;
pTotalRotation [ i ] = 360.0f * ( dRot * dt * 0.5 + pRevolutionsPerSec [ i - 1 ] * dt ) + pTotalRotation [ i - 1 ] ;
}
// We need to compute how long a single rotation takes, then create samples
// at 1/4 the frequency of that amount of time
VMatrix rot ;
matrix3x4_t total ;
QAngle angles ;
float flMaxRotationTime = ( flMaxRPS ! = 0.0f ) ? ( 0.125f / flMaxRPS ) : ( pTime [ 3 ] . GetSeconds ( ) - pTime [ 0 ] . GetSeconds ( ) ) ;
DmeTime_t dt ( flMaxRotationTime ) ;
for ( DmeTime_t t = pTime [ 0 ] ; t < = pTime [ 3 ] ; t + = dt )
{
int i = ( t < pTime [ 1 ] ) ? 1 : ( ( t < pTime [ 2 ] ) ? 2 : 3 ) ;
float flInterval = t . GetSeconds ( ) - pTime [ i - 1 ] . GetSeconds ( ) ;
float flOOSegmentDur = pTime [ i ] . GetSeconds ( ) - pTime [ i - 1 ] . GetSeconds ( ) ;
if ( flOOSegmentDur = = 0.0f )
{
Assert ( flInterval = = 0.0f ) ;
flOOSegmentDur = 1.0f ;
}
else
{
flOOSegmentDur = 1.0f / flOOSegmentDur ;
}
float dRot = pRevolutionsPerSec [ i ] - pRevolutionsPerSec [ i - 1 ] ;
float flRotation = 360.0f * ( dRot * flInterval * flInterval * 0.5f * flOOSegmentDur + pRevolutionsPerSec [ i - 1 ] * flInterval ) + pTotalRotation [ i - 1 ] ;
MatrixBuildRotationAboutAxis ( rot , vecAxis , flRotation ) ;
ConcatTransforms ( initial , rot . As3x4 ( ) , total ) ;
MatrixToAngles ( total , angles ) ;
AngleQuaternion ( angles , q ) ;
pLayer - > SetKey ( t , q ) ;
}
}
//-----------------------------------------------------------------------------
// Transforms a position log
//-----------------------------------------------------------------------------
void RotatePositionLog ( CDmeVector3LogLayer * pPositionLog , const matrix3x4_t & matrix )
{
Assert ( fabs ( matrix [ 0 ] [ 3 ] ) < 1e-3 & & fabs ( matrix [ 1 ] [ 3 ] ) < 1e-3 & & fabs ( matrix [ 2 ] [ 3 ] ) < 1e-3 ) ;
Vector position ;
int nCount = pPositionLog - > GetKeyCount ( ) ;
for ( int i = 0 ; i < nCount ; + + i )
{
const Vector & srcPosition = pPositionLog - > GetKeyValue ( i ) ;
VectorTransform ( srcPosition , matrix , position ) ;
pPositionLog - > SetKeyValue ( i , position ) ;
}
}
//-----------------------------------------------------------------------------
// Transforms a orientation log
//-----------------------------------------------------------------------------
void RotateOrientationLog ( CDmeQuaternionLogLayer * pOrientationLog , const matrix3x4_t & matrix , bool bPreMultiply = false )
{
Assert ( fabs ( matrix [ 0 ] [ 3 ] ) < 1e-3 & & fabs ( matrix [ 1 ] [ 3 ] ) < 1e-3 & & fabs ( matrix [ 2 ] [ 3 ] ) < 1e-3 ) ;
matrix3x4_t orientation , newOrientation ;
Quaternion q ;
int nCount = pOrientationLog - > GetKeyCount ( ) ;
for ( int i = 0 ; i < nCount ; + + i )
{
const Quaternion & srcQuat = pOrientationLog - > GetKeyValue ( i ) ;
QuaternionMatrix ( srcQuat , orientation ) ;
if ( bPreMultiply )
{
ConcatTransforms ( matrix , orientation , newOrientation ) ;
}
else
{
ConcatTransforms ( orientation , matrix , newOrientation ) ;
}
MatrixQuaternion ( newOrientation , q ) ;
pOrientationLog - > SetKeyValue ( i , q ) ;
}
}