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

  1. //========= Copyright � Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //==========================================================================//
  6. #include "cmatrixstack.h"
  7. // Define RUN_TEST_CODE to validate that CMatrixStack behaves the same as ID3DXMatrixStack
  8. //#define RUN_TEST_CODE
  9. #if defined( RUN_TEST_CODE )
  10. #ifndef WIN32
  11. #error sorry man
  12. #endif
  13. #ifdef _X360
  14. #include "d3d9.h"
  15. #include "d3dx9.h"
  16. #else
  17. #include <windows.h>
  18. #include "../../dx9sdk/include/d3d9.h"
  19. #include "../../dx9sdk/include/d3dx9.h"
  20. #endif
  21. #else // RUN_TEST_CODE
  22. #if !defined( _X360 )
  23. struct D3DXMATRIX : public VMatrix{};
  24. struct D3DXVECTOR3 : public Vector{};
  25. #endif // _X360
  26. #endif // RUN_TEST_CODE
  27. // memdbgon must be the last include file in a .cpp file!!!
  28. #include "tier0/memdbgon.h"
  29. CMatrixStack::CMatrixStack( void )
  30. {
  31. m_Stack.AddToTail();
  32. m_Stack.Tail().Identity();
  33. }
  34. CMatrixStack::~CMatrixStack( void )
  35. {
  36. Assert( m_Stack.Count() == 1 ); // Catch push/pop mismatch
  37. Assert( m_Stack.Tail().IsIdentity() ); // Modifying the root matrix is probably unintentional
  38. }
  39. D3DXMATRIX *CMatrixStack::GetTop( void )
  40. {
  41. return (D3DXMATRIX *)&m_Stack.Tail();
  42. }
  43. void CMatrixStack::Push()
  44. {
  45. AssertMsg( m_Stack.Count() < 100, "CMatrixStack - Push/Pop mismatch!" ); // Catch push/pop mismatch
  46. // Duplicate the current 'top' matrix (NOTE: AddToTail can realloc!)
  47. m_Stack.AddToTail();
  48. VMatrix *top = &m_Stack.Tail();
  49. top[0] = top[-1];
  50. }
  51. void CMatrixStack::Pop()
  52. {
  53. AssertMsg( m_Stack.Count() > 1, "CMatrixStack - Push/Pop mismatch!" ); // Catch push/pop mismatch
  54. m_Stack.RemoveMultipleFromTail( 1 );
  55. }
  56. void CMatrixStack::LoadIdentity()
  57. {
  58. m_Stack.Tail().Identity();
  59. }
  60. void CMatrixStack::LoadMatrix( const D3DXMATRIX *pMat )
  61. {
  62. COMPILE_TIME_ASSERT( sizeof( VMatrix ) == sizeof( D3DXMATRIX ) );
  63. memcpy( &m_Stack.Tail(), pMat, sizeof( VMatrix ) );
  64. }
  65. void CMatrixStack::MultMatrix( const D3DXMATRIX *pMat )
  66. {
  67. // Right-multiply
  68. VMatrix &top = m_Stack.Tail();
  69. VMatrix result;
  70. MatrixMultiply( top, *(const VMatrix *)pMat, result );
  71. top = result;
  72. }
  73. void CMatrixStack::MultMatrixLocal( const D3DXMATRIX *pMat )
  74. {
  75. // Left-multiply
  76. VMatrix &top = m_Stack.Tail();
  77. VMatrix result;
  78. MatrixMultiply( *(const VMatrix *)pMat, top, result );
  79. top = result;
  80. }
  81. bool CMatrixStack::ScaleLocal( float x, float y, float z )
  82. {
  83. VMatrix scale;
  84. MatrixBuildScale( scale, x, y, z );
  85. // scale = scale.Transpose(); // A no-op, in this case :)
  86. MultMatrixLocal( (D3DXMATRIX *)&scale );
  87. return true;
  88. }
  89. bool CMatrixStack::RotateAxisLocal( const D3DXVECTOR3 *pV, float angleInRadians )
  90. {
  91. COMPILE_TIME_ASSERT( sizeof( Vector ) == sizeof( D3DXVECTOR3 ) );
  92. const Vector &axis = *(const Vector *)pV;
  93. VMatrix rotate;
  94. MatrixBuildRotationAboutAxis( rotate, axis, angleInRadians * 180 / M_PI );
  95. rotate = rotate.Transpose();
  96. MultMatrixLocal( (D3DXMATRIX *)&rotate );
  97. return true;
  98. }
  99. bool CMatrixStack::TranslateLocal( float x, float y, float z )
  100. {
  101. VMatrix translate;
  102. MatrixBuildTranslation( translate, x, y, z );
  103. translate = translate.Transpose();
  104. MultMatrixLocal( (D3DXMATRIX *)&translate );
  105. return true;
  106. }
  107. //==========================================================================//
  108. //
  109. // Test code to ensure this produces the same results as ID3DMATRIXStack
  110. //
  111. //==========================================================================//
  112. #if defined( RUN_TEST_CODE )
  113. class CMatrixStack_Test
  114. {
  115. enum TestOps
  116. {
  117. LOAD_IDENT = 0,
  118. LOAD_MAT = 1,
  119. PUSH = 2,
  120. POP = 3,
  121. MULT = 4,
  122. MULT_LOCAL = 5,
  123. // Only these local/left-multiply variants are used by ShaderAPI (not the right-multiply ROTATE/TRANSLATE/SCALE versions)
  124. SCALE_LOCAL = 6,
  125. ROTATE_LOCAL = 7,
  126. TRANSLATE_LOCAL = 8,
  127. NUM_TEST_OPS
  128. };
  129. public:
  130. CMatrixStack *m_pStack;
  131. ID3DXMatrixStack *m_pD3DStack;
  132. CMatrixStack_Test()
  133. {
  134. m_pStack = new CMatrixStack();
  135. HRESULT result = D3DXCreateMatrixStack( 0, &m_pD3DStack );
  136. if ( result == S_OK )
  137. {
  138. VMatrix testMatrix;
  139. testMatrix.Identity();
  140. MatrixTranslate( testMatrix, Vector( 1, 2, 3 ) );
  141. MatrixRotate( testMatrix, Vector( 1, 0, 0 ), 90 );
  142. MatrixTranslate( testMatrix, Vector( 4, 5, 6 ) );
  143. // CMatrixStack mimics D3DX's transposed matrix style
  144. testMatrix = testMatrix.Transpose();
  145. // Leave the top matrix unmodified
  146. m_pStack->Push();
  147. m_pD3DStack->Push();
  148. int depth = 2;
  149. Msg( "CMatrixStack test...\n" );
  150. srand(1352469);
  151. for ( int i = 0; i < 1000; i++ )
  152. {
  153. TestOps op = (TestOps)( rand() % NUM_TEST_OPS );
  154. switch( op )
  155. {
  156. case LOAD_IDENT:
  157. Msg( "LOAD_IDENT\n" );
  158. m_pStack->LoadIdentity();
  159. m_pD3DStack->LoadIdentity();
  160. break;
  161. case LOAD_MAT:
  162. Msg( "LOAD_MAT\n" );
  163. m_pStack->LoadMatrix( (D3DXMATRIX *) &testMatrix );
  164. m_pD3DStack->LoadMatrix( (D3DXMATRIX *) &testMatrix );
  165. break;
  166. case PUSH:
  167. Msg( "PUSH\n" );
  168. m_pStack->Push();
  169. m_pD3DStack->Push();
  170. depth++;
  171. break;
  172. case POP:
  173. if ( depth > 2 ) // Leave the top matrix unmodified
  174. {
  175. Msg( "POP\n" );
  176. m_pStack->Pop();
  177. m_pD3DStack->Pop();
  178. depth--;
  179. }
  180. break;
  181. case MULT:
  182. Msg( "MULT\n" );
  183. m_pStack->MultMatrix( (D3DXMATRIX *) &testMatrix );
  184. m_pD3DStack->MultMatrix( (D3DXMATRIX *) &testMatrix );
  185. break;
  186. case MULT_LOCAL:
  187. Msg( "MULT_LOCAL\n" );
  188. m_pStack->MultMatrixLocal( (D3DXMATRIX *) &testMatrix );
  189. m_pD3DStack->MultMatrixLocal( (D3DXMATRIX *) &testMatrix );
  190. break;
  191. case SCALE_LOCAL:
  192. Msg( "SCALE_LOCAL\n" );
  193. if ( i & 1 )
  194. {
  195. m_pStack->ScaleLocal( 2.0f, 2.0f, 2.0f );
  196. m_pD3DStack->ScaleLocal( 2.0f, 2.0f, 2.0f );
  197. }
  198. else
  199. {
  200. m_pStack->ScaleLocal( 0.5f, 0.5f, 0.5f );
  201. m_pD3DStack->ScaleLocal( 0.5f, 0.5f, 0.5f );
  202. }
  203. break;
  204. case ROTATE_LOCAL:
  205. {
  206. Msg( "ROTATE_LOCAL\n" );
  207. float angleInRadians = ( (i&1)?+1:-1 )*0.5f*M_PI;
  208. D3DXVECTOR3 axis(1,0,0);
  209. if ( (i%3) == 1 ) axis = D3DXVECTOR3(0,1,0);
  210. if ( (i%3) == 2 ) axis = D3DXVECTOR3(0,0,1);
  211. m_pStack->RotateAxisLocal( &axis, angleInRadians );
  212. m_pD3DStack->RotateAxisLocal( &axis, angleInRadians );
  213. break;
  214. }
  215. case TRANSLATE_LOCAL:
  216. {
  217. Msg( "TRANSLATE_LOCAL\n" );
  218. Vector delta = RandomVector( -10, +10 );
  219. m_pStack->TranslateLocal( delta.x, delta.y, delta.z );
  220. m_pD3DStack->TranslateLocal( delta.x, delta.y, delta.z );
  221. break;
  222. }
  223. }
  224. CompareTopMatrices( op );
  225. }
  226. while( depth > 1 )
  227. {
  228. m_pStack->Pop();
  229. m_pD3DStack->Pop();
  230. depth--;
  231. CompareTopMatrices( POP );
  232. }
  233. m_pD3DStack->Release();
  234. }
  235. delete m_pStack;
  236. }
  237. void CompareTopMatrices( TestOps op )
  238. {
  239. // Compare the top matrices
  240. float mat[4][4], d3dMat[4][4];
  241. COMPILE_TIME_ASSERT( sizeof( D3DXMATRIX ) == 16*sizeof( float ) );
  242. memcpy( mat, m_pStack->GetTop(), sizeof( D3DXMATRIX ) );
  243. memcpy( d3dMat, m_pD3DStack->GetTop(), sizeof( D3DXMATRIX ) );
  244. for ( int y = 0; y < 4; y++ )
  245. {
  246. for ( int x = 0; x < 4; x++ )
  247. {
  248. static float absEpsilon = 1.0e-5f, relEpsilon = 1.0e-4f;
  249. float absolute = fabsf( mat[y][x] - d3dMat[y][x] );
  250. float relative = 0;
  251. if ( fabsf( d3dMat[y][x] ) > 0.00001f )
  252. {
  253. relative = fabsf( ( mat[y][x] / d3dMat[y][x] ) - 1.0f );
  254. }
  255. AssertMsg9( ( absolute <= absEpsilon ) && ( relative <= relEpsilon ),
  256. "DIFFERENCE! CMatrixStack[%d][%d] = %10f, ID3DXMatrixStack[%d][%d] = %10f (OP: %d, Absolute diff: %10e, Relative diff: %10e)\n",
  257. y, x, mat[y][x],
  258. y, x, d3dMat[y][x],
  259. op, absolute, relative );
  260. }
  261. }
  262. // Copy the D3D version back onto ours, to negate accumulated numerical differences
  263. m_pStack->LoadMatrix( m_pD3DStack->GetTop() );
  264. }
  265. };
  266. static CMatrixStack_Test g_MatrixStackTest;
  267. #endif // defined( RUN_TEST_CODE )