Team Fortress 2 Source Code as on 22/4/2020
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.

334 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Dme version of a skeletal model (gets compiled into a MDL)
  4. //
  5. //=============================================================================
  6. #include "movieobjects/dmemodel.h"
  7. #include "movieobjects_interfaces.h"
  8. #include "datamodel/dmelementfactoryhelper.h"
  9. #include "datacache/imdlcache.h"
  10. #include "materialsystem/imaterialsystem.h"
  11. #include "tier2/tier2.h"
  12. #include "studio.h"
  13. #include "materialsystem/imaterialsystemhardwareconfig.h"
  14. // memdbgon must be the last include file in a .cpp file!!!
  15. #include "tier0/memdbgon.h"
  16. //-----------------------------------------------------------------------------
  17. // Expose this class to the scene database
  18. //-----------------------------------------------------------------------------
  19. IMPLEMENT_ELEMENT_FACTORY( DmeModel, CDmeModel );
  20. //-----------------------------------------------------------------------------
  21. // Stack of DmeModels currently being rendered. Used to set up render state
  22. //-----------------------------------------------------------------------------
  23. CUtlStack< CDmeModel * > CDmeModel::s_ModelStack;
  24. static CUtlVector< matrix3x4_t > s_PoseToWorld;
  25. //-----------------------------------------------------------------------------
  26. // Purpose:
  27. //-----------------------------------------------------------------------------
  28. void CDmeModel::OnConstruction()
  29. {
  30. m_JointTransforms.Init( this, "jointTransforms" );
  31. m_BaseStates.Init( this, "baseStates" );
  32. }
  33. void CDmeModel::OnDestruction()
  34. {
  35. }
  36. //-----------------------------------------------------------------------------
  37. // Add joint
  38. //-----------------------------------------------------------------------------
  39. int CDmeModel::AddJoint( CDmeDag *pJoint )
  40. {
  41. int nIndex = GetJointTransformIndex( pJoint->GetTransform() );
  42. if ( nIndex >= 0 )
  43. return nIndex;
  44. return m_JointTransforms.AddToTail( pJoint->GetTransform() );
  45. }
  46. //-----------------------------------------------------------------------------
  47. // Add joint
  48. //-----------------------------------------------------------------------------
  49. CDmeJoint *CDmeModel::AddJoint( const char *pJointName, CDmeDag *pParent )
  50. {
  51. CDmeJoint *pJoint = CreateElement<CDmeJoint>( pJointName, GetFileId() );
  52. CDmeTransform *pTransform = pJoint->GetTransform();
  53. pTransform->SetName( pJointName );
  54. if ( !pParent )
  55. {
  56. pParent = this;
  57. }
  58. pParent->AddChild( pJoint );
  59. m_JointTransforms.AddToTail( pTransform );
  60. return pJoint;
  61. }
  62. //-----------------------------------------------------------------------------
  63. // Returns the number of joint transforms we know about
  64. //-----------------------------------------------------------------------------
  65. int CDmeModel::GetJointTransformCount() const
  66. {
  67. return m_JointTransforms.Count();
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Determines joint transform index given a joint transform
  71. //-----------------------------------------------------------------------------
  72. int CDmeModel::GetJointTransformIndex( CDmeTransform *pTransform ) const
  73. {
  74. int nCount = m_JointTransforms.Count();
  75. for ( int i = 0; i < nCount; ++i )
  76. {
  77. if ( pTransform == m_JointTransforms[i] )
  78. return i;
  79. }
  80. return -1;
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Determines joint transform index given a joint
  84. //-----------------------------------------------------------------------------
  85. int CDmeModel::GetJointTransformIndex( CDmeDag *pJoint ) const
  86. {
  87. return GetJointTransformIndex( pJoint->GetTransform() );
  88. }
  89. //-----------------------------------------------------------------------------
  90. // Determines joint transform index given a joint name
  91. //-----------------------------------------------------------------------------
  92. CDmeTransform *CDmeModel::GetJointTransform( int nIndex )
  93. {
  94. return m_JointTransforms[ nIndex ];
  95. }
  96. const CDmeTransform *CDmeModel::GetJointTransform( int nIndex ) const
  97. {
  98. return m_JointTransforms[ nIndex ];
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Finds a base state by name, returns NULL if not found
  102. //-----------------------------------------------------------------------------
  103. CDmeTransformList *CDmeModel::FindBaseState( const char *pBaseStateName )
  104. {
  105. int nCount = m_BaseStates.Count();
  106. for ( int i = 0; i < nCount; ++i )
  107. {
  108. if ( !Q_stricmp( m_BaseStates[i]->GetName(), pBaseStateName ) )
  109. return m_BaseStates[i];
  110. }
  111. return NULL;
  112. }
  113. //-----------------------------------------------------------------------------
  114. // Captures the current joint transforms into a base state
  115. //-----------------------------------------------------------------------------
  116. void CDmeModel::CaptureJointsToBaseState( const char *pBaseStateName )
  117. {
  118. CDmeTransformList *pTransformList = FindBaseState( pBaseStateName );
  119. if ( !pTransformList )
  120. {
  121. pTransformList = CreateElement<CDmeTransformList>( pBaseStateName, GetFileId() );
  122. m_BaseStates.AddToTail( pTransformList );
  123. }
  124. // Make the transform list have the correct number of elements
  125. int nJointCount = m_JointTransforms.Count();
  126. int nCurrentCount = pTransformList->GetTransformCount();
  127. if ( nJointCount > nCurrentCount )
  128. {
  129. for ( int i = nCurrentCount; i < nJointCount; ++i )
  130. {
  131. CDmeTransform *pTransform = CreateElement<CDmeTransform>( m_JointTransforms[i]->GetName(), pTransformList->GetFileId() );
  132. pTransformList->m_Transforms.AddToTail( pTransform );
  133. }
  134. }
  135. else if ( nJointCount < nCurrentCount )
  136. {
  137. pTransformList->m_Transforms.RemoveMultiple( nJointCount, nCurrentCount - nJointCount );
  138. }
  139. // Copy the state over
  140. for ( int i = 0; i < nJointCount; ++i )
  141. {
  142. matrix3x4_t mat;
  143. m_JointTransforms[i]->GetTransform( mat );
  144. pTransformList->SetTransform( i, mat );
  145. }
  146. }
  147. //-----------------------------------------------------------------------------
  148. // Loads up joint transforms for this model
  149. //-----------------------------------------------------------------------------
  150. void CDmeModel::LoadJointTransform( CDmeDag *pJoint, CDmeTransformList *pBindPose, const matrix3x4_t &parentToWorld, const matrix3x4_t &parentToBindPose, bool bSetHardwareState )
  151. {
  152. CDmeTransform *pTransform = pJoint->GetTransform();
  153. // Determines joint transform index; no index, no traversing lower in the hierarchy
  154. int nJointIndex = GetJointTransformIndex( pTransform );
  155. if ( nJointIndex < 0 )
  156. return;
  157. // FIXME: Sucky search here necessary to find bone matrix index
  158. matrix3x4_t jointToWorld, jointToParent;
  159. pTransform->GetTransform( jointToParent );
  160. ConcatTransforms( parentToWorld, jointToParent, jointToWorld );
  161. matrix3x4_t bindJointToParent, bindPoseToJoint, bindPoseToWorld, jointToBindPose;
  162. if ( pBindPose )
  163. {
  164. if ( nJointIndex >= pBindPose->GetTransformCount() )
  165. {
  166. Warning( "Model is in an invalid state! There are different numbers of bones in the bind pose and joint transform list!\n" );
  167. return;
  168. }
  169. pBindPose->GetTransform( nJointIndex )->GetTransform( bindJointToParent );
  170. }
  171. else
  172. {
  173. MatrixCopy( jointToParent, bindJointToParent );
  174. }
  175. ConcatTransforms( parentToBindPose, bindJointToParent, jointToBindPose );
  176. MatrixInvert( jointToBindPose, bindPoseToJoint );
  177. ConcatTransforms( jointToWorld, bindPoseToJoint, bindPoseToWorld );
  178. if ( bSetHardwareState )
  179. {
  180. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  181. pRenderContext->LoadBoneMatrix( nJointIndex, bindPoseToWorld );
  182. }
  183. MatrixCopy( bindPoseToWorld, s_PoseToWorld[ nJointIndex ] );
  184. int nChildCount = pJoint->GetChildCount();
  185. for ( int i = 0; i < nChildCount; ++i )
  186. {
  187. CDmeDag *pChildJoint = pJoint->GetChild(i);
  188. if ( !pChildJoint )
  189. continue;
  190. LoadJointTransform( pChildJoint, pBindPose, jointToWorld, jointToBindPose, bSetHardwareState );
  191. }
  192. }
  193. //-----------------------------------------------------------------------------
  194. // Sets up the render state for the model
  195. //-----------------------------------------------------------------------------
  196. CDmeModel::SetupBoneRetval_t CDmeModel::SetupBoneMatrixState( const matrix3x4_t& shapeToWorld, bool bForceSoftwareSkin )
  197. {
  198. int nJointCount = m_JointTransforms.Count();
  199. if ( nJointCount <= 0 )
  200. return NO_SKIN_DATA;
  201. int nBoneBatchCount = g_pMaterialSystemHardwareConfig->MaxVertexShaderBlendMatrices();
  202. bool bSetHardwareState = ( nJointCount <= nBoneBatchCount ) && !bForceSoftwareSkin;
  203. s_PoseToWorld.EnsureCount( nJointCount );
  204. // Finds a base state by name, returns NULL if not found
  205. CDmeTransformList *pBindPose = FindBaseState( "bind" );
  206. matrix3x4_t parentToBindPose;
  207. SetIdentityMatrix( parentToBindPose );
  208. int nChildCount = GetChildCount();
  209. for ( int i = 0; i < nChildCount; ++i )
  210. {
  211. CDmeDag *pChildJoint = GetChild(i);
  212. if ( !pChildJoint )
  213. continue;
  214. LoadJointTransform( pChildJoint, pBindPose, shapeToWorld, parentToBindPose, bSetHardwareState );
  215. }
  216. return bSetHardwareState ? BONES_SET_UP : TOO_MANY_BONES;
  217. }
  218. matrix3x4_t *CDmeModel::SetupModelRenderState( const matrix3x4_t& shapeToWorld, bool bHasSkinningData, bool bForceSoftwareSkin )
  219. {
  220. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  221. if ( bHasSkinningData && ( s_ModelStack.Count() > 0 ) )
  222. {
  223. SetupBoneRetval_t retVal = s_ModelStack.Top()->SetupBoneMatrixState( shapeToWorld, bForceSoftwareSkin );
  224. if ( retVal == TOO_MANY_BONES )
  225. {
  226. pRenderContext->MatrixMode( MATERIAL_MODEL );
  227. pRenderContext->LoadIdentity( );
  228. return s_PoseToWorld.Base();
  229. }
  230. if ( retVal != NO_SKIN_DATA )
  231. return NULL;
  232. }
  233. if ( bForceSoftwareSkin )
  234. {
  235. pRenderContext->MatrixMode( MATERIAL_MODEL );
  236. pRenderContext->LoadIdentity( );
  237. s_PoseToWorld.EnsureCount( 1 );
  238. MatrixCopy( shapeToWorld, s_PoseToWorld[0] );
  239. return s_PoseToWorld.Base();
  240. }
  241. pRenderContext->MatrixMode( MATERIAL_MODEL );
  242. pRenderContext->LoadMatrix( shapeToWorld );
  243. return NULL;
  244. }
  245. void CDmeModel::CleanupModelRenderState()
  246. {
  247. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  248. pRenderContext->MatrixMode( MATERIAL_MODEL );
  249. pRenderContext->LoadIdentity();
  250. }
  251. //-----------------------------------------------------------------------------
  252. // Recursively render the Dag hierarchy
  253. //-----------------------------------------------------------------------------
  254. void CDmeModel::Draw( CDmeDrawSettings *pDrawSettings /* = NULL */ )
  255. {
  256. s_ModelStack.Push( this );
  257. BaseClass::Draw( pDrawSettings );
  258. s_ModelStack.Pop( );
  259. }
  260. //-----------------------------------------------------------------------------
  261. // Set if Z is the up axis of the model
  262. //-----------------------------------------------------------------------------
  263. void CDmeModel::ZUp( bool bZUp )
  264. {
  265. SetValue( "upAxis", bZUp ? "Z" : "Y" );
  266. }
  267. //-----------------------------------------------------------------------------
  268. // Returns true if the DmeModel is Z Up.
  269. // NOTE: Since Y & Z are the only supported modes and Y is the default
  270. // because that's how DmeModel data was originally defined,
  271. // assume Y is up if the m_UpAxis attribute is not "Z"
  272. //-----------------------------------------------------------------------------
  273. bool CDmeModel::IsZUp() const
  274. {
  275. const char *pszZUp = this->GetValueString( "upAxis" );
  276. return ( pszZUp && *pszZUp ) ? StringHasPrefix( pszZUp, "Z" ) : false;
  277. }