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.

1559 lines
43 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include "tier0/dbg.h"
  9. #include "mathlib/mathlib.h"
  10. #include "bone_setup.h"
  11. #include <string.h>
  12. #include "collisionutils.h"
  13. #include "vstdlib/random.h"
  14. #include "tier0/vprof.h"
  15. #include "bone_accessor.h"
  16. #include "mathlib/ssequaternion.h"
  17. #include "bitvec.h"
  18. #include "datamanager.h"
  19. #include "convar.h"
  20. #include "tier0/tslist.h"
  21. #include "vphysics_interface.h"
  22. #include "datacache/idatacache.h"
  23. #include "posedebugger.h"
  24. #include "mathlib/softbody.h"
  25. #include "tier0/miniprofiler.h"
  26. #ifdef CLIENT_DLL
  27. #include "posedebugger.h"
  28. #endif
  29. #include "bone_utils.h"
  30. // memdbgon must be the last include file in a .cpp file!!!
  31. #include "tier0/memdbgon.h"
  32. //-----------------------------------------------------------------------------
  33. // Purpose: calculate a pose for a single sequence
  34. //-----------------------------------------------------------------------------
  35. void InitPose(
  36. const CStudioHdr *pStudioHdr,
  37. BoneVector pos[],
  38. BoneQuaternionAligned q[],
  39. int boneMask
  40. )
  41. {
  42. // const fltx4 zeroQ = Four_Origin;
  43. BONE_PROFILE_FUNC();
  44. SNPROF_ANIM("InitPose");
  45. if( mstudiolinearbone_t *pLinearBones = pStudioHdr->pLinearBones() )
  46. {
  47. int numBones = pStudioHdr->numbones();
  48. Assert( sizeof(Quaternion) == sizeof(BoneQuaternion) );
  49. memcpy( q, (((byte *)pLinearBones) + pLinearBones->quatindex), sizeof( Quaternion ) * numBones );
  50. if( sizeof(Vector) == sizeof(BoneVector) )
  51. {
  52. memcpy( pos, (((byte *)pLinearBones) + pLinearBones->posindex), sizeof( Vector ) * numBones );
  53. }
  54. else
  55. {
  56. Vector *pSrcPos = (Vector *)(((byte *)pLinearBones) + pLinearBones->posindex);
  57. for( int i = 0; i < pStudioHdr->numbones(); i++ )
  58. {
  59. //if( pStudioHdr->boneFlags( i ) & boneMask )
  60. {
  61. pos[i] = pSrcPos[i];
  62. }
  63. }
  64. }
  65. }
  66. else
  67. {
  68. for( int i = 0; i < pStudioHdr->numbones(); i++ )
  69. {
  70. if( pStudioHdr->boneFlags( i ) & boneMask )
  71. {
  72. const mstudiobone_t *pbone = pStudioHdr->pBone( i );
  73. pos[i] = pbone->pos;
  74. q[i] = pbone->quat;
  75. }
  76. /* // unnecessary to initialize unused bones since they are ignored downstream.
  77. else
  78. {
  79. pos[i].Zero();
  80. // q[i] = zeroQ;
  81. StoreAlignedSIMD(q[i].Base(), zeroQ);
  82. }
  83. */
  84. }
  85. }
  86. }
  87. inline bool PoseIsAllZeros(
  88. const CStudioHdr *pStudioHdr,
  89. int sequence,
  90. mstudioseqdesc_t &seqdesc,
  91. int i0,
  92. int i1
  93. )
  94. {
  95. int baseanim;
  96. // remove "zero" positional blends
  97. baseanim = pStudioHdr->iRelativeAnim( sequence, seqdesc.anim(i0 ,i1 ) );
  98. mstudioanimdesc_t &anim = ((CStudioHdr *)pStudioHdr)->pAnimdesc( baseanim );
  99. return (anim.flags & STUDIO_ALLZEROS) != 0;
  100. }
  101. //-----------------------------------------------------------------------------
  102. // Purpose: turn a 2x2 blend into a 3 way triangle blend
  103. // Returns: returns the animination indices and barycentric coordinates of a triangle
  104. // the triangle is a right triangle, and the diagonal is between elements [0] and [2]
  105. //-----------------------------------------------------------------------------
  106. static ConVar anim_3wayblend( "anim_3wayblend", "1", FCVAR_REPLICATED, "Toggle the 3-way animation blending code." );
  107. void Calc3WayBlendIndices( int i0, int i1, float s0, float s1, const mstudioseqdesc_t &seqdesc, int *pAnimIndices, float *pWeight )
  108. {
  109. BONE_PROFILE_FUNC();
  110. // Figure out which bi-section direction we are using to make triangles.
  111. bool bEven = ( ( ( i0 + i1 ) & 0x1 ) == 0 );
  112. int x1, y1;
  113. int x2, y2;
  114. int x3, y3;
  115. // diagonal is between elements 1 & 3
  116. // TL to BR
  117. if ( bEven )
  118. {
  119. if ( s0 > s1 )
  120. {
  121. // B
  122. x1 = 0; y1 = 0;
  123. x2 = 1; y2 = 0;
  124. x3 = 1; y3 = 1;
  125. pWeight[0] = (1.0f - s0);
  126. pWeight[1] = s0 - s1;
  127. }
  128. else
  129. {
  130. // C
  131. x1 = 1; y1 = 1;
  132. x2 = 0; y2 = 1;
  133. x3 = 0; y3 = 0;
  134. pWeight[0] = s0;
  135. pWeight[1] = s1 - s0;
  136. }
  137. }
  138. // BL to TR
  139. else
  140. {
  141. float flTotal = s0 + s1;
  142. if( flTotal > 1.0f )
  143. {
  144. // D
  145. x1 = 1; y1 = 0;
  146. x2 = 1; y2 = 1;
  147. x3 = 0; y3 = 1;
  148. pWeight[0] = (1.0f - s1);
  149. pWeight[1] = s0 - 1.0f + s1;
  150. }
  151. else
  152. {
  153. // A
  154. x1 = 0; y1 = 1;
  155. x2 = 0; y2 = 0;
  156. x3 = 1; y3 = 0;
  157. pWeight[0] = s1;
  158. pWeight[1] = 1.0f - s0 - s1;
  159. }
  160. }
  161. pAnimIndices[0] = seqdesc.anim( i0 + x1, i1 + y1 );
  162. pAnimIndices[1] = seqdesc.anim( i0 + x2, i1 + y2 );
  163. pAnimIndices[2] = seqdesc.anim( i0 + x3, i1 + y3 );
  164. /*
  165. float w0 = ((x2-x3)*(y3-s1) - (x3-s0)*(y2-y3)) / ((x1-x3)*(y2-y3) - (x2-x3)*(y1-y3));
  166. float w1 = ((x1-x3)*(y3-s1) - (x3-s0)*(y1-y3)) / ((x2-x3)*(y1-y3) - (x1-x3)*(y2-y3));
  167. Assert( pWeight[0] == w0 && pWeight[1] == w1 );
  168. */
  169. // clamp the diagonal
  170. if (pWeight[1] < 0.001f)
  171. pWeight[1] = 0.0f;
  172. pWeight[2] = 1.0f - pWeight[0] - pWeight[1];
  173. Assert( pWeight[0] >= 0.0f && pWeight[0] <= 1.0f );
  174. Assert( pWeight[1] >= 0.0f && pWeight[1] <= 1.0f );
  175. Assert( pWeight[2] >= 0.0f && pWeight[2] <= 1.0f );
  176. }
  177. //-----------------------------------------------------------------------------
  178. // Purpose: calculate a pose for a single sequence
  179. //-----------------------------------------------------------------------------
  180. bool CalcPoseSingle(
  181. const CStudioHdr *pStudioHdr,
  182. BoneVector pos[],
  183. BoneQuaternionAligned q[],
  184. mstudioseqdesc_t &seqdesc,
  185. int sequence,
  186. float cycle,
  187. const float poseParameter[],
  188. int boneMask,
  189. float flTime
  190. )
  191. {
  192. BONE_PROFILE_FUNC(); // ex: x360: up to 1.3ms
  193. SNPROF_ANIM("CalcPoseSingle");
  194. bool bResult = true;
  195. BoneVector *pos2 = g_VectorPool.Alloc();
  196. BoneQuaternionAligned *q2 = g_QuaternionPool.Alloc();
  197. BoneVector *pos3 = g_VectorPool.Alloc();
  198. BoneQuaternionAligned *q3 = g_QuaternionPool.Alloc();
  199. if ( sequence < 0 || sequence >= pStudioHdr->GetNumSeq())
  200. {
  201. AssertMsg( false, "Trying to CalcPoseSingle with an out-of-range sequence!\n" );
  202. return false;
  203. //sequence = 0;
  204. //seqdesc = ((CStudioHdr *)pStudioHdr)->pSeqdesc( sequence );
  205. }
  206. float s0 = 0, s1 = 0;
  207. int i0 = Studio_LocalPoseParameter( pStudioHdr, poseParameter, seqdesc, sequence, 0, s0 );
  208. int i1 = Studio_LocalPoseParameter( pStudioHdr, poseParameter, seqdesc, sequence, 1, s1 );
  209. if (seqdesc.flags & STUDIO_REALTIME)
  210. {
  211. float cps = Studio_CPS( pStudioHdr, seqdesc, sequence, poseParameter );
  212. cycle = flTime * cps;
  213. cycle = cycle - (int)cycle;
  214. }
  215. else if (seqdesc.flags & STUDIO_CYCLEPOSE)
  216. {
  217. int iPose = pStudioHdr->GetSharedPoseParameter( sequence, seqdesc.cycleposeindex );
  218. if (iPose != -1)
  219. {
  220. /*
  221. const mstudioposeparamdesc_t &Pose = pStudioHdr->pPoseParameter( iPose );
  222. cycle = poseParameter[ iPose ] * (Pose.end - Pose.start) + Pose.start;
  223. */
  224. cycle = poseParameter[ iPose ];
  225. }
  226. else
  227. {
  228. cycle = 0.0f;
  229. }
  230. }
  231. else if (cycle < 0 || cycle >= 1)
  232. {
  233. if (seqdesc.flags & STUDIO_LOOPING)
  234. {
  235. cycle = cycle - (int)cycle;
  236. if (cycle < 0) cycle += 1;
  237. }
  238. else
  239. {
  240. cycle = clamp( cycle, 0.0f, 1.0f );
  241. }
  242. }
  243. if (s0 < 0.001)
  244. {
  245. if (s1 < 0.001)
  246. {
  247. if (PoseIsAllZeros( pStudioHdr, sequence, seqdesc, i0, i1 ))
  248. {
  249. bResult = false;
  250. }
  251. else
  252. {
  253. CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0 , i1 ), cycle, boneMask );
  254. }
  255. }
  256. else if (s1 > 0.999)
  257. {
  258. CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0 , i1+1 ), cycle, boneMask );
  259. }
  260. else
  261. {
  262. CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0 , i1 ), cycle, boneMask );
  263. CalcAnimation( pStudioHdr, pos2, q2, seqdesc, sequence, seqdesc.anim( i0 , i1+1 ), cycle, boneMask );
  264. BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, s1, boneMask );
  265. }
  266. }
  267. else if (s0 > 0.999)
  268. {
  269. if (s1 < 0.001)
  270. {
  271. if (PoseIsAllZeros( pStudioHdr, sequence, seqdesc, i0+1, i1 ))
  272. {
  273. bResult = false;
  274. }
  275. else
  276. {
  277. CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0+1, i1 ), cycle, boneMask );
  278. }
  279. }
  280. else if (s1 > 0.999)
  281. {
  282. CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0+1, i1+1 ), cycle, boneMask );
  283. }
  284. else
  285. {
  286. CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0+1, i1 ), cycle, boneMask );
  287. CalcAnimation( pStudioHdr, pos2, q2, seqdesc, sequence, seqdesc.anim( i0+1, i1+1 ), cycle, boneMask );
  288. BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, s1, boneMask );
  289. }
  290. }
  291. else
  292. {
  293. if (s1 < 0.001)
  294. {
  295. if (PoseIsAllZeros( pStudioHdr, sequence, seqdesc, i0+1, i1 ))
  296. {
  297. CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0 ,i1 ), cycle, boneMask );
  298. ScaleBones( pStudioHdr, q, pos, sequence, 1.0 - s0, boneMask );
  299. }
  300. else if (PoseIsAllZeros( pStudioHdr, sequence, seqdesc, i0, i1 ))
  301. {
  302. CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0+1 ,i1 ), cycle, boneMask );
  303. ScaleBones( pStudioHdr, q, pos, sequence, s0, boneMask );
  304. }
  305. else
  306. {
  307. CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0 ,i1 ), cycle, boneMask );
  308. CalcAnimation( pStudioHdr, pos2, q2, seqdesc, sequence, seqdesc.anim( i0+1,i1 ), cycle, boneMask );
  309. BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, s0, boneMask );
  310. }
  311. }
  312. else if (s1 > 0.999)
  313. {
  314. CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0 ,i1+1 ), cycle, boneMask );
  315. CalcAnimation( pStudioHdr, pos2, q2, seqdesc, sequence, seqdesc.anim( i0+1,i1+1 ), cycle, boneMask );
  316. BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, s0, boneMask );
  317. }
  318. else if ( !anim_3wayblend.GetBool() )
  319. {
  320. CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, seqdesc.anim( i0 ,i1 ), cycle, boneMask );
  321. CalcAnimation( pStudioHdr, pos2, q2, seqdesc, sequence, seqdesc.anim( i0+1,i1 ), cycle, boneMask );
  322. BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, s0, boneMask );
  323. CalcAnimation( pStudioHdr, pos2, q2, seqdesc, sequence, seqdesc.anim( i0 , i1+1), cycle, boneMask );
  324. CalcAnimation( pStudioHdr, pos3, q3, seqdesc, sequence, seqdesc.anim( i0+1, i1+1), cycle, boneMask );
  325. BlendBones( pStudioHdr, q2, pos2, seqdesc, sequence, q3, pos3, s0, boneMask );
  326. BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, s1, boneMask );
  327. }
  328. else
  329. {
  330. int iAnimIndices[3];
  331. float weight[3];
  332. Calc3WayBlendIndices( i0, i1, s0, s1, seqdesc, iAnimIndices, weight );
  333. /*
  334. char buf[256];
  335. sprintf( buf, "%d %6.2f %d %6.2f : %6.2f %6.2f %6.2f\n", i0, s0, i1, s1, weight[0], weight[1], weight[2] );
  336. OutputDebugString( buf );
  337. */
  338. if (weight[1] < 0.001)
  339. {
  340. // on diagonal
  341. CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, iAnimIndices[0], cycle, boneMask );
  342. CalcAnimation( pStudioHdr, pos2, q2, seqdesc, sequence, iAnimIndices[2], cycle, boneMask );
  343. BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, weight[2] / (weight[0] + weight[2]), boneMask );
  344. }
  345. else
  346. {
  347. CalcAnimation( pStudioHdr, pos, q, seqdesc, sequence, iAnimIndices[0], cycle, boneMask );
  348. CalcAnimation( pStudioHdr, pos2, q2, seqdesc, sequence, iAnimIndices[1], cycle, boneMask );
  349. BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, weight[1] / (weight[0] + weight[1]), boneMask );
  350. CalcAnimation( pStudioHdr, pos3, q3, seqdesc, sequence, iAnimIndices[2], cycle, boneMask );
  351. BlendBones( pStudioHdr, q, pos, seqdesc, sequence, q3, pos3, weight[2], boneMask );
  352. }
  353. }
  354. }
  355. g_VectorPool.Free( pos2 );
  356. g_QuaternionPool.Free( q2 );
  357. g_VectorPool.Free( pos3 );
  358. g_QuaternionPool.Free( q3 );
  359. return bResult;
  360. }
  361. //-----------------------------------------------------------------------------
  362. // Purpose: calculate a pose for a single sequence
  363. // adds autolayers, runs local ik rukes
  364. //-----------------------------------------------------------------------------
  365. void CBoneSetup::AddSequenceLayers(
  366. BoneVector pos[],
  367. BoneQuaternion q[],
  368. mstudioseqdesc_t &seqdesc,
  369. int sequence,
  370. float cycle,
  371. float flWeight,
  372. float flTime,
  373. CIKContext *pIKContext
  374. )
  375. {
  376. BONE_PROFILE_FUNC(); // ex: x360: 1.84ms
  377. SNPROF_ANIM("CBoneSetup::AddSequenceLayers");
  378. for (int i = 0; i < seqdesc.numautolayers; i++)
  379. {
  380. mstudioautolayer_t *pLayer = seqdesc.pAutolayer( i );
  381. if (pLayer->flags & STUDIO_AL_LOCAL)
  382. continue;
  383. float layerCycle = cycle;
  384. float layerWeight = flWeight;
  385. if (pLayer->start != pLayer->end)
  386. {
  387. float s = 1.0;
  388. float index;
  389. if (!(pLayer->flags & STUDIO_AL_POSE))
  390. {
  391. index = cycle;
  392. }
  393. else
  394. {
  395. int iSequence = m_pStudioHdr->iRelativeSeq( sequence, pLayer->iSequence );
  396. int iPose = m_pStudioHdr->GetSharedPoseParameter( iSequence, pLayer->iPose );
  397. if (iPose != -1)
  398. {
  399. const mstudioposeparamdesc_t &Pose = ((CStudioHdr *)m_pStudioHdr)->pPoseParameter( iPose );
  400. index = m_flPoseParameter[ iPose ] * (Pose.end - Pose.start) + Pose.start;
  401. }
  402. else
  403. {
  404. index = 0;
  405. }
  406. }
  407. if (index < pLayer->start)
  408. continue;
  409. if (index >= pLayer->end)
  410. continue;
  411. if (index < pLayer->peak && pLayer->start != pLayer->peak)
  412. {
  413. s = (index - pLayer->start) / (pLayer->peak - pLayer->start);
  414. }
  415. else if (index > pLayer->tail && pLayer->end != pLayer->tail)
  416. {
  417. s = (pLayer->end - index) / (pLayer->end - pLayer->tail);
  418. }
  419. if (pLayer->flags & STUDIO_AL_SPLINE)
  420. {
  421. s = clamp( SimpleSpline( s ), 0, 1 ); // SimpleSpline imprecision can push some float values outside 0..1
  422. }
  423. if ((pLayer->flags & STUDIO_AL_XFADE) && (index > pLayer->tail))
  424. {
  425. layerWeight = ( s * flWeight ) / ( 1 - flWeight + s * flWeight );
  426. }
  427. else if (pLayer->flags & STUDIO_AL_NOBLEND)
  428. {
  429. layerWeight = s;
  430. }
  431. else
  432. {
  433. layerWeight = flWeight * s;
  434. }
  435. if (!(pLayer->flags & STUDIO_AL_POSE))
  436. {
  437. layerCycle = (cycle - pLayer->start) / (pLayer->end - pLayer->start);
  438. }
  439. }
  440. else if ( pLayer->start == 0 && pLayer->end == 0 && (pLayer->flags & STUDIO_AL_POSE) )
  441. {
  442. int iSequence = m_pStudioHdr->iRelativeSeq( sequence, pLayer->iSequence );
  443. int iPose = m_pStudioHdr->GetSharedPoseParameter( iSequence, pLayer->iPose );
  444. if (iPose == -1)
  445. continue;
  446. const mstudioposeparamdesc_t &Pose = ((CStudioHdr *)m_pStudioHdr)->pPoseParameter( iPose );
  447. float s = m_flPoseParameter[ iPose ] * (Pose.end - Pose.start) + Pose.start;
  448. Assert( (pLayer->tail - pLayer->peak) != 0 );
  449. s = clamp( (s - pLayer->peak) / (pLayer->tail - pLayer->peak), 0, 1 );
  450. if (pLayer->flags & STUDIO_AL_SPLINE)
  451. {
  452. s = clamp( SimpleSpline( s ), 0, 1 ); // SimpleSpline imprecision can push some float values outside 0..1
  453. }
  454. layerWeight = flWeight * s;
  455. }
  456. int iSequence = m_pStudioHdr->iRelativeSeq( sequence, pLayer->iSequence );
  457. AccumulatePose( pos, q, iSequence, layerCycle, layerWeight, flTime, pIKContext );
  458. }
  459. }
  460. //-----------------------------------------------------------------------------
  461. // Purpose: calculate a pose for a single sequence
  462. // adds autolayers, runs local ik rukes
  463. //-----------------------------------------------------------------------------
  464. void CBoneSetup::AddLocalLayers(
  465. BoneVector pos[],
  466. BoneQuaternion q[],
  467. mstudioseqdesc_t &seqdesc,
  468. int sequence,
  469. float cycle,
  470. float flWeight,
  471. float flTime,
  472. CIKContext *pIKContext
  473. )
  474. {
  475. BONE_PROFILE_FUNC();
  476. SNPROF_ANIM("CBoneSetup::AddLocalLayers");
  477. if (!(seqdesc.flags & STUDIO_LOCAL))
  478. {
  479. return;
  480. }
  481. for (int i = 0; i < seqdesc.numautolayers; i++)
  482. {
  483. mstudioautolayer_t *pLayer = seqdesc.pAutolayer( i );
  484. if (!(pLayer->flags & STUDIO_AL_LOCAL))
  485. continue;
  486. float layerCycle = cycle;
  487. float layerWeight = flWeight;
  488. if (pLayer->start != pLayer->end)
  489. {
  490. float s = 1.0;
  491. if (cycle < pLayer->start)
  492. continue;
  493. if (cycle >= pLayer->end)
  494. continue;
  495. if (cycle < pLayer->peak && pLayer->start != pLayer->peak)
  496. {
  497. s = (cycle - pLayer->start) / (pLayer->peak - pLayer->start);
  498. }
  499. else if (cycle > pLayer->tail && pLayer->end != pLayer->tail)
  500. {
  501. s = (pLayer->end - cycle) / (pLayer->end - pLayer->tail);
  502. }
  503. if (pLayer->flags & STUDIO_AL_SPLINE)
  504. {
  505. s = SimpleSpline( s );
  506. }
  507. if ((pLayer->flags & STUDIO_AL_XFADE) && (cycle > pLayer->tail))
  508. {
  509. layerWeight = ( s * flWeight ) / ( 1 - flWeight + s * flWeight );
  510. }
  511. else if (pLayer->flags & STUDIO_AL_NOBLEND)
  512. {
  513. layerWeight = s;
  514. }
  515. else
  516. {
  517. layerWeight = flWeight * s;
  518. }
  519. layerCycle = (cycle - pLayer->start) / (pLayer->end - pLayer->start);
  520. }
  521. int iSequence = m_pStudioHdr->iRelativeSeq( sequence, pLayer->iSequence );
  522. AccumulatePose( pos, q, iSequence, layerCycle, layerWeight, flTime, pIKContext );
  523. }
  524. }
  525. //-----------------------------------------------------------------------------
  526. // Purpose: my sleezy attempt at an interface only class
  527. //-----------------------------------------------------------------------------
  528. IBoneSetup::IBoneSetup( const CStudioHdr *pStudioHdr, int boneMask, const float poseParameter[], IPoseDebugger *pPoseDebugger )
  529. {
  530. m_pBoneSetup = new CBoneSetup( pStudioHdr, boneMask, poseParameter, pPoseDebugger );
  531. }
  532. IBoneSetup::~IBoneSetup( void )
  533. {
  534. if ( m_pBoneSetup )
  535. {
  536. delete m_pBoneSetup;
  537. }
  538. }
  539. void IBoneSetup::InitPose( BoneVector pos[], BoneQuaternionAligned q[] )
  540. {
  541. ::InitPose( m_pBoneSetup->m_pStudioHdr, pos, q, m_pBoneSetup->m_boneMask );
  542. }
  543. void IBoneSetup::AccumulatePose( BoneVector pos[], BoneQuaternion q[], int sequence, float cycle, float flWeight, float flTime, CIKContext *pIKContext )
  544. {
  545. m_pBoneSetup->AccumulatePose( pos, q, sequence, cycle, flWeight, flTime, pIKContext );
  546. }
  547. void IBoneSetup::CalcAutoplaySequences( BoneVector pos[], BoneQuaternion q[], float flRealTime, CIKContext *pIKContext )
  548. {
  549. m_pBoneSetup->CalcAutoplaySequences( pos, q, flRealTime, pIKContext );
  550. }
  551. // takes a "controllers[]" array normalized to 0..1 and adds in the adjustments to pos[], and q[].
  552. void IBoneSetup::CalcBoneAdj( BoneVector pos[], BoneQuaternion q[], const float controllers[] )
  553. {
  554. ::CalcBoneAdj( m_pBoneSetup->m_pStudioHdr, pos, q, controllers, m_pBoneSetup->m_boneMask );
  555. }
  556. CStudioHdr *IBoneSetup::GetStudioHdr()
  557. {
  558. return (CStudioHdr *)m_pBoneSetup->m_pStudioHdr;
  559. }
  560. CBoneSetup::CBoneSetup( const CStudioHdr *pStudioHdr, int boneMask, const float poseParameter[], IPoseDebugger *pPoseDebugger )
  561. {
  562. m_pStudioHdr = pStudioHdr;
  563. m_boneMask = boneMask;
  564. m_flPoseParameter = poseParameter;
  565. m_pPoseDebugger = pPoseDebugger;
  566. }
  567. #if 0
  568. //-----------------------------------------------------------------------------
  569. // Purpose: calculate a pose for a single sequence
  570. // adds autolayers, runs local ik rukes
  571. //-----------------------------------------------------------------------------
  572. void CalcPose(
  573. const CStudioHdr *pStudioHdr,
  574. CIKContext *pIKContext,
  575. BoneVector pos[],
  576. BoneQuaternionAligned q[],
  577. int sequence,
  578. float cycle,
  579. const float poseParameter[],
  580. int boneMask,
  581. float flWeight,
  582. float flTime
  583. )
  584. {
  585. BONE_PROFILE_FUNC();
  586. mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( sequence );
  587. Assert( flWeight >= 0.0f && flWeight <= 1.0f );
  588. // This shouldn't be necessary, but the Assert should help us catch whoever is screwing this up
  589. flWeight = clamp( flWeight, 0.0f, 1.0f );
  590. // add any IK locks to prevent numautolayers from moving extremities
  591. CIKContext seq_ik;
  592. if (seqdesc.numiklocks)
  593. {
  594. seq_ik.Init( pStudioHdr, vec3_angle, vec3_origin, 0.0, 0, boneMask ); // local space relative so absolute position doesn't mater
  595. seq_ik.AddSequenceLocks( seqdesc, pos, q );
  596. }
  597. CalcPoseSingle( pStudioHdr, pos, q, seqdesc, sequence, cycle, poseParameter, boneMask, flTime );
  598. if ( pIKContext )
  599. {
  600. pIKContext->AddDependencies( seqdesc, sequence, cycle, poseParameter, flWeight );
  601. }
  602. AddSequenceLayers( pStudioHdr, pIKContext, pos, q, seqdesc, sequence, cycle, poseParameter, boneMask, flWeight, flTime );
  603. if (seqdesc.numiklocks)
  604. {
  605. seq_ik.SolveSequenceLocks( seqdesc, pos, q );
  606. }
  607. }
  608. #endif
  609. extern ConVar cl_use_simd_bones;
  610. //-----------------------------------------------------------------------------
  611. // Purpose: accumulate a pose for a single sequence on top of existing animation
  612. // adds autolayers, runs local ik rukes
  613. //-----------------------------------------------------------------------------
  614. void CBoneSetup::AccumulatePose(
  615. BoneVector pos[],
  616. BoneQuaternion q[],
  617. int sequence,
  618. float cycle,
  619. float flWeight,
  620. float flTime,
  621. CIKContext *pIKContext
  622. )
  623. {
  624. BONE_PROFILE_FUNC(); // ex: x360: up to 3.6ms
  625. #if _DEBUG
  626. VPROF_INCREMENT_COUNTER("AccumulatePose",1);
  627. #endif
  628. VPROF( "AccumulatePose" );
  629. SNPROF_ANIM( "CBoneSetup::AccumulatePose" );
  630. // Check alignment.
  631. if ( cl_use_simd_bones.GetBool() && (! (reinterpret_cast<uintp>(q) & 0x0F) == 0 ) )
  632. {
  633. DebuggerBreakIfDebugging();
  634. AssertMsg(false,
  635. "Arguments to AccumulatePose are unaligned. Disaster will result.\n"
  636. );
  637. }
  638. Assert( flWeight >= 0.0f && flWeight <= 1.0f );
  639. // This shouldn't be necessary, but the Assert should help us catch whoever is screwing this up
  640. flWeight = clamp( flWeight, 0.0f, 1.0f );
  641. if ( sequence < 0 || sequence >= m_pStudioHdr->GetNumSeq() )
  642. {
  643. AssertMsg( false, "Trying to AccumulatePose with an out-of-range sequence!\n" );
  644. return;
  645. }
  646. // This should help re-use the memory for vectors/quaternions
  647. // BoneVector pos2[MAXSTUDIOBONES];
  648. // BoneQuaternion q2[MAXSTUDIOBONES];
  649. BoneVector *pos2 = g_VectorPool.Alloc();
  650. BoneQuaternionAligned * q2 = ( BoneQuaternionAligned * ) g_QuaternionPool.Alloc();
  651. PREFETCH360( pos2, 0 );
  652. PREFETCH360( q2, 0 );
  653. // Trigger pose debugger
  654. if (m_pPoseDebugger)
  655. {
  656. m_pPoseDebugger->AccumulatePose( m_pStudioHdr, pIKContext, pos, q, sequence, cycle, m_flPoseParameter, m_boneMask, flWeight, flTime );
  657. }
  658. mstudioseqdesc_t &seqdesc = ((CStudioHdr *)m_pStudioHdr)->pSeqdesc( sequence );
  659. // add any IK locks to prevent extremities from moving
  660. CIKContext seq_ik;
  661. if (seqdesc.numiklocks)
  662. {
  663. seq_ik.Init( m_pStudioHdr, vec3_angle, vec3_origin, 0.0, 0, m_boneMask ); // local space relative so absolute position doesn't mater
  664. seq_ik.AddSequenceLocks( seqdesc, pos, q );
  665. }
  666. if ((seqdesc.flags & STUDIO_LOCAL) || (seqdesc.flags & STUDIO_ROOTXFORM) || (seqdesc.flags & STUDIO_WORLD_AND_RELATIVE))
  667. {
  668. ::InitPose( m_pStudioHdr, pos2, q2, m_boneMask );
  669. }
  670. if (CalcPoseSingle( m_pStudioHdr, pos2, q2, seqdesc, sequence, cycle, m_flPoseParameter, m_boneMask, flTime ))
  671. {
  672. if ( (seqdesc.flags & STUDIO_ROOTXFORM) && seqdesc.rootDriverIndex > 0 )
  673. {
  674. // hack: Remap the driver bone if it's coming in from an included virtual model and the indices might not match
  675. // poseparam input is ignored for now
  676. int nRemappedDriverBone = seqdesc.rootDriverIndex;
  677. virtualmodel_t *pVModel = m_pStudioHdr->GetVirtualModel();
  678. if (pVModel)
  679. {
  680. const virtualgroup_t *pAnimGroup;
  681. const studiohdr_t *pAnimStudioHdr;
  682. int baseanimation = m_pStudioHdr->iRelativeAnim( sequence, 0 );
  683. pAnimGroup = pVModel->pAnimGroup( baseanimation );
  684. pAnimStudioHdr = ((CStudioHdr *)m_pStudioHdr)->pAnimStudioHdr( baseanimation );
  685. nRemappedDriverBone = pAnimGroup->masterBone[nRemappedDriverBone];
  686. }
  687. matrix3x4a_t rootDriverXform;
  688. AngleMatrix( RadianEuler(q2[nRemappedDriverBone]), pos2[nRemappedDriverBone], rootDriverXform );
  689. matrix3x4a_t rootToMove;
  690. AngleMatrix( RadianEuler(q[0]), pos[0], rootToMove );
  691. matrix3x4a_t rootMoved;
  692. ConcatTransforms_Aligned( rootDriverXform, rootToMove, rootMoved );
  693. MatrixAngles( rootMoved, q2[0], pos2[0] );
  694. }
  695. // this weight is wrong, the IK rules won't composite at the correct intensity
  696. AddLocalLayers( pos2, q2, seqdesc, sequence, cycle, 1.0, flTime, pIKContext );
  697. SlerpBones( m_pStudioHdr, q, pos, seqdesc, sequence, q2, pos2, flWeight, m_boneMask );
  698. }
  699. g_VectorPool.Free( pos2 );
  700. g_QuaternionPool.Free( q2 );
  701. if ( pIKContext )
  702. {
  703. pIKContext->AddDependencies( seqdesc, sequence, cycle, m_flPoseParameter, flWeight );
  704. }
  705. AddSequenceLayers( pos, q, seqdesc, sequence, cycle, flWeight, flTime, pIKContext );
  706. if (seqdesc.numiklocks)
  707. {
  708. seq_ik.SolveSequenceLocks( seqdesc, pos, q );
  709. }
  710. }
  711. //-----------------------------------------------------------------------------
  712. // Purpose: blend together q1,pos1 with q2,pos2. Return result in q1,pos1.
  713. // 0 returns q1, pos1. 1 returns q2, pos2
  714. //-----------------------------------------------------------------------------
  715. void CalcBoneAdj(
  716. const CStudioHdr *pStudioHdr,
  717. BoneVector pos[],
  718. BoneQuaternion q[],
  719. const float controllers[],
  720. int boneMask
  721. )
  722. {
  723. BONE_PROFILE_FUNC();
  724. int i, j, k;
  725. float value;
  726. mstudiobonecontroller_t *pbonecontroller;
  727. Vector p0;
  728. RadianEuler a0;
  729. Quaternion q0;
  730. for (j = 0; j < pStudioHdr->numbonecontrollers(); j++)
  731. {
  732. pbonecontroller = pStudioHdr->pBonecontroller( j );
  733. k = pbonecontroller->bone;
  734. if (pStudioHdr->boneFlags( k ) & boneMask)
  735. {
  736. i = pbonecontroller->inputfield;
  737. value = controllers[i];
  738. if (value < 0) value = 0;
  739. if (value > 1.0) value = 1.0;
  740. value = (1.0 - value) * pbonecontroller->start + value * pbonecontroller->end;
  741. switch(pbonecontroller->type & STUDIO_TYPES)
  742. {
  743. case STUDIO_XR:
  744. a0.Init( value * (M_PI / 180.0), 0, 0 );
  745. AngleQuaternion( a0, q0 );
  746. QuaternionSM( 1.0, q0, q[k], q[k] );
  747. break;
  748. case STUDIO_YR:
  749. a0.Init( 0, value * (M_PI / 180.0), 0 );
  750. AngleQuaternion( a0, q0 );
  751. QuaternionSM( 1.0, q0, q[k], q[k] );
  752. break;
  753. case STUDIO_ZR:
  754. a0.Init( 0, 0, value * (M_PI / 180.0) );
  755. AngleQuaternion( a0, q0 );
  756. QuaternionSM( 1.0, q0, q[k], q[k] );
  757. break;
  758. case STUDIO_X:
  759. pos[k].x += value;
  760. break;
  761. case STUDIO_Y:
  762. pos[k].y += value;
  763. break;
  764. case STUDIO_Z:
  765. pos[k].z += value;
  766. break;
  767. }
  768. }
  769. }
  770. }
  771. void CalcBoneDerivatives( Vector &velocity, AngularImpulse &angVel, const matrix3x4_t &prev, const matrix3x4_t &current, float dt )
  772. {
  773. float scale = 1.0;
  774. if ( dt > 0 )
  775. {
  776. scale = 1.0 / dt;
  777. }
  778. Vector endPosition, startPosition, deltaAxis;
  779. QAngle endAngles, startAngles;
  780. float deltaAngle;
  781. MatrixAngles( prev, startAngles, startPosition );
  782. MatrixAngles( current, endAngles, endPosition );
  783. velocity.x = (endPosition.x - startPosition.x) * scale;
  784. velocity.y = (endPosition.y - startPosition.y) * scale;
  785. velocity.z = (endPosition.z - startPosition.z) * scale;
  786. RotationDeltaAxisAngle( startAngles, endAngles, deltaAxis, deltaAngle );
  787. VectorScale( deltaAxis, (deltaAngle * scale), angVel );
  788. }
  789. void CalcBoneVelocityFromDerivative( const QAngle &vecAngles, Vector &velocity, AngularImpulse &angVel, const matrix3x4_t &current )
  790. {
  791. Vector vecLocalVelocity;
  792. AngularImpulse LocalAngVel;
  793. Quaternion q;
  794. float angle;
  795. MatrixAngles( current, q, vecLocalVelocity );
  796. QuaternionAxisAngle( q, LocalAngVel, angle );
  797. LocalAngVel *= angle;
  798. matrix3x4a_t matAngles;
  799. AngleMatrix( vecAngles, matAngles );
  800. VectorTransform( vecLocalVelocity, matAngles, velocity );
  801. VectorTransform( LocalAngVel, matAngles, angVel );
  802. }
  803. //-----------------------------------------------------------------------------
  804. // Purpose: run all animations that automatically play and are driven off of poseParameters
  805. //-----------------------------------------------------------------------------
  806. void CBoneSetup::CalcAutoplaySequences(
  807. BoneVector pos[],
  808. BoneQuaternion q[],
  809. float flRealTime,
  810. CIKContext *pIKContext
  811. )
  812. {
  813. BONE_PROFILE_FUNC();
  814. // ASSERT_NO_REENTRY();
  815. SNPROF_ANIM( "CBoneSetup::CalcAutoplaySequences" );
  816. int i;
  817. if ( pIKContext )
  818. {
  819. pIKContext->AddAutoplayLocks( pos, q );
  820. }
  821. unsigned short *pList = NULL;
  822. int count = m_pStudioHdr->GetAutoplayList( &pList );
  823. for (i = 0; i < count; i++)
  824. {
  825. int sequenceIndex = pList[i];
  826. mstudioseqdesc_t &seqdesc = ((CStudioHdr *)m_pStudioHdr)->pSeqdesc( sequenceIndex );
  827. if (seqdesc.flags & STUDIO_AUTOPLAY)
  828. {
  829. float cycle = 0;
  830. float cps = Studio_CPS( m_pStudioHdr, seqdesc, sequenceIndex, m_flPoseParameter );
  831. cycle = flRealTime * cps;
  832. cycle = cycle - (int)cycle;
  833. AccumulatePose( pos, q, sequenceIndex, cycle, 1.0, flRealTime, pIKContext );
  834. }
  835. }
  836. if ( pIKContext )
  837. {
  838. pIKContext->SolveAutoplayLocks( pos, q );
  839. }
  840. }
  841. //-----------------------------------------------------------------------------
  842. // Purpose:
  843. //-----------------------------------------------------------------------------
  844. void Studio_BuildMatrices(
  845. const CStudioHdr *pStudioHdr,
  846. const QAngle& angles,
  847. const Vector& origin,
  848. const BoneVector pos[],
  849. const BoneQuaternion q[],
  850. int iBone,
  851. float flScale,
  852. matrix3x4a_t bonetoworld[MAXSTUDIOBONES],
  853. int boneMask
  854. )
  855. {
  856. BONE_PROFILE_FUNC();
  857. int i, j;
  858. int chain[MAXSTUDIOBONES] = {};
  859. int chainlength = 0;
  860. if (iBone < -1 || iBone >= pStudioHdr->numbones())
  861. iBone = 0;
  862. // build list of what bones to use
  863. if (iBone == -1)
  864. {
  865. // all bones
  866. chainlength = pStudioHdr->numbones();
  867. for (i = 0; i < pStudioHdr->numbones(); i++)
  868. {
  869. chain[chainlength - i - 1] = i;
  870. }
  871. }
  872. else
  873. {
  874. // only the parent bones
  875. i = iBone;
  876. while (i != -1)
  877. {
  878. chain[chainlength++] = i;
  879. i = pStudioHdr->boneParent( i );
  880. }
  881. }
  882. matrix3x4a_t bonematrix;
  883. matrix3x4a_t rotationmatrix; // model to world transformation
  884. AngleMatrix( angles, origin, rotationmatrix );
  885. // Account for a change in scale
  886. if ( flScale < 1.0f-FLT_EPSILON || flScale > 1.0f+FLT_EPSILON )
  887. {
  888. Vector vecOffset;
  889. MatrixGetColumn( rotationmatrix, 3, vecOffset );
  890. vecOffset -= origin;
  891. vecOffset *= flScale;
  892. vecOffset += origin;
  893. MatrixSetColumn( vecOffset, 3, rotationmatrix );
  894. // Scale it uniformly
  895. VectorScale( rotationmatrix[0], flScale, rotationmatrix[0] );
  896. VectorScale( rotationmatrix[1], flScale, rotationmatrix[1] );
  897. VectorScale( rotationmatrix[2], flScale, rotationmatrix[2] );
  898. }
  899. // check for 16 byte alignment
  900. if ((((size_t)bonetoworld) % 16) != 0)
  901. {
  902. for (j = chainlength - 1; j >= 0; j--)
  903. {
  904. i = chain[j];
  905. if (pStudioHdr->boneFlags(i) & boneMask)
  906. {
  907. QuaternionMatrix( q[i], pos[i], bonematrix );
  908. if (pStudioHdr->boneParent(i) == -1)
  909. {
  910. ConcatTransforms (rotationmatrix, bonematrix, bonetoworld[i]);
  911. }
  912. else
  913. {
  914. ConcatTransforms (bonetoworld[pStudioHdr->boneParent(i)], bonematrix, bonetoworld[i]);
  915. }
  916. }
  917. }
  918. }
  919. else
  920. {
  921. for (j = chainlength - 1; j >= 0; j--)
  922. {
  923. i = chain[j];
  924. if (pStudioHdr->boneFlags(i) & boneMask)
  925. {
  926. QuaternionMatrix( q[i], pos[i], bonematrix );
  927. if (pStudioHdr->boneParent(i) == -1)
  928. {
  929. ConcatTransforms_Aligned (rotationmatrix, bonematrix, bonetoworld[i]);
  930. }
  931. else
  932. {
  933. ConcatTransforms_Aligned (bonetoworld[pStudioHdr->boneParent(i)], bonematrix, bonetoworld[i]);
  934. }
  935. }
  936. }
  937. }
  938. }
  939. //-----------------------------------------------------------------------------
  940. // Purpose: look at single column vector of another bones local transformation
  941. // and generate a procedural transformation based on how that column
  942. // points down the 6 cardinal axis (all negative weights are clamped to 0).
  943. //-----------------------------------------------------------------------------
  944. void DoAxisInterpBone(
  945. const mstudiobone_t *pbones,
  946. int ibone,
  947. CBoneAccessor &bonetoworld
  948. )
  949. {
  950. BONE_PROFILE_FUNC();
  951. matrix3x4a_t bonematrix;
  952. Vector control;
  953. mstudioaxisinterpbone_t *pProc = (mstudioaxisinterpbone_t *)pbones[ibone].pProcedure( );
  954. const matrix3x4_t &controlBone = bonetoworld.GetBone( pProc->control );
  955. if (pProc && pbones[pProc->control].parent != -1)
  956. {
  957. Vector tmp;
  958. // pull out the control column
  959. tmp.x = controlBone[0][pProc->axis];
  960. tmp.y = controlBone[1][pProc->axis];
  961. tmp.z = controlBone[2][pProc->axis];
  962. // invert it back into parent's space.
  963. VectorIRotate( tmp, bonetoworld.GetBone( pbones[pProc->control].parent ), control );
  964. #if 0
  965. matrix3x4a_t tmpmatrix;
  966. matrix3x4a_t controlmatrix;
  967. MatrixInvert( bonetoworld.GetBone( pbones[pProc->control].parent ), tmpmatrix );
  968. ConcatTransforms_Aligned( tmpmatrix, bonetoworld.GetBone( pProc->control ), controlmatrix );
  969. // pull out the control column
  970. control.x = controlmatrix[0][pProc->axis];
  971. control.y = controlmatrix[1][pProc->axis];
  972. control.z = controlmatrix[2][pProc->axis];
  973. #endif
  974. }
  975. else
  976. {
  977. // pull out the control column
  978. control.x = controlBone[0][pProc->axis];
  979. control.y = controlBone[1][pProc->axis];
  980. control.z = controlBone[2][pProc->axis];
  981. }
  982. Quaternion *q1, *q2, *q3;
  983. Vector *p1, *p2, *p3;
  984. // find axial control inputs
  985. float a1 = control.x;
  986. float a2 = control.y;
  987. float a3 = control.z;
  988. if (a1 >= 0)
  989. {
  990. q1 = &pProc->quat[0];
  991. p1 = &pProc->pos[0];
  992. }
  993. else
  994. {
  995. a1 = -a1;
  996. q1 = &pProc->quat[1];
  997. p1 = &pProc->pos[1];
  998. }
  999. if (a2 >= 0)
  1000. {
  1001. q2 = &pProc->quat[2];
  1002. p2 = &pProc->pos[2];
  1003. }
  1004. else
  1005. {
  1006. a2 = -a2;
  1007. q2 = &pProc->quat[3];
  1008. p2 = &pProc->pos[3];
  1009. }
  1010. if (a3 >= 0)
  1011. {
  1012. q3 = &pProc->quat[4];
  1013. p3 = &pProc->pos[4];
  1014. }
  1015. else
  1016. {
  1017. a3 = -a3;
  1018. q3 = &pProc->quat[5];
  1019. p3 = &pProc->pos[5];
  1020. }
  1021. // do a three-way blend
  1022. Vector p;
  1023. Quaternion v, tmp;
  1024. if (a1 + a2 > 0)
  1025. {
  1026. float t = 1.0 / (a1 + a2 + a3);
  1027. // FIXME: do a proper 3-way Quat blend!
  1028. QuaternionSlerp( *q2, *q1, a1 / (a1 + a2), tmp );
  1029. QuaternionSlerp( tmp, *q3, a3 * t, v );
  1030. VectorScale( *p1, a1 * t, p );
  1031. VectorMA( p, a2 * t, *p2, p );
  1032. VectorMA( p, a3 * t, *p3, p );
  1033. }
  1034. else
  1035. {
  1036. QuaternionSlerp( *q3, *q3, 0, v ); // ??? no quat copy?
  1037. p = *p3;
  1038. }
  1039. QuaternionMatrix( v, p, bonematrix );
  1040. ConcatTransforms (bonetoworld.GetBone( pbones[ibone].parent ), bonematrix, bonetoworld.GetBoneForWrite( ibone ));
  1041. }
  1042. //-----------------------------------------------------------------------------
  1043. // Purpose: Generate a procedural transformation based on how that another bones
  1044. // local transformation matches a set of target orientations.
  1045. //-----------------------------------------------------------------------------
  1046. void DoQuatInterpBone(
  1047. const mstudiobone_t *pbones,
  1048. int ibone,
  1049. CBoneAccessor &bonetoworld
  1050. )
  1051. {
  1052. BONE_PROFILE_FUNC();
  1053. matrix3x4a_t bonematrix;
  1054. Vector control;
  1055. mstudioquatinterpbone_t *pProc = (mstudioquatinterpbone_t *)pbones[ibone].pProcedure( );
  1056. if (pProc && pbones[pProc->control].parent != -1)
  1057. {
  1058. Quaternion src;
  1059. float weight[32];
  1060. float scale = 0.0;
  1061. Quaternion quat;
  1062. Vector pos;
  1063. matrix3x4a_t tmpmatrix;
  1064. matrix3x4a_t controlmatrix;
  1065. MatrixInvert( bonetoworld.GetBone( pbones[pProc->control].parent), tmpmatrix );
  1066. ConcatTransforms_Aligned( tmpmatrix, bonetoworld.GetBone( pProc->control ), controlmatrix );
  1067. MatrixAngles( controlmatrix, src, pos ); // FIXME: make a version without pos
  1068. int i;
  1069. for (i = 0; i < pProc->numtriggers; i++)
  1070. {
  1071. float dot = fabs( QuaternionDotProduct( pProc->pTrigger( i )->trigger, src ) );
  1072. // FIXME: a fast acos should be acceptable
  1073. dot = clamp( dot, -1, 1 );
  1074. weight[i] = 1 - (2 * acos( dot ) * pProc->pTrigger( i )->inv_tolerance );
  1075. weight[i] = MAX( 0, weight[i] );
  1076. scale += weight[i];
  1077. }
  1078. if (scale <= 0.001) // EPSILON?
  1079. {
  1080. AngleMatrix( RadianEuler(pProc->pTrigger( 0 )->quat), pProc->pTrigger( 0 )->pos, bonematrix );
  1081. ConcatTransforms ( bonetoworld.GetBone( pbones[ibone].parent ), bonematrix, bonetoworld.GetBoneForWrite( ibone ) );
  1082. return;
  1083. }
  1084. scale = 1.0 / scale;
  1085. quat.Init( 0, 0, 0, 0);
  1086. pos.Init( );
  1087. for (i = 0; i < pProc->numtriggers; i++)
  1088. {
  1089. if (weight[i])
  1090. {
  1091. float s = weight[i] * scale;
  1092. mstudioquatinterpinfo_t *pTrigger = pProc->pTrigger( i );
  1093. QuaternionAlign( pTrigger->quat, quat, quat );
  1094. quat.x = quat.x + s * pTrigger->quat.x;
  1095. quat.y = quat.y + s * pTrigger->quat.y;
  1096. quat.z = quat.z + s * pTrigger->quat.z;
  1097. quat.w = quat.w + s * pTrigger->quat.w;
  1098. pos.x = pos.x + s * pTrigger->pos.x;
  1099. pos.y = pos.y + s * pTrigger->pos.y;
  1100. pos.z = pos.z + s * pTrigger->pos.z;
  1101. }
  1102. }
  1103. Assert( QuaternionNormalize( quat ) != 0);
  1104. QuaternionMatrix( quat, pos, bonematrix );
  1105. }
  1106. ConcatTransforms_Aligned( bonetoworld.GetBone( pbones[ibone].parent ), bonematrix, bonetoworld.GetBoneForWrite( ibone ) );
  1107. }
  1108. /*
  1109. * This is for DoAimAtBone below, was just for testing, not needed in general
  1110. * but to turn it back on, uncomment this and the section in DoAimAtBone() below
  1111. *
  1112. static ConVar aim_constraint( "aim_constraint", "1", FCVAR_REPLICATED, "Toggle <aimconstraint> Helper Bones" );
  1113. */
  1114. //-----------------------------------------------------------------------------
  1115. // Purpose: Generate a procedural transformation so that one bone points at
  1116. // another point on the model
  1117. //-----------------------------------------------------------------------------
  1118. void DoAimAtBone(
  1119. const mstudiobone_t *pBones,
  1120. int iBone,
  1121. CBoneAccessor &bonetoworld,
  1122. const CStudioHdr *pStudioHdr
  1123. )
  1124. {
  1125. BONE_PROFILE_FUNC();
  1126. mstudioaimatbone_t *pProc = (mstudioaimatbone_t *)pBones[iBone].pProcedure();
  1127. if ( !pProc )
  1128. {
  1129. return;
  1130. }
  1131. /*
  1132. * Uncomment this if the ConVar above is uncommented
  1133. *
  1134. if ( !aim_constraint.GetBool() )
  1135. {
  1136. // If the aim constraint is turned off then just copy the parent transform
  1137. // plus the offset value
  1138. matrix3x4a_t boneToWorldSpace;
  1139. MatrixCopy ( bonetoworld.GetBone( pProc->parent ), boneToWorldSpace );
  1140. Vector boneWorldPosition;
  1141. VectorTransform( pProc->basepos, boneToWorldSpace, boneWorldPosition );
  1142. MatrixSetColumn( boneWorldPosition, 3, boneToWorldSpace );
  1143. MatrixCopy( boneToWorldSpace, bonetoworld.GetBoneForWrite( iBone ) );
  1144. return;
  1145. }
  1146. */
  1147. // The world matrix of the bone to change
  1148. matrix3x4a_t boneMatrix;
  1149. // Guaranteed to be unit length
  1150. const Vector &userAimVector( pProc->aimvector );
  1151. // Guaranteed to be unit length
  1152. const Vector &userUpVector( pProc->upvector );
  1153. // Get to get position of bone but also for up reference
  1154. matrix3x4a_t parentSpace;
  1155. MatrixCopy ( bonetoworld.GetBone( pProc->parent ), parentSpace );
  1156. // World space position of the bone to aim
  1157. Vector aimWorldPosition;
  1158. VectorTransform( pProc->basepos, parentSpace, aimWorldPosition );
  1159. // The worldspace matrix of the bone to aim at
  1160. matrix3x4a_t aimAtSpace;
  1161. if ( pStudioHdr )
  1162. {
  1163. // This means it's AIMATATTACH
  1164. const mstudioattachment_t &attachment( ((CStudioHdr *)pStudioHdr)->pAttachment( pProc->aim ) );
  1165. ConcatTransforms(
  1166. bonetoworld.GetBone( attachment.localbone ),
  1167. attachment.local,
  1168. aimAtSpace );
  1169. }
  1170. else
  1171. {
  1172. MatrixCopy( bonetoworld.GetBone( pProc->aim ), aimAtSpace );
  1173. }
  1174. Vector aimAtWorldPosition;
  1175. MatrixGetColumn( aimAtSpace, 3, aimAtWorldPosition );
  1176. // make sure the redundant parent info is correct
  1177. Assert( pProc->parent == pBones[iBone].parent );
  1178. // make sure the redundant position info is correct
  1179. Assert( pProc->basepos.DistToSqr( pBones[iBone].pos ) < 0.1 );
  1180. // The aim and up data is relative to this bone, not the parent bone
  1181. matrix3x4a_t bonematrix;
  1182. matrix3x4a_t boneLocalToWorld;
  1183. AngleMatrix( RadianEuler(pBones[iBone].quat), pProc->basepos, bonematrix );
  1184. ConcatTransforms_Aligned( bonetoworld.GetBone( pProc->parent ), bonematrix, boneLocalToWorld );
  1185. Vector aimVector;
  1186. VectorSubtract( aimAtWorldPosition, aimWorldPosition, aimVector );
  1187. VectorNormalizeFast( aimVector );
  1188. Vector axis;
  1189. CrossProduct( userAimVector, aimVector, axis );
  1190. VectorNormalizeFast( axis );
  1191. Assert( 1.0f - fabs( DotProduct( userAimVector, aimVector ) ) > FLT_EPSILON );
  1192. float angle( acosf( DotProduct( userAimVector, aimVector ) ) );
  1193. Quaternion aimRotation;
  1194. AxisAngleQuaternion( axis, RAD2DEG( angle ), aimRotation );
  1195. if ( ( 1.0f - fabs( DotProduct( userUpVector, userAimVector ) ) ) > FLT_EPSILON )
  1196. {
  1197. matrix3x4a_t aimRotationMatrix;
  1198. QuaternionMatrix( aimRotation, aimRotationMatrix );
  1199. Vector tmpV;
  1200. Vector tmp_pUp;
  1201. VectorRotate( userUpVector, aimRotationMatrix, tmp_pUp );
  1202. VectorScale( aimVector, DotProduct( aimVector, tmp_pUp ), tmpV );
  1203. Vector pUp;
  1204. VectorSubtract( tmp_pUp, tmpV, pUp );
  1205. VectorNormalizeFast( pUp );
  1206. Vector tmp_pParentUp;
  1207. VectorRotate( userUpVector, boneLocalToWorld, tmp_pParentUp );
  1208. VectorScale( aimVector, DotProduct( aimVector, tmp_pParentUp ), tmpV );
  1209. Vector pParentUp;
  1210. VectorSubtract( tmp_pParentUp, tmpV, pParentUp );
  1211. VectorNormalizeFast( pParentUp );
  1212. Quaternion upRotation;
  1213. //Assert( 1.0f - fabs( DotProduct( pUp, pParentUp ) ) > FLT_EPSILON );
  1214. if( 1.0f - fabs( DotProduct( pUp, pParentUp ) ) > FLT_EPSILON )
  1215. {
  1216. angle = acos( DotProduct( pUp, pParentUp ) );
  1217. CrossProduct( pUp, pParentUp, axis );
  1218. }
  1219. else
  1220. {
  1221. angle = 0;
  1222. axis = pUp;
  1223. }
  1224. VectorNormalizeFast( axis );
  1225. AxisAngleQuaternion( axis, RAD2DEG( angle ), upRotation );
  1226. Quaternion boneRotation;
  1227. QuaternionMult( upRotation, aimRotation, boneRotation );
  1228. QuaternionMatrix( boneRotation, aimWorldPosition, boneMatrix );
  1229. }
  1230. else
  1231. {
  1232. QuaternionMatrix( aimRotation, aimWorldPosition, boneMatrix );
  1233. }
  1234. MatrixCopy( boneMatrix, bonetoworld.GetBoneForWrite( iBone ) );
  1235. }
  1236. //-----------------------------------------------------------------------------
  1237. // Purpose: Run the twist bone constraint code
  1238. //-----------------------------------------------------------------------------
  1239. static ConVar anim_twistbones_enabled( "anim_twistbones_enabled", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "Enable procedural twist bones." );
  1240. void DoTwistBones(
  1241. const mstudiobone_t *pBones,
  1242. int iBone,
  1243. CBoneAccessor &bonetoworld,
  1244. const CStudioHdr *pStudioHdr )
  1245. {
  1246. BONE_PROFILE_FUNC();
  1247. mstudiotwistbone_t *pProc = ( mstudiotwistbone_t * )pBones[iBone].pProcedure();
  1248. if ( !pProc )
  1249. return;
  1250. matrix3x4a_t mTmp;
  1251. // Compute local space version of parent bone matrix
  1252. const matrix3x4a_t &mParentToWorld = bonetoworld.GetBone( pProc->m_nParentBone );
  1253. QuaternionAligned qParent;
  1254. const int nGrandParentBone = pBones[pProc->m_nParentBone].parent;
  1255. if ( nGrandParentBone >= 0 )
  1256. {
  1257. MatrixInvert( bonetoworld.GetBone( pBones[pProc->m_nParentBone].parent), mTmp );
  1258. matrix3x4a_t mParent;
  1259. ConcatTransforms_Aligned( mTmp, mParentToWorld, mParent );
  1260. MatrixQuaternion( mParent, qParent );
  1261. }
  1262. else
  1263. {
  1264. MatrixQuaternion( mParentToWorld, qParent );
  1265. }
  1266. // Compute local space version of child bone matrix
  1267. matrix3x4a_t mChild;
  1268. MatrixInvert( mParentToWorld, mTmp );
  1269. ConcatTransforms_Aligned( mTmp, bonetoworld.GetBone( pProc->m_nChildBone ), mChild );
  1270. float *pflWeights = ( float * )stackalloc( pProc->m_nTargetCount * sizeof( float ) );
  1271. Quaternion *pqTwistBases = ( Quaternion * )stackalloc( pProc->m_nTargetCount * sizeof( Quaternion ) );
  1272. Quaternion *pqTwists = ( Quaternion * )stackalloc( pProc->m_nTargetCount * sizeof( Quaternion ) );
  1273. for ( int i = 0; i < pProc->m_nTargetCount; ++i )
  1274. {
  1275. const mstudiotwistbonetarget_t *pTwistTarget = pProc->pTarget( i );
  1276. pflWeights[i] = pTwistTarget->m_flWeight;
  1277. pqTwistBases[i] = pTwistTarget->m_qBaseRotation;
  1278. }
  1279. V_memcpy( pqTwists, pqTwistBases, pProc->m_nTargetCount * sizeof( Quaternion ) );
  1280. if ( anim_twistbones_enabled.GetBool() )
  1281. ComputeTwistBones( pqTwists, pProc->m_nTargetCount, pProc->m_bInverse, pProc->m_vUpVector, qParent, mChild, pProc->m_qBaseInv, pflWeights, pqTwistBases );
  1282. for ( int i = 0; i < pProc->m_nTargetCount; ++i )
  1283. {
  1284. const mstudiotwistbonetarget_t *pTwistTarget = pProc->pTarget( i );
  1285. AngleMatrix( RadianEuler(pqTwists[i]), pTwistTarget->m_vBaseTranslate, mTmp );
  1286. ConcatTransforms_Aligned( mParentToWorld, mTmp, bonetoworld.GetBoneForWrite( pTwistTarget->m_nBone ) );
  1287. }
  1288. }
  1289. //-----------------------------------------------------------------------------
  1290. // Purpose:
  1291. //-----------------------------------------------------------------------------
  1292. bool CalcProceduralBone(
  1293. const CStudioHdr *pStudioHdr,
  1294. int iBone,
  1295. CBoneAccessor &bonetoworld
  1296. )
  1297. {
  1298. const mstudiobone_t *pbones = pStudioHdr->pBone( 0 );
  1299. if ( pStudioHdr->boneFlags( iBone ) & BONE_ALWAYS_PROCEDURAL )
  1300. {
  1301. switch( pbones[iBone].proctype )
  1302. {
  1303. case STUDIO_PROC_AXISINTERP:
  1304. DoAxisInterpBone( pbones, iBone, bonetoworld );
  1305. return true;
  1306. case STUDIO_PROC_QUATINTERP:
  1307. DoQuatInterpBone( pbones, iBone, bonetoworld );
  1308. return true;
  1309. case STUDIO_PROC_AIMATBONE:
  1310. DoAimAtBone( pbones, iBone, bonetoworld, NULL );
  1311. return true;
  1312. case STUDIO_PROC_AIMATATTACH:
  1313. DoAimAtBone( pbones, iBone, bonetoworld, pStudioHdr );
  1314. return true;
  1315. case STUDIO_PROC_TWIST_MASTER:
  1316. DoTwistBones( pbones, iBone, bonetoworld, pStudioHdr );
  1317. return true;
  1318. case STUDIO_PROC_TWIST_SLAVE:
  1319. // Twist bones are grouped because many twist boens tend to share
  1320. // a large amount of common computation
  1321. // There is one TWIST_MASTER per group and any number of TWIST_SLAVE
  1322. // TWIST_SLAVE data is computed when their corresponding TWIST_MASTER
  1323. // is computed, so they don't need any explicit computation
  1324. return true;
  1325. default:
  1326. return false;
  1327. }
  1328. }
  1329. return false;
  1330. }