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.

439 lines
12 KiB

  1. //========= Copyright � 1996-2005, 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. Init( NULL );
  19. }
  20. void CBoneMergeCache::Init( CBaseAnimating *pOwner )
  21. {
  22. m_pOwner = pOwner;
  23. m_pFollow = NULL;
  24. m_pFollowHdr = NULL;
  25. m_pFollowRenderHdr = NULL;
  26. m_pOwnerHdr = NULL;
  27. m_pFollowRenderHdr = NULL;
  28. m_nFollowBoneSetupMask = 0;
  29. m_bForceCacheClear = false;
  30. m_MergedBones.Purge();
  31. V_memset( m_iRawIndexMapping, 0xFF, sizeof( m_iRawIndexMapping ) ); // initialize to -1s
  32. }
  33. void CBoneMergeCache::UpdateCache()
  34. {
  35. if ( !m_pOwner )
  36. return;
  37. CStudioHdr *pOwnerHdr = m_pOwner->GetModelPtr();
  38. if ( !pOwnerHdr )
  39. return;
  40. const studiohdr_t *pOwnerRenderHdr = pOwnerHdr->GetRenderHdr();
  41. CBaseAnimating *pFollow = m_pOwner->FindFollowedEntity();
  42. CStudioHdr *pFollowHdr = (pFollow ? pFollow->GetModelPtr() : NULL);
  43. const studiohdr_t *pFollowRenderHdr = (pFollowHdr ? pFollowHdr->GetRenderHdr() : NULL );
  44. // if the follow parent has changed, or any of the underlying models has changed, reset the MergedBones list
  45. if ( pFollow != m_pFollow || pFollowRenderHdr != m_pFollowRenderHdr || pOwnerRenderHdr != m_pOwnerRenderHdr || m_bForceCacheClear )
  46. {
  47. m_MergedBones.Purge();
  48. m_bForceCacheClear = false;
  49. // Update the cache.
  50. if ( pFollow && pFollowHdr && pOwnerHdr )
  51. {
  52. m_pFollow = pFollow;
  53. m_pFollowHdr = pFollowHdr;
  54. m_pFollowRenderHdr = pFollowRenderHdr;
  55. m_pOwnerHdr = pOwnerHdr;
  56. m_pOwnerRenderHdr = pOwnerRenderHdr;
  57. m_BoneMergeBits.Resize( pOwnerHdr->numbones() );
  58. m_BoneMergeBits.ClearAll();
  59. const mstudiobone_t *pOwnerBones = m_pOwnerHdr->pBone( 0 );
  60. m_nFollowBoneSetupMask = BONE_USED_BY_BONE_MERGE;
  61. for ( int i = 0; i < m_pOwnerHdr->numbones(); i++ )
  62. {
  63. int parentBoneIndex = Studio_BoneIndexByName( m_pFollowHdr, pOwnerBones[i].pszName() );
  64. if ( parentBoneIndex < 0 )
  65. continue;
  66. m_iRawIndexMapping[i] = parentBoneIndex;
  67. // Add a merged bone here.
  68. CMergedBone mergedBone;
  69. mergedBone.m_iMyBone = i;
  70. mergedBone.m_iParentBone = parentBoneIndex;
  71. m_MergedBones.AddToTail( mergedBone );
  72. m_BoneMergeBits.Set( i );
  73. // flag bones used in merge so that they'll always be setup
  74. if ( ( m_pFollowHdr->boneFlags( parentBoneIndex ) & BONE_USED_BY_BONE_MERGE ) == 0 )
  75. {
  76. // go ahead and mark the bone and its parents
  77. int n = parentBoneIndex;
  78. while (n != -1)
  79. {
  80. m_pFollowHdr->setBoneFlags( n, BONE_USED_BY_BONE_MERGE );
  81. n = m_pFollowHdr->boneParent( n );
  82. }
  83. }
  84. // FIXME: only do this if it's for a "reverse" merge
  85. if ( ( m_pOwnerHdr->boneFlags( i ) & BONE_USED_BY_BONE_MERGE ) == 0 )
  86. {
  87. // go ahead and mark the bone and its parents
  88. int n = i;
  89. while (n != -1)
  90. {
  91. m_pOwnerHdr->setBoneFlags( n, BONE_USED_BY_BONE_MERGE );
  92. n = m_pOwnerHdr->boneParent( n );
  93. }
  94. }
  95. }
  96. // No merged bones found? Slam the mask to 0
  97. if ( !m_MergedBones.Count() )
  98. {
  99. m_nFollowBoneSetupMask = 0;
  100. }
  101. // find and record pose params that match by name
  102. for ( int i = 0; i < MAXSTUDIOPOSEPARAM; i++ )
  103. {
  104. // init mapping as invalid
  105. m_nOwnerToFollowPoseParamMapping[i] = -1;
  106. if ( i < m_pFollowHdr->GetNumPoseParameters() )
  107. {
  108. // get the follower's pose param name for this index
  109. const char * szFollowerPoseParamName = m_pFollowHdr->pPoseParameter( i ).pszName();
  110. // find it on the owner
  111. for ( int n = 0; n < MAXSTUDIOPOSEPARAM && n < m_pOwnerHdr->GetNumPoseParameters(); n++ )
  112. {
  113. const char * szOwnerPoseParamName = m_pOwnerHdr->pPoseParameter( n ).pszName();
  114. if ( !Q_strcmp( szFollowerPoseParamName, szOwnerPoseParamName ) )
  115. {
  116. //match
  117. m_nOwnerToFollowPoseParamMapping[i] = n;
  118. break;
  119. }
  120. }
  121. }
  122. }
  123. }
  124. else
  125. {
  126. Init( m_pOwner );
  127. }
  128. }
  129. }
  130. void CBoneMergeCache::MergeMatchingPoseParams( void )
  131. {
  132. UpdateCache();
  133. // If this is set, then all the other cache data is set.
  134. if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
  135. return;
  136. // set follower pose params using mapped indices from owner
  137. for ( int i = 0; i < MAXSTUDIOPOSEPARAM; i++ )
  138. {
  139. if ( m_nOwnerToFollowPoseParamMapping[i] != -1 )
  140. {
  141. m_pOwner->SetPoseParameter( m_nOwnerToFollowPoseParamMapping[i], m_pFollow->GetPoseParameter( i ) );
  142. }
  143. }
  144. }
  145. #ifdef CLIENT_DLL
  146. void CBoneMergeCache::MergeMatchingBones( int boneMask )
  147. {
  148. UpdateCache();
  149. // If this is set, then all the other cache data is set.
  150. if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
  151. return;
  152. // Have the entity we're following setup its bones.
  153. int nTempMask = m_nFollowBoneSetupMask;
  154. if ( m_pFollow->IsPlayer() )
  155. {
  156. // if the parent is a player, respect the incoming bone mask plus attachments,
  157. nTempMask = ( boneMask | BONE_USED_BY_ATTACHMENT );
  158. // but only use the custom blending rule portion
  159. if ( m_pFollow->m_nCustomBlendingRuleMask != -1 )
  160. nTempMask &= m_pFollow->m_nCustomBlendingRuleMask;
  161. }
  162. m_pFollow->SetupBones( NULL, -1, nTempMask, gpGlobals->curtime );
  163. // Now copy the bone matrices.
  164. for ( int i=0; i < m_MergedBones.Count(); i++ )
  165. {
  166. int iOwnerBone = m_MergedBones[i].m_iMyBone;
  167. int iParentBone = m_MergedBones[i].m_iParentBone;
  168. // Only update bones reference by the bone mask.
  169. if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) )
  170. continue;
  171. MatrixCopy( m_pFollow->GetBone( iParentBone ), m_pOwner->GetBoneForWrite( iOwnerBone ) );
  172. }
  173. }
  174. #endif
  175. #ifndef CLIENT_DLL
  176. void CBoneMergeCache::BuildMatricesWithBoneMerge(
  177. const CStudioHdr *pStudioHdr,
  178. const QAngle& angles,
  179. const Vector& origin,
  180. const Vector pos[MAXSTUDIOBONES],
  181. const Quaternion q[MAXSTUDIOBONES],
  182. matrix3x4_t bonetoworld[MAXSTUDIOBONES],
  183. CBaseAnimating *pParent,
  184. CBoneCache *pParentCache,
  185. int boneMask
  186. )
  187. {
  188. UpdateCache();
  189. bool bMergedBone[ MAXSTUDIOBONES ];
  190. memset( &bMergedBone, 0, sizeof(bool) * MAXSTUDIOBONES );
  191. for ( int i=0; i < m_MergedBones.Count(); i++ )
  192. {
  193. int iOwnerBone = m_MergedBones[i].m_iMyBone;
  194. int iParentBone = m_MergedBones[i].m_iParentBone;
  195. if ( iParentBone >= 0 )
  196. {
  197. // Only update bones reference by the bone mask.
  198. if ( !( pStudioHdr->boneFlags( iOwnerBone ) & boneMask ) )
  199. continue;
  200. matrix3x4_t *pMat = pParentCache->GetCachedBone( iParentBone );
  201. if ( pMat )
  202. {
  203. MatrixCopy( *pMat, bonetoworld[ iOwnerBone ] );
  204. bMergedBone[iOwnerBone] = true;
  205. }
  206. }
  207. }
  208. const mstudiobone_t *pbones = pStudioHdr->pBone( 0 );
  209. matrix3x4_t rotationmatrix; // model to world transformation
  210. AngleMatrix( angles, origin, rotationmatrix);
  211. for ( int i=0; i < pStudioHdr->numbones(); i++ )
  212. {
  213. if ( !bMergedBone[i] )
  214. {
  215. // If we get down here, then the bone wasn't merged.
  216. matrix3x4_t bonematrix;
  217. QuaternionMatrix( q[i], pos[i], bonematrix );
  218. if (pbones[i].parent == -1)
  219. {
  220. ConcatTransforms (rotationmatrix, bonematrix, bonetoworld[i]);
  221. }
  222. else
  223. {
  224. ConcatTransforms (bonetoworld[pbones[i].parent], bonematrix, bonetoworld[i]);
  225. }
  226. }
  227. }
  228. //CStudioHdr *fhdr = pParent->GetModelPtr();
  229. //const mstudiobone_t *pbones = pStudioHdr->pBone( 0 );
  230. //
  231. //matrix3x4_t rotationmatrix; // model to world transformation
  232. //AngleMatrix( angles, origin, rotationmatrix);
  233. //
  234. //for ( int i=0; i < pStudioHdr->numbones(); i++ )
  235. //{
  236. // // Now find the bone in the parent entity.
  237. // bool merged = false;
  238. // int parentBoneIndex = Studio_BoneIndexByName( fhdr, pbones[i].pszName() );
  239. // if ( parentBoneIndex >= 0 )
  240. // {
  241. // matrix3x4_t *pMat = pParentCache->GetCachedBone( parentBoneIndex );
  242. // if ( pMat )
  243. // {
  244. // MatrixCopy( *pMat, bonetoworld[ i ] );
  245. // merged = true;
  246. // }
  247. // }
  248. //
  249. // if ( !merged )
  250. // {
  251. // // If we get down here, then the bone wasn't merged.
  252. // matrix3x4_t bonematrix;
  253. // QuaternionMatrix( q[i], pos[i], bonematrix );
  254. //
  255. // if (pbones[i].parent == -1)
  256. // {
  257. // ConcatTransforms (rotationmatrix, bonematrix, bonetoworld[i]);
  258. // }
  259. // else
  260. // {
  261. // ConcatTransforms (bonetoworld[pbones[i].parent], bonematrix, bonetoworld[i]);
  262. // }
  263. // }
  264. //}
  265. }
  266. #endif
  267. void CBoneMergeCache::CopyFromFollow( const BoneVector followPos[], const BoneQuaternion followQ[], int boneMask, BoneVector myPos[], BoneQuaternion myQ[] )
  268. {
  269. UpdateCache();
  270. // If this is set, then all the other cache data is set.
  271. if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
  272. return;
  273. // Now copy the bone matrices.
  274. for ( int i=0; i < m_MergedBones.Count(); i++ )
  275. {
  276. int iOwnerBone = m_MergedBones[i].m_iMyBone;
  277. int iParentBone = m_MergedBones[i].m_iParentBone;
  278. // Only update bones reference by the bone mask.
  279. if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) )
  280. continue;
  281. myPos[ iOwnerBone ] = followPos[ iParentBone ];
  282. myQ[ iOwnerBone ] = followQ[ iParentBone ];
  283. }
  284. }
  285. void CBoneMergeCache::CopyToFollow( const BoneVector myPos[], const BoneQuaternion myQ[], int boneMask, BoneVector followPos[], BoneQuaternion followQ[] )
  286. {
  287. UpdateCache();
  288. // If this is set, then all the other cache data is set.
  289. if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
  290. return;
  291. // Now copy the bone matrices.
  292. for ( int i=0; i < m_MergedBones.Count(); i++ )
  293. {
  294. int iOwnerBone = m_MergedBones[i].m_iMyBone;
  295. int iParentBone = m_MergedBones[i].m_iParentBone;
  296. // Only update bones reference by the bone mask.
  297. if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) )
  298. continue;
  299. followPos[ iParentBone ] = myPos[ iOwnerBone ];
  300. followQ[ iParentBone ] = myQ[ iOwnerBone ];
  301. }
  302. m_nCopiedFramecount = gpGlobals->framecount;
  303. }
  304. bool CBoneMergeCache::IsCopied( )
  305. {
  306. return (m_nCopiedFramecount == gpGlobals->framecount);
  307. }
  308. bool CBoneMergeCache::GetAimEntOrigin( Vector *pAbsOrigin, QAngle *pAbsAngles )
  309. {
  310. UpdateCache();
  311. // If this is set, then all the other cache data is set.
  312. if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
  313. return false;
  314. // We want the abs origin such that if we put the entity there, the first merged bone
  315. // will be aligned. This way the entity will be culled in the correct position.
  316. //
  317. // ie: mEntity * mBoneLocal = mFollowBone
  318. // so: mEntity = mFollowBone * Inverse( mBoneLocal )
  319. //
  320. // Note: the code below doesn't take animation into account. If the attached entity animates
  321. // all over the place, then this won't get the right results.
  322. // FIXME: we're merged onto a dead player that's likely ragdolled all over the place.
  323. // The parent's cached position and angles are dirty, but the absorigin and absangles are good enough.
  324. // Returning false here means the uncached parent origin/angles will be used.
  325. if ( m_pFollow->IsPlayer() && !m_pFollow->IsAlive() )
  326. return false;
  327. // Get mFollowBone.
  328. #ifdef CLIENT_DLL
  329. ACTIVE_SPLITSCREEN_PLAYER_GUARD( 0 );
  330. m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime );
  331. const matrix3x4_t &mFollowBone = m_pFollow->GetBone( m_MergedBones[0].m_iParentBone );
  332. #else
  333. m_pFollow->SetupBones( NULL, m_nFollowBoneSetupMask );
  334. matrix3x4_t mFollowBone;
  335. m_pFollow->GetBoneTransform( m_MergedBones[0].m_iParentBone, mFollowBone );
  336. #endif
  337. // Get Inverse( mBoneLocal )
  338. matrix3x4_t mBoneLocal, mBoneLocalInv;
  339. SetupSingleBoneMatrix( m_pOwnerHdr, m_pOwner->GetSequence(), 0, m_MergedBones[0].m_iMyBone, mBoneLocal );
  340. MatrixInvert( mBoneLocal, mBoneLocalInv );
  341. // Now calculate mEntity = mFollowBone * Inverse( mBoneLocal )
  342. matrix3x4_t mEntity;
  343. ConcatTransforms( mFollowBone, mBoneLocalInv, mEntity );
  344. MatrixAngles( mEntity, *pAbsAngles, *pAbsOrigin );
  345. return true;
  346. }
  347. bool CBoneMergeCache::GetRootBone( matrix3x4_t &rootBone )
  348. {
  349. UpdateCache();
  350. // If this is set, then all the other cache data is set.
  351. if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
  352. return false;
  353. // Get mFollowBone.
  354. #ifdef CLIENT_DLL
  355. m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime );
  356. rootBone = m_pFollow->GetBone( m_MergedBones[0].m_iParentBone );
  357. #else
  358. m_pFollow->SetupBones( NULL, m_nFollowBoneSetupMask );
  359. m_pFollow->GetBoneTransform( m_MergedBones[0].m_iParentBone, rootBone );
  360. #endif
  361. return true;
  362. }