Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

302 lines
7.9 KiB

//========= Copyright © Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//==========================================================================//
#include "cmatrixstack.h"
// Define RUN_TEST_CODE to validate that CMatrixStack behaves the same as ID3DXMatrixStack
//#define RUN_TEST_CODE
#if defined( RUN_TEST_CODE )
#ifndef WIN32
#error sorry man
#endif
#ifdef _X360
#include "d3d9.h"
#include "d3dx9.h"
#else
#include <windows.h>
#include "../../dx9sdk/include/d3d9.h"
#include "../../dx9sdk/include/d3dx9.h"
#endif
#else // RUN_TEST_CODE
#if !defined( _X360 )
struct D3DXMATRIX : public VMatrix{};
struct D3DXVECTOR3 : public Vector{};
#endif // _X360
#endif // RUN_TEST_CODE
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CMatrixStack::CMatrixStack( void )
{
m_Stack.AddToTail();
m_Stack.Tail().Identity();
}
CMatrixStack::~CMatrixStack( void )
{
Assert( m_Stack.Count() == 1 ); // Catch push/pop mismatch
Assert( m_Stack.Tail().IsIdentity() ); // Modifying the root matrix is probably unintentional
}
D3DXMATRIX *CMatrixStack::GetTop( void )
{
return (D3DXMATRIX *)&m_Stack.Tail();
}
void CMatrixStack::Push()
{
AssertMsg( m_Stack.Count() < 100, "CMatrixStack - Push/Pop mismatch!" ); // Catch push/pop mismatch
// Duplicate the current 'top' matrix (NOTE: AddToTail can realloc!)
m_Stack.AddToTail();
VMatrix *top = &m_Stack.Tail();
top[0] = top[-1];
}
void CMatrixStack::Pop()
{
AssertMsg( m_Stack.Count() > 1, "CMatrixStack - Push/Pop mismatch!" ); // Catch push/pop mismatch
m_Stack.RemoveMultipleFromTail( 1 );
}
void CMatrixStack::LoadIdentity()
{
m_Stack.Tail().Identity();
}
void CMatrixStack::LoadMatrix( const D3DXMATRIX *pMat )
{
COMPILE_TIME_ASSERT( sizeof( VMatrix ) == sizeof( D3DXMATRIX ) );
memcpy( &m_Stack.Tail(), pMat, sizeof( VMatrix ) );
}
void CMatrixStack::MultMatrix( const D3DXMATRIX *pMat )
{
// Right-multiply
VMatrix &top = m_Stack.Tail();
VMatrix result;
MatrixMultiply( top, *(const VMatrix *)pMat, result );
top = result;
}
void CMatrixStack::MultMatrixLocal( const D3DXMATRIX *pMat )
{
// Left-multiply
VMatrix &top = m_Stack.Tail();
VMatrix result;
MatrixMultiply( *(const VMatrix *)pMat, top, result );
top = result;
}
bool CMatrixStack::ScaleLocal( float x, float y, float z )
{
VMatrix scale;
MatrixBuildScale( scale, x, y, z );
// scale = scale.Transpose(); // A no-op, in this case :)
MultMatrixLocal( (D3DXMATRIX *)&scale );
return true;
}
bool CMatrixStack::RotateAxisLocal( const D3DXVECTOR3 *pV, float angleInRadians )
{
COMPILE_TIME_ASSERT( sizeof( Vector ) == sizeof( D3DXVECTOR3 ) );
const Vector &axis = *(const Vector *)pV;
VMatrix rotate;
MatrixBuildRotationAboutAxis( rotate, axis, angleInRadians * 180 / M_PI );
rotate = rotate.Transpose();
MultMatrixLocal( (D3DXMATRIX *)&rotate );
return true;
}
bool CMatrixStack::TranslateLocal( float x, float y, float z )
{
VMatrix translate;
MatrixBuildTranslation( translate, x, y, z );
translate = translate.Transpose();
MultMatrixLocal( (D3DXMATRIX *)&translate );
return true;
}
//==========================================================================//
//
// Test code to ensure this produces the same results as ID3DMATRIXStack
//
//==========================================================================//
#if defined( RUN_TEST_CODE )
class CMatrixStack_Test
{
enum TestOps
{
LOAD_IDENT = 0,
LOAD_MAT = 1,
PUSH = 2,
POP = 3,
MULT = 4,
MULT_LOCAL = 5,
// Only these local/left-multiply variants are used by ShaderAPI (not the right-multiply ROTATE/TRANSLATE/SCALE versions)
SCALE_LOCAL = 6,
ROTATE_LOCAL = 7,
TRANSLATE_LOCAL = 8,
NUM_TEST_OPS
};
public:
CMatrixStack *m_pStack;
ID3DXMatrixStack *m_pD3DStack;
CMatrixStack_Test()
{
m_pStack = new CMatrixStack();
HRESULT result = D3DXCreateMatrixStack( 0, &m_pD3DStack );
if ( result == S_OK )
{
VMatrix testMatrix;
testMatrix.Identity();
MatrixTranslate( testMatrix, Vector( 1, 2, 3 ) );
MatrixRotate( testMatrix, Vector( 1, 0, 0 ), 90 );
MatrixTranslate( testMatrix, Vector( 4, 5, 6 ) );
// CMatrixStack mimics D3DX's transposed matrix style
testMatrix = testMatrix.Transpose();
// Leave the top matrix unmodified
m_pStack->Push();
m_pD3DStack->Push();
int depth = 2;
Msg( "CMatrixStack test...\n" );
srand(1352469);
for ( int i = 0; i < 1000; i++ )
{
TestOps op = (TestOps)( rand() % NUM_TEST_OPS );
switch( op )
{
case LOAD_IDENT:
Msg( "LOAD_IDENT\n" );
m_pStack->LoadIdentity();
m_pD3DStack->LoadIdentity();
break;
case LOAD_MAT:
Msg( "LOAD_MAT\n" );
m_pStack->LoadMatrix( (D3DXMATRIX *) &testMatrix );
m_pD3DStack->LoadMatrix( (D3DXMATRIX *) &testMatrix );
break;
case PUSH:
Msg( "PUSH\n" );
m_pStack->Push();
m_pD3DStack->Push();
depth++;
break;
case POP:
if ( depth > 2 ) // Leave the top matrix unmodified
{
Msg( "POP\n" );
m_pStack->Pop();
m_pD3DStack->Pop();
depth--;
}
break;
case MULT:
Msg( "MULT\n" );
m_pStack->MultMatrix( (D3DXMATRIX *) &testMatrix );
m_pD3DStack->MultMatrix( (D3DXMATRIX *) &testMatrix );
break;
case MULT_LOCAL:
Msg( "MULT_LOCAL\n" );
m_pStack->MultMatrixLocal( (D3DXMATRIX *) &testMatrix );
m_pD3DStack->MultMatrixLocal( (D3DXMATRIX *) &testMatrix );
break;
case SCALE_LOCAL:
Msg( "SCALE_LOCAL\n" );
if ( i & 1 )
{
m_pStack->ScaleLocal( 2.0f, 2.0f, 2.0f );
m_pD3DStack->ScaleLocal( 2.0f, 2.0f, 2.0f );
}
else
{
m_pStack->ScaleLocal( 0.5f, 0.5f, 0.5f );
m_pD3DStack->ScaleLocal( 0.5f, 0.5f, 0.5f );
}
break;
case ROTATE_LOCAL:
{
Msg( "ROTATE_LOCAL\n" );
float angleInRadians = ( (i&1)?+1:-1 )*0.5f*M_PI;
D3DXVECTOR3 axis(1,0,0);
if ( (i%3) == 1 ) axis = D3DXVECTOR3(0,1,0);
if ( (i%3) == 2 ) axis = D3DXVECTOR3(0,0,1);
m_pStack->RotateAxisLocal( &axis, angleInRadians );
m_pD3DStack->RotateAxisLocal( &axis, angleInRadians );
break;
}
case TRANSLATE_LOCAL:
{
Msg( "TRANSLATE_LOCAL\n" );
Vector delta = RandomVector( -10, +10 );
m_pStack->TranslateLocal( delta.x, delta.y, delta.z );
m_pD3DStack->TranslateLocal( delta.x, delta.y, delta.z );
break;
}
}
CompareTopMatrices( op );
}
while( depth > 1 )
{
m_pStack->Pop();
m_pD3DStack->Pop();
depth--;
CompareTopMatrices( POP );
}
m_pD3DStack->Release();
}
delete m_pStack;
}
void CompareTopMatrices( TestOps op )
{
// Compare the top matrices
float mat[4][4], d3dMat[4][4];
COMPILE_TIME_ASSERT( sizeof( D3DXMATRIX ) == 16*sizeof( float ) );
memcpy( mat, m_pStack->GetTop(), sizeof( D3DXMATRIX ) );
memcpy( d3dMat, m_pD3DStack->GetTop(), sizeof( D3DXMATRIX ) );
for ( int y = 0; y < 4; y++ )
{
for ( int x = 0; x < 4; x++ )
{
static float absEpsilon = 1.0e-5f, relEpsilon = 1.0e-4f;
float absolute = fabsf( mat[y][x] - d3dMat[y][x] );
float relative = 0;
if ( fabsf( d3dMat[y][x] ) > 0.00001f )
{
relative = fabsf( ( mat[y][x] / d3dMat[y][x] ) - 1.0f );
}
AssertMsg9( ( absolute <= absEpsilon ) && ( relative <= relEpsilon ),
"DIFFERENCE! CMatrixStack[%d][%d] = %10f, ID3DXMatrixStack[%d][%d] = %10f (OP: %d, Absolute diff: %10e, Relative diff: %10e)\n",
y, x, mat[y][x],
y, x, d3dMat[y][x],
op, absolute, relative );
}
}
// Copy the D3D version back onto ours, to negate accumulated numerical differences
m_pStack->LoadMatrix( m_pD3DStack->GetTop() );
}
};
static CMatrixStack_Test g_MatrixStackTest;
#endif // defined( RUN_TEST_CODE )