|
|
//============ Copyright (c) Valve Corporation, All rights reserved. ==========
//
//=============================================================================
#include "datamodel/dmelementfactoryhelper.h"
#include "movieobjects/dmechannel.h"
#include "movieobjects/dmelog.h"
#include "movieobjects/dmemesh.h"
#include "movieobjects/dmemodel.h"
#include "movieobjects/dmevertexdata.h"
#include "tier1/fmtstr.h"
#include "movieobjects/dmeaxissystem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY( DmeAxisSystem, CDmeAxisSystem );
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static CDmeAxisSystem::Axis_t GetAbsAxisAndSign( int &nSign, const CDmeAxisSystem::Axis_t eAxis ) { nSign = ( eAxis < 0 ) ? -1 : 1; return static_cast< CDmeAxisSystem::Axis_t >( abs( eAxis ) ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static CDmeAxisSystem::ForwardParity_t GetAbsForwardParityAndSign( int &nSign, const CDmeAxisSystem::ForwardParity_t eForwardParity ) { nSign = ( eForwardParity < 0 ) ? -1 : 1; return static_cast< CDmeAxisSystem::ForwardParity_t >( abs( eForwardParity ) ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static CDmeAxisSystem::Axis_t ComputeAbsForwardAxisAndSign( int &nSign, const CDmeAxisSystem::Axis_t eUpAxis, const CDmeAxisSystem::ForwardParity_t eForwardParity ) { Assert( CDmeAxisSystem::IsValid( eUpAxis, eForwardParity ) );
int nUpAxisSign = 0; const CDmeAxisSystem::Axis_t eAbsUpAxis = GetAbsAxisAndSign( nUpAxisSign, eUpAxis ); AssertDbg( eAbsUpAxis >= CDmeAxisSystem::AS_AXIS_X && eAbsUpAxis <= CDmeAxisSystem::AS_AXIS_Z );
const CDmeAxisSystem::ForwardParity_t eAbsForwardParity = GetAbsForwardParityAndSign( nSign, eForwardParity ); AssertDbg( eAbsForwardParity >= CDmeAxisSystem::AS_PARITY_EVEN && eAbsForwardParity <= CDmeAxisSystem::AS_PARITY_ODD );
// eAxisParityMap[Axis_t - 1][ ForwardParityType_t - 1 ] gives parity axis
static const CDmeAxisSystem::Axis_t eAxisParityMap[][2] = { { CDmeAxisSystem::AS_AXIS_Y, CDmeAxisSystem::AS_AXIS_Z }, // Up X
{ CDmeAxisSystem::AS_AXIS_X, CDmeAxisSystem::AS_AXIS_Z }, // Up Y
{ CDmeAxisSystem::AS_AXIS_X, CDmeAxisSystem::AS_AXIS_Y } // Up Z
};
const CDmeAxisSystem::Axis_t nAbsForwardAxis = eAxisParityMap[ eAbsUpAxis - 1 ][ eAbsForwardParity - 1 ]; AssertDbg( nAbsForwardAxis != eAbsUpAxis );
return nAbsForwardAxis; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static CDmeAxisSystem::Axis_t ComputeAbsLeftAxisAndSign( int &nSign, const CDmeAxisSystem::Axis_t eUpAxis, const CDmeAxisSystem::ForwardParity_t eForwardParity, const CDmeAxisSystem::CoordSys_t eCoordSys ) { Assert( CDmeAxisSystem::IsValid( eUpAxis, eForwardParity, eCoordSys ) );
int nUpAxisSign = 0; const CDmeAxisSystem::Axis_t eAbsUpAxis = GetAbsAxisAndSign( nUpAxisSign, eUpAxis ); AssertDbg( nUpAxisSign == -1 || nUpAxisSign == 1 ); AssertDbg( eAbsUpAxis >= CDmeAxisSystem::AS_AXIS_X && eAbsUpAxis <= CDmeAxisSystem::AS_AXIS_Z );
int nForwardAxisSign = 0; const CDmeAxisSystem::Axis_t eAbsForwardAxis = ComputeAbsForwardAxisAndSign( nForwardAxisSign, eUpAxis, eForwardParity ); AssertDbg( eAbsForwardAxis >= CDmeAxisSystem::AS_AXIS_X && eAbsForwardAxis <= CDmeAxisSystem::AS_AXIS_Z ); AssertDbg( nForwardAxisSign == -1 || nForwardAxisSign == 1 );
AssertDbg( eAbsForwardAxis != eAbsUpAxis );
// Chart of cross products, COL x ROW, 24 possibilities as parallel vectors are not allowed
// NOTE: The 3x3 matrices are the same across both diagonals and the two sets of 3x3's are
// simply the negative image of each other
//
// +=====+=====+=====+=====+=====+=====+
// | -X | -Y | -Z | X | Y | Z |
// +=====+=====+=====+=====+=====+=====+
//
// +=====+ +-----+-----+-----+-----+-----+-----+
// | -X | | . | Z | -Y | . | -Z | Y |
// +-----+ +-----+-----+-----+-----+-----+-----+
// | -Y | | -Z | . | X | Z | . | -X |
// +-----+ +-----+-----+-----+-----+-----+-----+
// | -Z | | Y | -X | . | -Y | X | . |
// +-----+ +-----+-----+-----+-----+-----+-----+
// | X | | . | -Z | Y | . | Z | -Y |
// +-----+ +-----+-----+-----+-----+-----+-----+
// | Y | | Z | . | -X | -Z | . | X |
// +-----+ +-----+-----+-----+-----+-----+-----+
// | Z | | -Y | X | . | Y | -X | . |
// +=====+ +-----+-----+-----+-----+-----+-----+
// The 3x3 matrix from the above table without sign, sign is broken down in next table
// 0's are invalid cases, index [up - 1][forward - 1]
static const CDmeAxisSystem::Axis_t eAxisUpForwardMap[3][3] = { { (CDmeAxisSystem::Axis_t)0, CDmeAxisSystem::AS_AXIS_Z, CDmeAxisSystem::AS_AXIS_Y }, { CDmeAxisSystem::AS_AXIS_Z, (CDmeAxisSystem::Axis_t)0, CDmeAxisSystem::AS_AXIS_X }, { CDmeAxisSystem::AS_AXIS_Y, CDmeAxisSystem::AS_AXIS_X, (CDmeAxisSystem::Axis_t)0 } };
// The signs from the lower right 3x3 case (positive axis x positive axis)
// 0's are invalid cases, index [up - 1][forward - 1]
static const int nSignUpForwardMap[3][3] = { { 0, 1, -1 }, { -1, 0, 1 }, { 1, -1, 0 } };
const CDmeAxisSystem::Axis_t eAbsLeftAxis = eAxisUpForwardMap[ eAbsUpAxis - 1 ][ eAbsForwardAxis - 1 ]; AssertDbg( eAbsLeftAxis >= CDmeAxisSystem::AS_AXIS_X && eAbsLeftAxis <= CDmeAxisSystem::AS_AXIS_Z ); AssertDbg( eAbsLeftAxis != eAbsUpAxis ); AssertDbg( eAbsLeftAxis != eAbsForwardAxis );
nSign = nSignUpForwardMap[ eAbsUpAxis - 1 ][ eAbsForwardAxis - 1 ];
// If up and forward are not the same sign, then sign is reversed from table
if ( nUpAxisSign != nForwardAxisSign ) { nSign = -nSign; }
// If left handed, reverse sign of axis
if ( eCoordSys == CDmeAxisSystem::AS_LEFT_HANDED ) { nSign = -nSign; }
return eAbsLeftAxis; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeAxisSystem::OnConstruction() { // Initialize to Maya Y Up
m_nUpAxis.InitAndSet( this, "upAxis", AS_AXIS_Y ); m_nForwardParity.InitAndSet( this, "forwardParity", AS_PARITY_ODD ); m_nCoordSys.InitAndSet( this, "coordSys", AS_RIGHT_HANDED );
Assert( IsValid() ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeAxisSystem::OnDestruction() { }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CDmeAxisSystem::Init( Axis_t eUpAxis, ForwardParity_t eForwardParity, CoordSys_t eCoordSys /*= AS_RIGHT_HANDED */ ) { if ( !IsValid( eUpAxis, eForwardParity, eCoordSys ) ) { AssertMsg( false, "Invalid Initialization of CDmeAxisSystem" ); return false; }
m_nUpAxis = eUpAxis; m_nForwardParity = eForwardParity; m_nCoordSys = eCoordSys;
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CDmeAxisSystem::Init( PredefinedAxisSystem ePredefinedAxisSystem ) { Axis_t eUpAxis = static_cast< Axis_t >( m_nUpAxis.Get() ); ForwardParity_t eForwardParity = static_cast< ForwardParity_t >( m_nForwardParity.Get() ); CoordSys_t eCoordSys = static_cast< CoordSys_t >( m_nCoordSys.Get() );
if ( !GetPredefinedAxisSystem( eUpAxis, eForwardParity, eCoordSys, ePredefinedAxisSystem ) ) return false;
return Init( eUpAxis, eForwardParity, eCoordSys ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CDmeAxisSystem::IsValid() const { return IsValid( static_cast< Axis_t >( m_nUpAxis.Get() ), static_cast< ForwardParity_t >( m_nForwardParity.Get() ), static_cast< CoordSys_t >( m_nCoordSys.Get() ) ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CDmeAxisSystem::IsValid( Axis_t nUpAxis, ForwardParity_t eForwardParity, CoordSys_t eCoordSys ) { if ( nUpAxis == 0 || nUpAxis < AS_AXIS_NZ || nUpAxis > AS_AXIS_Z ) return false;
if ( eForwardParity == 0 || eForwardParity < AS_PARITY_NODD || eForwardParity > AS_PARITY_ODD ) return false;
if ( eCoordSys < AS_RIGHT_HANDED || eCoordSys > AS_LEFT_HANDED ) return false;
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CDmeAxisSystem::GetPredefinedAxisSystem( Axis_t &eUpAxis, ForwardParity_t &eForwardParity, CoordSys_t &eCoordSys, PredefinedAxisSystem ePredefinedAxisSystem ) { if ( ePredefinedAxisSystem < AS_VALVE_ENGINE || ePredefinedAxisSystem > AS_3DSMAX ) return false;
static int predefinedAxisSystemList[][3] = { { AS_AXIS_Z, AS_PARITY_EVEN, AS_RIGHT_HANDED }, // AS_VALVE_ENGINE +Z, +X
{ AS_AXIS_Z, -AS_PARITY_ODD, AS_RIGHT_HANDED }, // AS_SMD +Z, -Y
{ AS_AXIS_Y, AS_PARITY_ODD, AS_RIGHT_HANDED }, // AS_MAYA_YUP +Y, +Z
{ AS_AXIS_Z, -AS_PARITY_ODD, AS_RIGHT_HANDED }, // AS_MAYA_ZUP +Z, -Y
{ AS_AXIS_Y, AS_PARITY_ODD, AS_RIGHT_HANDED }, // AS_MODO +Y, +Z
{ AS_AXIS_Z, -AS_PARITY_ODD, AS_RIGHT_HANDED } // AS_3DSMAX +Z, -Y
};
COMPILE_TIME_ASSERT( AS_VALVE_ENGINE == 0 ); COMPILE_TIME_ASSERT( AS_SMD == 1 ); COMPILE_TIME_ASSERT( AS_MAYA_YUP == 2 ); COMPILE_TIME_ASSERT( AS_MAYA_ZUP == 3 ); COMPILE_TIME_ASSERT( AS_MODO_YUP == 4 ); COMPILE_TIME_ASSERT( AS_3DSMAX == 5 ); COMPILE_TIME_ASSERT( AS_3DSMAX + 1 == ARRAYSIZE( predefinedAxisSystemList ) );
eUpAxis = static_cast< Axis_t >( predefinedAxisSystemList[ePredefinedAxisSystem][0] ); eForwardParity = static_cast< ForwardParity_t >( predefinedAxisSystemList[ePredefinedAxisSystem][1] ); eCoordSys = static_cast< CoordSys_t >( predefinedAxisSystemList[ePredefinedAxisSystem][2] );
Assert( IsValid( eUpAxis, eForwardParity, eCoordSys ) );
return true; }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CDmeAxisSystem::IsEqual( PredefinedAxisSystem ePredefinedAxisSystem ) const { Axis_t eAUpAxis; ForwardParity_t eAForwardParity; CoordSys_t eACoordSys;
if ( !GetPredefinedAxisSystem( eAUpAxis, eAForwardParity, eACoordSys, ePredefinedAxisSystem ) ) return false;
const Axis_t eBUpAxis = GetUpAxis(); const ForwardParity_t eBForwardParity = GetForwardParity(); const CoordSys_t eBCoordSys = GetCoordSys();
return ( eBUpAxis == eAUpAxis ) && ( eBForwardParity == eAForwardParity ) && ( eBCoordSys == eACoordSys );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeAxisSystem::Axis_t CDmeAxisSystem::GetUpAxis() const { return static_cast< Axis_t >( m_nUpAxis.Get() ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeAxisSystem::ForwardParity_t CDmeAxisSystem::GetForwardParity() const { return static_cast< ForwardParity_t >( m_nForwardParity.Get() ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeAxisSystem::CoordSys_t CDmeAxisSystem::GetCoordSys() const { return static_cast< CoordSys_t >( m_nCoordSys.Get() ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeAxisSystem::ComputeMatrix( matrix3x4a_t &mMatrix, const PredefinedAxisSystem ePredefinedAxisSystem ) { Axis_t eUpAxis; ForwardParity_t eForwardParity; CoordSys_t eCoordSys;
GetPredefinedAxisSystem( eUpAxis, eForwardParity, eCoordSys, ePredefinedAxisSystem ); ComputeMatrix( mMatrix, eUpAxis, eForwardParity, eCoordSys ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeAxisSystem::GetConversionMatrix( matrix3x4a_t &mMat, PredefinedAxisSystem eFromAxisSystem, PredefinedAxisSystem eToAxisSystem ) { Axis_t eFromUpAxis; ForwardParity_t eFromForwardParity; CoordSys_t eFromCoordSys;
GetPredefinedAxisSystem( eFromUpAxis, eFromForwardParity, eFromCoordSys, eFromAxisSystem ); Assert( IsValid( eFromUpAxis, eFromForwardParity, eFromCoordSys ) );
Axis_t eToUpAxis; ForwardParity_t eToForwardParity; CoordSys_t eToCoordSys;
GetPredefinedAxisSystem( eToUpAxis, eToForwardParity, eToCoordSys, eToAxisSystem ); Assert( IsValid( eToUpAxis, eToForwardParity, eToCoordSys ) );
GetConversionMatrix( mMat, eFromUpAxis, eFromForwardParity, eFromCoordSys, eToUpAxis, eToForwardParity, eToCoordSys ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeAxisSystem::GetConversionMatrix( matrix3x4a_t &mMat, Axis_t eFromUpAxis, ForwardParity_t eFromForwardParity, Axis_t eToUpAxis, ForwardParity_t eToForwardParity ) { GetConversionMatrix( mMat, eFromUpAxis, eFromForwardParity, AS_RIGHT_HANDED, eToUpAxis, eToForwardParity, AS_RIGHT_HANDED ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeAxisSystem::GetConversionMatrix( matrix3x4a_t &mMat, Axis_t eFromUpAxis, ForwardParity_t eFromForwardParity, CoordSys_t eFromCoordSys, Axis_t eToUpAxis, ForwardParity_t eToForwardParity, CoordSys_t eToCoordSys ) { matrix3x4a_t mFrom; ComputeMatrix( mFrom, eFromUpAxis, eFromForwardParity, eFromCoordSys );
matrix3x4a_t mTo; ComputeMatrix( mTo, eToUpAxis, eToForwardParity, eToCoordSys );
// Matrix is guaranteed to be a rotation matrix (orthonormal upper 3x3) with no translation
// so in this case, Transpose is the same as Inverse
matrix3x4a_t mFromInv; MatrixTranspose( mFrom, mFromInv );
MatrixMultiply( mTo, mFromInv, mMat ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CUtlString CDmeAxisSystem::GetAxisString( Axis_t eUpAxis, ForwardParity_t eForwardParity, CoordSys_t eCoordSys ) { int nUSign = 0; const int nU = GetAbsAxisAndSign( nUSign, eUpAxis ); int nFSign = 0; const int nF = ::ComputeAbsForwardAxisAndSign( nFSign, eUpAxis, eForwardParity ); int nLSign = 0; const int nL = ::ComputeAbsLeftAxisAndSign( nLSign, eUpAxis, eForwardParity, eCoordSys );
const char *szAxis[] = { "x", "y", "z" };
return CUtlString( CFmtStr( "u_%s%s_f_%s%s_l_%s%s", nUSign < 0 ? "n" : "", szAxis[nU - 1], nFSign < 0 ? "n" : "", szAxis[nF - 1], nLSign < 0 ? "n" : "", szAxis[nL - 1] ).Get() ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeAxisSystem::Axis_t CDmeAxisSystem::GetAbsUpAxisAndSign( int &nSign ) const { return ::GetAbsAxisAndSign( nSign, static_cast< Axis_t >( m_nUpAxis.Get() ) ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeAxisSystem::ForwardParity_t CDmeAxisSystem::GetAbsForwardParityAndSign( int &nSign ) const { return ::GetAbsForwardParityAndSign( nSign, GetForwardParity() ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeAxisSystem::Axis_t CDmeAxisSystem::ComputeAbsForwardAxisAndSign( int &nSign ) const { Assert( IsValid() ); return ::ComputeAbsForwardAxisAndSign( nSign, GetUpAxis(), GetForwardParity() ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
CDmeAxisSystem::Axis_t CDmeAxisSystem::ComputeLeftAxis( int &nSign ) const { Assert( IsValid() ); return ::ComputeAbsLeftAxisAndSign( nSign, GetUpAxis(), GetForwardParity(), GetCoordSys() ); }
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeAxisSystem::ComputeMatrix( matrix3x4a_t &mMatrix, const Axis_t eUpAxis, const ForwardParity_t eForwardParity, const CoordSys_t eCoordSys ) { Assert( IsValid( eUpAxis, eForwardParity, eCoordSys ) );
int nUpAxisSign = 0; const Axis_t eAbsUpAxis = ::GetAbsAxisAndSign( nUpAxisSign, eUpAxis ); AssertDbg( nUpAxisSign == -1 || nUpAxisSign == 1 ); AssertDbg( eAbsUpAxis >= AS_AXIS_X && eAbsUpAxis <= AS_AXIS_Z );
int nForwardAxisSign = 0; const Axis_t eAbsForwardAxis = ::ComputeAbsForwardAxisAndSign( nForwardAxisSign, eUpAxis, eForwardParity ); AssertDbg( eAbsForwardAxis >= AS_AXIS_X && eAbsForwardAxis <= AS_AXIS_Z ); AssertDbg( nForwardAxisSign == -1 || nForwardAxisSign == 1 );
AssertDbg( eAbsForwardAxis != eAbsUpAxis );
int nLeftAxisSign = 0; const Axis_t eAbsLeftAxis = ::ComputeAbsLeftAxisAndSign( nLeftAxisSign, eUpAxis, eForwardParity, eCoordSys ); AssertDbg( eAbsLeftAxis >= AS_AXIS_X && eAbsLeftAxis <= AS_AXIS_Z ); AssertDbg( nLeftAxisSign == -1 || nLeftAxisSign == 1 ); AssertDbg( eAbsLeftAxis != eAbsUpAxis ); AssertDbg( eAbsLeftAxis != eAbsForwardAxis );
// flVectorList[nAbsAxis - 1][( nSign + 1 ) / 2][]
static const float flVectorList[][2][3] = { { { -1.0f, 0.0f, 0.0f }, // -X
{ 1.0f, 0.0f, 0.0f } // X
}, { { 0.0f, -1.0f, 0.0f }, // -Y
{ 0.0f, 1.0f, 0.0f } // Y
}, { { 0.0f, 0.0f, -1.0f }, // -Z
{ 0.0f, 0.0f, 1.0f } // Z
} };
const int nUpSignIndex = ( nUpAxisSign + 1 ) / 2; const int nForwardSignIndex = ( nForwardAxisSign + 1 ) / 2; const int nLeftSignIndex = ( nLeftAxisSign + 1 ) / 2;
// Is this a bad idea?
const Vector &vUp = *reinterpret_cast< const Vector * >( flVectorList[eAbsUpAxis - 1][nUpSignIndex] ); const Vector &vForward = *reinterpret_cast< const Vector * >( flVectorList[eAbsForwardAxis - 1][nForwardSignIndex] ); const Vector &vLeft = *reinterpret_cast< const Vector * >( flVectorList[eAbsLeftAxis - 1][nLeftSignIndex] );
MatrixInitialize/*FLU*/( mMatrix, vec3_origin, vForward, vLeft, vUp ); }
|