csgo-2018-source/movieobjects/dmeaxissystem.cpp
2021-07-24 21:11:47 -07:00

537 lines
19 KiB
C++

//============ 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 );
}