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.

288 lines
8.6 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "bone_merge_cache.h"
  10. #include "bone_setup.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include "tier0/memdbgon.h"
  13. //-----------------------------------------------------------------------------
  14. // CBoneMergeCache
  15. //-----------------------------------------------------------------------------
  16. CBoneMergeCache::CBoneMergeCache()
  17. {
  18. m_pOwner = NULL;
  19. m_pFollow = NULL;
  20. m_pFollowHdr = NULL;
  21. m_pFollowRenderHdr = NULL;
  22. m_pOwnerHdr = NULL;
  23. m_nFollowBoneSetupMask = 0;
  24. }
  25. void CBoneMergeCache::Init( C_BaseAnimating *pOwner )
  26. {
  27. m_pOwner = pOwner;
  28. m_pFollow = NULL;
  29. m_pFollowHdr = NULL;
  30. m_pFollowRenderHdr = NULL;
  31. m_pOwnerHdr = NULL;
  32. m_nFollowBoneSetupMask = 0;
  33. }
  34. void CBoneMergeCache::UpdateCache()
  35. {
  36. CStudioHdr *pOwnerHdr = m_pOwner ? m_pOwner->GetModelPtr() : NULL;
  37. if ( !pOwnerHdr )
  38. {
  39. if ( m_pOwnerHdr )
  40. {
  41. // Owner's model got swapped out
  42. m_MergedBones.Purge();
  43. m_BoneMergeBits.Purge();
  44. m_pFollow = NULL;
  45. m_pFollowHdr = NULL;
  46. m_pFollowRenderHdr = NULL;
  47. m_pOwnerHdr = NULL;
  48. m_nFollowBoneSetupMask = 0;
  49. }
  50. return;
  51. }
  52. C_BaseAnimating *pTestFollow = m_pOwner->FindFollowedEntity();
  53. CStudioHdr *pTestHdr = (pTestFollow ? pTestFollow->GetModelPtr() : NULL);
  54. const studiohdr_t *pTestStudioHDR = (pTestHdr ? pTestHdr->GetRenderHdr() : NULL);
  55. if ( pTestFollow != m_pFollow || pTestHdr != m_pFollowHdr || pTestStudioHDR != m_pFollowRenderHdr || pOwnerHdr != m_pOwnerHdr )
  56. {
  57. m_MergedBones.Purge();
  58. m_BoneMergeBits.Purge();
  59. // Update the cache.
  60. if ( pTestFollow && pTestHdr && pOwnerHdr )
  61. {
  62. m_pFollow = pTestFollow;
  63. m_pFollowHdr = pTestHdr;
  64. m_pFollowRenderHdr = pTestStudioHDR;
  65. m_pOwnerHdr = pOwnerHdr;
  66. m_BoneMergeBits.SetSize( pOwnerHdr->numbones() / 8 + 1 );
  67. memset( m_BoneMergeBits.Base(), 0, m_BoneMergeBits.Count() );
  68. mstudiobone_t *pOwnerBones = m_pOwnerHdr->pBone( 0 );
  69. m_nFollowBoneSetupMask = BONE_USED_BY_BONE_MERGE;
  70. for ( int i = 0; i < m_pOwnerHdr->numbones(); i++ )
  71. {
  72. int parentBoneIndex = Studio_BoneIndexByName( m_pFollowHdr, pOwnerBones[i].pszName() );
  73. if ( parentBoneIndex < 0 )
  74. continue;
  75. // Add a merged bone here.
  76. CMergedBone mergedBone;
  77. mergedBone.m_iMyBone = i;
  78. mergedBone.m_iParentBone = parentBoneIndex;
  79. m_MergedBones.AddToTail( mergedBone );
  80. m_BoneMergeBits[i>>3] |= ( 1 << ( i & 7 ) );
  81. if ( ( m_pFollowHdr->boneFlags( parentBoneIndex ) & BONE_USED_BY_BONE_MERGE ) == 0 )
  82. {
  83. m_nFollowBoneSetupMask = BONE_USED_BY_ANYTHING;
  84. // Warning("Performance warning: Merge with '%s'. Mark bone '%s' in model '%s' as being used by bone merge in the .qc!\n",
  85. // pOwnerHdr->pszName(), m_pFollowHdr->pBone( parentBoneIndex )->pszName(), m_pFollowHdr->pszName() );
  86. }
  87. }
  88. // No merged bones found? Slam the mask to 0
  89. if ( !m_MergedBones.Count() )
  90. {
  91. m_nFollowBoneSetupMask = 0;
  92. }
  93. }
  94. else
  95. {
  96. m_pFollow = NULL;
  97. m_pFollowHdr = NULL;
  98. m_pFollowRenderHdr = NULL;
  99. m_pOwnerHdr = NULL;
  100. m_nFollowBoneSetupMask = 0;
  101. }
  102. }
  103. }
  104. #ifdef STAGING_ONLY
  105. ConVar r_captain_canteen_is_angry ( "r_captain_canteen_is_angry", "1" );
  106. #endif
  107. void CBoneMergeCache::MergeMatchingBones( int boneMask )
  108. {
  109. UpdateCache();
  110. // If this is set, then all the other cache data is set.
  111. if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
  112. return;
  113. // Have the entity we're following setup its bones.
  114. bool bWorked = m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime );
  115. // We suspect there's some cases where SetupBones couldn't do its thing, and then this causes Captain Canteen.
  116. Assert ( bWorked );
  117. if ( !bWorked )
  118. {
  119. // Usually this means your parent is invisible or gone or whatever.
  120. // This routine has no way to tell its caller not to draw itself unfortunately.
  121. // But we can shrink all the bones down to zero size.
  122. // But it might still spawn particle systems? :-(
  123. matrix3x4_t NewBone;
  124. MatrixScaleByZero ( NewBone );
  125. MatrixSetTranslation ( Vector ( 0.0f, 0.0f, 0.0f ), NewBone );
  126. #ifdef STAGING_ONLY
  127. if ( r_captain_canteen_is_angry.GetBool() )
  128. {
  129. // We actually want to see when Captain Canteen happened, and make it really obvious that (a) he was here and (b) this code would have fixed him.
  130. float HowAngry = 20.0f; // Leon's getting larger!
  131. MatrixSetColumn ( Vector ( HowAngry, 0.0f, 0.0f ), 0, NewBone );
  132. MatrixSetColumn ( Vector ( 0.0f, HowAngry, 0.0f ), 1, NewBone );
  133. MatrixSetColumn ( Vector ( 0.0f, 0.0f, HowAngry ), 2, NewBone );
  134. }
  135. #endif
  136. for ( int i=0; i < m_MergedBones.Count(); i++ )
  137. {
  138. int iOwnerBone = m_MergedBones[i].m_iMyBone;
  139. // Only update bones reference by the bone mask.
  140. if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) )
  141. continue;
  142. m_pOwner->GetBoneForWrite( iOwnerBone ) = NewBone;
  143. }
  144. }
  145. else
  146. {
  147. // Now copy the bone matrices.
  148. for ( int i=0; i < m_MergedBones.Count(); i++ )
  149. {
  150. int iOwnerBone = m_MergedBones[i].m_iMyBone;
  151. int iParentBone = m_MergedBones[i].m_iParentBone;
  152. // Only update bones reference by the bone mask.
  153. if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) )
  154. continue;
  155. MatrixCopy( m_pFollow->GetBone( iParentBone ), m_pOwner->GetBoneForWrite( iOwnerBone ) );
  156. }
  157. }
  158. }
  159. // copy bones instead of matrices
  160. void CBoneMergeCache::CopyParentToChild( const Vector parentPos[], const Quaternion parentQ[], Vector childPos[], Quaternion childQ[], int boneMask )
  161. {
  162. UpdateCache();
  163. // If this is set, then all the other cache data is set.
  164. if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
  165. return;
  166. // Now copy the bone matrices.
  167. for ( int i=0; i < m_MergedBones.Count(); i++ )
  168. {
  169. int iOwnerBone = m_MergedBones[i].m_iMyBone;
  170. int iParentBone = m_MergedBones[i].m_iParentBone;
  171. if ( m_pOwnerHdr->boneParent( iOwnerBone ) == -1 || m_pFollowHdr->boneParent( iParentBone ) == -1 )
  172. continue;
  173. // Only update bones reference by the bone mask.
  174. if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) )
  175. continue;
  176. childPos[ iOwnerBone ] = parentPos[ iParentBone ];
  177. childQ[ iOwnerBone ] = parentQ[ iParentBone ];
  178. }
  179. }
  180. void CBoneMergeCache::CopyChildToParent( const Vector childPos[], const Quaternion childQ[], Vector parentPos[], Quaternion parentQ[], int boneMask )
  181. {
  182. UpdateCache();
  183. // If this is set, then all the other cache data is set.
  184. if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
  185. return;
  186. // Now copy the bone matrices.
  187. for ( int i=0; i < m_MergedBones.Count(); i++ )
  188. {
  189. int iOwnerBone = m_MergedBones[i].m_iMyBone;
  190. int iParentBone = m_MergedBones[i].m_iParentBone;
  191. if ( m_pOwnerHdr->boneParent( iOwnerBone ) == -1 || m_pFollowHdr->boneParent( iParentBone ) == -1 )
  192. continue;
  193. // Only update bones reference by the bone mask.
  194. if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) )
  195. continue;
  196. parentPos[ iParentBone ] = childPos[ iOwnerBone ];
  197. parentQ[ iParentBone ] = childQ[ iOwnerBone ];
  198. }
  199. }
  200. bool CBoneMergeCache::GetAimEntOrigin( Vector *pAbsOrigin, QAngle *pAbsAngles )
  201. {
  202. UpdateCache();
  203. // If this is set, then all the other cache data is set.
  204. if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
  205. return false;
  206. // We want the abs origin such that if we put the entity there, the first merged bone
  207. // will be aligned. This way the entity will be culled in the correct position.
  208. //
  209. // ie: mEntity * mBoneLocal = mFollowBone
  210. // so: mEntity = mFollowBone * Inverse( mBoneLocal )
  211. //
  212. // Note: the code below doesn't take animation into account. If the attached entity animates
  213. // all over the place, then this won't get the right results.
  214. // Get mFollowBone.
  215. m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime );
  216. const matrix3x4_t &mFollowBone = m_pFollow->GetBone( m_MergedBones[0].m_iParentBone );
  217. // Get Inverse( mBoneLocal )
  218. matrix3x4_t mBoneLocal, mBoneLocalInv;
  219. SetupSingleBoneMatrix( m_pOwnerHdr, m_pOwner->GetSequence(), 0, m_MergedBones[0].m_iMyBone, mBoneLocal );
  220. MatrixInvert( mBoneLocal, mBoneLocalInv );
  221. // Now calculate mEntity = mFollowBone * Inverse( mBoneLocal )
  222. matrix3x4_t mEntity;
  223. ConcatTransforms( mFollowBone, mBoneLocalInv, mEntity );
  224. MatrixAngles( mEntity, *pAbsAngles, *pAbsOrigin );
  225. return true;
  226. }
  227. bool CBoneMergeCache::GetRootBone( matrix3x4_t &rootBone )
  228. {
  229. UpdateCache();
  230. // If this is set, then all the other cache data is set.
  231. if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
  232. return false;
  233. // Get mFollowBone.
  234. m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime );
  235. rootBone = m_pFollow->GetBone( m_MergedBones[0].m_iParentBone );
  236. return true;
  237. }