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.

8238 lines
221 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // studiomdl.c: generates a studio .mdl file from a .qc script
  4. // models/<scriptname>.mdl.
  5. //
  6. // $NoKeywords: $
  7. //
  8. //===========================================================================//
  9. #pragma warning( disable : 4244 )
  10. #pragma warning( disable : 4237 )
  11. #pragma warning( disable : 4305 )
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <sys/stat.h>
  15. #include <math.h>
  16. #include <float.h>
  17. #include "cmdlib.h"
  18. #include "scriplib.h"
  19. #include "mathlib/mathlib.h"
  20. #include "studio.h"
  21. #include "studiomdl.h"
  22. #include "bone_setup.h"
  23. #include "tier1/strtools.h"
  24. #include "mathlib/vmatrix.h"
  25. #include "mdlobjects/dmeboneflexdriver.h"
  26. class CBoneRenderBounds
  27. {
  28. public:
  29. Vector m_Mins; // In bone space.
  30. Vector m_Maxs;
  31. };
  32. // this is computed once so render models and their physics hulls get translated by the same amount
  33. static Vector g_PropCenterOffset(0,0,0);
  34. //----------------------------------------------------------------------
  35. // underlay:
  36. // studiomdl : delta = new_anim * ( -1 * base_anim )
  37. // engine : result = (w * delta) * base_anim
  38. //
  39. // overlay
  40. //
  41. // studiomdl : delta = (-1 * base_anim ) * new_anim
  42. // engine : result = base_anim * (w * delta)
  43. //
  44. //----------------------------------------------------------------------
  45. void QuaternionSMAngles( float s, Quaternion const &p, Quaternion const &q, RadianEuler &angles )
  46. {
  47. Quaternion qt;
  48. QuaternionSM( s, p, q, qt );
  49. QuaternionAngles( qt, angles );
  50. }
  51. void QuaternionMAAngles( Quaternion const &p, float s, Quaternion const &q, RadianEuler &angles )
  52. {
  53. Quaternion qt;
  54. QuaternionMA( p, s, q, qt );
  55. QuaternionAngles( qt, angles );
  56. }
  57. // q = p * (-q * p)
  58. //-----------------------------------------------------------------------------
  59. // Purpose: subtract linear motion from root bone animations
  60. // fixup missing frames from looping animations
  61. // create "delta" animations
  62. //-----------------------------------------------------------------------------
  63. int g_rootIndex = 0;
  64. void buildAnimationWeights( void );
  65. void extractLinearMotion( s_animation_t *panim, int motiontype, int iStartFrame, int iEndFrame, int iSrcFrame, s_animation_t *pRefAnim, int iRefFrame /* , Vector pos, QAngle angles */ );
  66. void fixupMissingFrame( s_animation_t *panim );
  67. void realignLooping( s_animation_t *panim );
  68. void extractUnusedMotion( s_animation_t *panim );
  69. // TODO: psrc and pdest as terms are ambigious, replace with something better
  70. void setAnimationWeight( s_animation_t *panim, int index );
  71. void processMatch( s_animation_t *psrc, s_animation_t *pdest, int flags );
  72. void worldspaceBlend( s_animation_t *psrc, s_animation_t *pdest, int srcframe, int flags );
  73. void processAutoorigin( s_animation_t *psrc, s_animation_t *pdest, int flags, int srcframe, int destframe, int bone );
  74. void subtractBaseAnimations( s_animation_t *psrc, s_animation_t *pdest, int srcframe, int flags );
  75. void fixupLoopingDiscontinuities( s_animation_t *panim, int start, int end );
  76. void matchBlend( s_animation_t *pDestAnim, s_animation_t *pSrcAnimation, int iSrcFrame, int iDestFrame, int iPre, int iPost );
  77. void makeAngle( s_animation_t *panim, float angle );
  78. void fixupIKErrors( s_animation_t *panim, s_ikrule_t *pRule );
  79. void createDerivative( s_animation_t *panim, float scale );
  80. void clearAnimations( s_animation_t *panim );
  81. void counterRotateBone( s_animation_t *panim, int bone, QAngle target );
  82. void localHierarchy( s_animation_t *panim, char *pBonename, char *pParentname, int start, int peak, int tail, int end );
  83. void linearDelta( s_animation_t *psrc, s_animation_t *pdest, int srcframe, int flags );
  84. void splineDelta( s_animation_t *psrc, s_animation_t *pdest, int srcframe, int flags );
  85. void reencodeAnimation( s_animation_t *panim, int frameskip );
  86. void forceNumframes( s_animation_t *panim, int frames );
  87. void forceAnimationLoop( s_animation_t *panim );
  88. void solveBone( s_animation_t *panim, int iFrame, int iBone, matrix3x4_t* pBoneToWorld );
  89. void ClearModel (void)
  90. {
  91. }
  92. void processAnimations()
  93. {
  94. int i, j;
  95. // find global root bone.
  96. if ( strlen( rootname ) )
  97. {
  98. g_rootIndex = findGlobalBone( rootname );
  99. if (g_rootIndex == -1)
  100. g_rootIndex = 0;
  101. }
  102. buildAnimationWeights( );
  103. for (i = 0; i < g_numani; i++)
  104. {
  105. s_animation_t *panim = g_panimation[i];
  106. extractUnusedMotion( panim ); // FIXME: this should be part of LinearMotion()
  107. setAnimationWeight( panim, 0 );
  108. int startframe = 0;
  109. if (panim->fudgeloop)
  110. {
  111. fixupMissingFrame( panim );
  112. }
  113. for (j = 0; j < panim->numcmds; j++)
  114. {
  115. s_animcmd_t *pcmd = &panim->cmds[j];
  116. switch( pcmd->cmd )
  117. {
  118. case CMD_WEIGHTS:
  119. setAnimationWeight( panim, pcmd->u.weightlist.index );
  120. break;
  121. case CMD_SUBTRACT:
  122. panim->flags |= STUDIO_DELTA;
  123. subtractBaseAnimations( pcmd->u.subtract.ref, panim, pcmd->u.subtract.frame, pcmd->u.subtract.flags );
  124. break;
  125. case CMD_AO:
  126. {
  127. int bone = g_rootIndex;
  128. if (pcmd->u.ao.pBonename != NULL)
  129. {
  130. bone = findGlobalBone( pcmd->u.ao.pBonename );
  131. if (bone == -1)
  132. {
  133. MdlError("unable to find bone %s to alignbone\n", pcmd->u.ao.pBonename );
  134. }
  135. }
  136. processAutoorigin( pcmd->u.ao.ref, panim, pcmd->u.ao.motiontype, pcmd->u.ao.srcframe, pcmd->u.ao.destframe, bone );
  137. }
  138. break;
  139. case CMD_MATCH:
  140. processMatch( pcmd->u.match.ref, panim, false );
  141. break;
  142. case CMD_FIXUP:
  143. fixupLoopingDiscontinuities( panim, pcmd->u.fixuploop.start, pcmd->u.fixuploop.end );
  144. break;
  145. case CMD_ANGLE:
  146. makeAngle( panim, pcmd->u.angle.angle );
  147. break;
  148. case CMD_IKFIXUP:
  149. break;
  150. case CMD_IKRULE:
  151. // processed later
  152. break;
  153. case CMD_MOTION:
  154. {
  155. extractLinearMotion(
  156. panim,
  157. pcmd->u.motion.motiontype,
  158. startframe,
  159. pcmd->u.motion.iEndFrame,
  160. pcmd->u.motion.iEndFrame,
  161. panim,
  162. startframe );
  163. startframe = pcmd->u.motion.iEndFrame;
  164. }
  165. break;
  166. case CMD_REFMOTION:
  167. {
  168. extractLinearMotion(
  169. panim,
  170. pcmd->u.motion.motiontype,
  171. startframe,
  172. pcmd->u.motion.iEndFrame,
  173. pcmd->u.motion.iSrcFrame,
  174. pcmd->u.motion.pRefAnim,
  175. pcmd->u.motion.iRefFrame );
  176. startframe = pcmd->u.motion.iEndFrame;
  177. }
  178. break;
  179. case CMD_DERIVATIVE:
  180. {
  181. createDerivative(
  182. panim,
  183. pcmd->u.derivative.scale );
  184. }
  185. break;
  186. case CMD_NOANIMATION:
  187. {
  188. clearAnimations( panim );
  189. }
  190. break;
  191. case CMD_LINEARDELTA:
  192. {
  193. panim->flags |= STUDIO_DELTA;
  194. linearDelta( panim, panim, panim->numframes - 1, pcmd->u.linear.flags );
  195. }
  196. break;
  197. case CMD_COMPRESS:
  198. {
  199. reencodeAnimation( panim, pcmd->u.compress.frames );
  200. }
  201. break;
  202. case CMD_NUMFRAMES:
  203. {
  204. forceNumframes( panim, pcmd->u.numframes.frames );
  205. }
  206. break;
  207. case CMD_COUNTERROTATE:
  208. {
  209. int bone = findGlobalBone( pcmd->u.counterrotate.pBonename );
  210. if (bone != -1)
  211. {
  212. QAngle target;
  213. if (!pcmd->u.counterrotate.bHasTarget)
  214. {
  215. matrix3x4_t rootxform;
  216. matrix3x4_t defaultBoneToWorld;
  217. AngleMatrix( panim->rotation, rootxform );
  218. ConcatTransforms( rootxform, g_bonetable[bone].boneToPose, defaultBoneToWorld );
  219. MatrixAngles( defaultBoneToWorld, target );
  220. }
  221. else
  222. {
  223. target.Init( pcmd->u.counterrotate.targetAngle[0], pcmd->u.counterrotate.targetAngle[1], pcmd->u.counterrotate.targetAngle[2] );
  224. }
  225. counterRotateBone( panim, bone, target );
  226. }
  227. else
  228. {
  229. MdlError("unable to find bone %s to counterrotate\n", pcmd->u.counterrotate.pBonename );
  230. }
  231. }
  232. break;
  233. case CMD_WORLDSPACEBLEND:
  234. worldspaceBlend( pcmd->u.world.ref, panim, pcmd->u.world.startframe, pcmd->u.world.loops );
  235. break;
  236. case CMD_MATCHBLEND:
  237. matchBlend( panim, pcmd->u.match.ref, pcmd->u.match.srcframe, pcmd->u.match.destframe, pcmd->u.match.destpre, pcmd->u.match.destpost );
  238. break;
  239. case CMD_LOCALHIERARCHY:
  240. localHierarchy( panim, pcmd->u.localhierarchy.pBonename, pcmd->u.localhierarchy.pParentname, pcmd->u.localhierarchy.start, pcmd->u.localhierarchy.peak, pcmd->u.localhierarchy.tail, pcmd->u.localhierarchy.end );
  241. // localHierarchy( panim, char *pBonename, char *pParentname, int start, int peak, int tail, int end );
  242. break;
  243. }
  244. }
  245. if (panim->motiontype)
  246. {
  247. int lastframe;
  248. if (!(panim->flags & STUDIO_LOOPING) )
  249. {
  250. // roll back 0.2 seconds to try to prevent popping
  251. int frames = panim->fps * panim->motionrollback;
  252. lastframe = max( min( startframe + 1, panim->numframes - 1), panim->numframes - frames - 1 );
  253. //printf("%s : %d %d (%d)\n", panim->name, startframe, lastframe, panim->numframes - 1 );
  254. }
  255. else
  256. {
  257. lastframe = panim->numframes - 1;
  258. }
  259. extractLinearMotion( panim, panim->motiontype, startframe, lastframe, panim->numframes - 1, panim, startframe );
  260. startframe = panim->numframes - 1;
  261. }
  262. realignLooping( panim );
  263. forceAnimationLoop( panim );
  264. }
  265. // merge weightlists
  266. for (i = 0; i < g_sequence.Count(); i++)
  267. {
  268. int k, n;
  269. for (n = 0; n < g_numbones; n++)
  270. {
  271. g_sequence[i].weight[n] = 0.0;
  272. for (j = 0; j < g_sequence[i].groupsize[0]; j++)
  273. {
  274. for (k = 0; k < g_sequence[i].groupsize[1]; k++)
  275. {
  276. g_sequence[i].weight[n] = max( g_sequence[i].weight[n], g_sequence[i].panim[j][k]->weight[n] );
  277. }
  278. }
  279. }
  280. }
  281. }
  282. /*
  283. void lookupLinearMotion( s_animation_t *panim, int motiontype, int startframe, int endframe, Vector &p1, Vector &p2 )
  284. {
  285. Vector p0 = panim->sanim[startframe][g_rootIndex].pos;
  286. p2 = panim->sanim[endframe][g_rootIndex].pos[0];
  287. float fFrame = (startframe + endframe) / 2.0;
  288. int iFrame = (int)fFrame;
  289. float s = fFrame - iFrame;
  290. p1 = panim->sanim[iFrame][g_rootIndex].pos * (1 - s) + panim->sanim[iFrame+1][g_rootIndex].pos * s;
  291. }
  292. */
  293. // 0.375 * v1 + 0.125 * v2 - d2 = 0.5 * v1 + 0.5 * v2 - d3;
  294. // 0.375 * v1 - 0.5 * v1 = 0.5 * v2 - d3 - 0.125 * v2 + d2;
  295. // 0.375 * v1 - 0.5 * v1 = 0.5 * v2 - d3 - 0.125 * v2 + d2;
  296. // -0.125 * v1 = 0.375 * v2 - d3 + d2;
  297. // v1 = (0.375 * v2 - d3 + d2) / -0.125;
  298. // -3 * (0.375 * v2 - d3 + d2) + 0.125 * v2 - d2 = 0
  299. // -3 * (0.375 * v2 - d3 + d2) + 0.125 * v2 - d2 = 0
  300. // -1 * v2 + 3 * d3 - 3 * d2 - d2 = 0
  301. // v2 = 3 * d3 - 4 * d2
  302. // 0.5 * v1 + 0.5 * v2 - d3
  303. // -4 * (0.375 * v2 - d3 + d2) + 0.5 * v2 - d3 = 0
  304. // -1.5 * v2 + 4 * d3 - 4 * d2 + 0.5 * v2 - d3 = 0
  305. // v2 = 4 * d3 - 4 * d2 - d3
  306. // v2 = 3 * d3 - 4 * d2
  307. // 0.5 * v1 + 0.5 * (3 * d3 - 4 * d2) - d3 = 0
  308. // v1 + (3 * d3 - 4 * d2) - 2 * d3 = 0
  309. // v1 = -3 * d3 + 4 * d2 + 2 * d3
  310. // v1 = -1 * d3 + 4 * d2
  311. void ConvertToAnimLocal( s_animation_t *panim, Vector &pos, QAngle &angles )
  312. {
  313. matrix3x4_t bonematrix;
  314. matrix3x4_t adjmatrix;
  315. // convert explicit position/angle into animation relative values
  316. AngleMatrix( angles, pos, bonematrix );
  317. AngleMatrix( panim->rotation, panim->adjust, adjmatrix );
  318. MatrixInvert( adjmatrix, adjmatrix );
  319. ConcatTransforms( adjmatrix, bonematrix, bonematrix );
  320. MatrixAngles( bonematrix, angles, pos );
  321. // pos = pos * panim->scale;
  322. }
  323. //-----------------------------------------------------------------------------
  324. // Purpose: find the linear movement/rotation between two frames, subtract that
  325. // out of the animation and add it back on as a "piecewise movement" command
  326. // panim - current animation
  327. // motiontype - what to extract
  328. // iStartFrame - first frame to apply motion over
  329. // iEndFrame - last end frame to apply motion over
  330. // iSrcFrame - match refFrame against what frame of the current animation
  331. // pRefAnim - reference animtion
  332. // iRefFrame - frame of reference animation to match
  333. //-----------------------------------------------------------------------------
  334. void extractLinearMotion( s_animation_t *panim, int motiontype, int iStartFrame, int iEndFrame, int iSrcFrame, s_animation_t *pRefAnim, int iRefFrame /* , Vector pos, QAngle angles */ )
  335. {
  336. int j, k;
  337. matrix3x4_t adjmatrix;
  338. // Can't extract motion with only 1 frame of animation!
  339. if ( panim->numframes <= 1 )
  340. {
  341. MdlError( "Can't extract motion from sequence %s (%s). Check your QC options!\n", panim->name, panim->filename );
  342. }
  343. if (panim->numpiecewisekeys >= MAXSTUDIOMOVEKEYS)
  344. {
  345. MdlError( "Too many piecewise movement keys in %s (%s)\n", panim->name, panim->filename );
  346. }
  347. if (iEndFrame > panim->numframes - 1)
  348. iEndFrame = panim->numframes - 1;
  349. if (iSrcFrame > panim->numframes - 1)
  350. iSrcFrame = panim->numframes - 1;
  351. if (iStartFrame >= iEndFrame)
  352. {
  353. MdlWarning("Motion extraction ignored, no frames remaining in %s (%s)\n", panim->name, panim->filename );
  354. return;
  355. }
  356. float fFrame = (iStartFrame + iSrcFrame) / 2.0;
  357. int iMidFrame = (int)fFrame;
  358. float s = fFrame - iMidFrame;
  359. // find rotation
  360. RadianEuler rot( 0, 0, 0 );
  361. if (motiontype & (STUDIO_LXR | STUDIO_LYR | STUDIO_LZR))
  362. {
  363. Quaternion q0;
  364. Quaternion q1;
  365. Quaternion q2;
  366. AngleQuaternion( pRefAnim->sanim[iRefFrame][g_rootIndex].rot, q0 );
  367. AngleQuaternion( panim->sanim[iMidFrame][g_rootIndex].rot, q1 ); // only used for rotation checking
  368. AngleQuaternion( panim->sanim[iSrcFrame][g_rootIndex].rot, q2 );
  369. Quaternion deltaQ1;
  370. QuaternionMA( q1, -1, q0, deltaQ1 );
  371. Quaternion deltaQ2;
  372. QuaternionMA( q2, -1, q0, deltaQ2 );
  373. // FIXME: this is still wrong, but it should be slightly more robust
  374. RadianEuler a3;
  375. if (motiontype & STUDIO_LXR)
  376. {
  377. Quaternion q4;
  378. q4.Init( deltaQ2.x, 0, 0, deltaQ2.w );
  379. QuaternionNormalize( q4 );
  380. QuaternionAngles( q4, a3 );
  381. rot.x = a3.x;
  382. }
  383. if (motiontype & STUDIO_LYR)
  384. {
  385. Quaternion q4;
  386. q4.Init( 0, deltaQ2.y, 0, deltaQ2.w );
  387. QuaternionNormalize( q4 );
  388. QuaternionAngles( q4, a3 );
  389. rot.y = a3.y;
  390. }
  391. if (motiontype & STUDIO_LZR)
  392. {
  393. Quaternion q4;
  394. q4.Init( 0, 0, deltaQ2.z, deltaQ2.w );
  395. QuaternionNormalize( q4 );
  396. QuaternionAngles( q4, a3 );
  397. // check for possible rotations >180 degrees by looking at the
  398. // halfway point and seeing if it's rotating a different direction
  399. // than the shortest path to the end point
  400. Quaternion q5;
  401. RadianEuler a5;
  402. q5.Init( 0, 0, deltaQ1.z, deltaQ1.w );
  403. QuaternionNormalize( q5 );
  404. QuaternionAngles( q5, a5 );
  405. if (a3.z > M_PI) a5.z -= 2*M_PI;
  406. if (a3.z < -M_PI) a5.z += 2*M_PI;
  407. if (a5.z > M_PI) a5.z -= 2*M_PI;
  408. if (a5.z < -M_PI) a5.z += 2*M_PI;
  409. if (a5.z > M_PI/4 && a3.z < 0)
  410. {
  411. a3.z += 2*M_PI;
  412. }
  413. if (a5.z < -M_PI/4 && a3.z > 0)
  414. {
  415. a3.z -= 2*M_PI;
  416. }
  417. rot.z = a3.z;
  418. }
  419. }
  420. // find movement
  421. Vector p0;
  422. AngleMatrix(rot, adjmatrix );
  423. VectorRotate( pRefAnim->sanim[iRefFrame][g_rootIndex].pos, adjmatrix, p0 );
  424. Vector p2 = panim->sanim[iSrcFrame][g_rootIndex].pos;
  425. Vector p1 = panim->sanim[iMidFrame][g_rootIndex].pos * (1 - s) + panim->sanim[iMidFrame+1][g_rootIndex].pos * s;
  426. // ConvertToAnimLocal( panim, pos, angles ); // FIXME: unused
  427. p2 = p2 - p0;
  428. p1 = p1 - p0;
  429. if (!(motiontype & STUDIO_LX)) { p2.x = 0; p1.x = 0; };
  430. if (!(motiontype & STUDIO_LY)) { p2.y = 0; p1.y = 0; };
  431. if (!(motiontype & STUDIO_LZ)) { p2.z = 0; p1.z = 0; };
  432. // printf("%s %.1f %.1f %.1f\n", g_bonetable[g_rootIndex].name, p2.x, p2.y, p2.z );
  433. float d1 = p1.Length();
  434. float d2 = p2.Length();
  435. float v0 = -1 * d2 + 4 * d1;
  436. float v1 = 3 * d2 - 4 * d1;
  437. if ( g_verbose )
  438. {
  439. printf("%s : %d - %d : %.1f %.1f %.1f\n", panim->name, iStartFrame, iEndFrame, p2.x, p2.y, RAD2DEG( rot[2] ) );
  440. }
  441. int numframes = iEndFrame - iStartFrame + 1;
  442. if (numframes < 1)
  443. return;
  444. float n = numframes - 1;
  445. //printf("%f %f : ", v0, v1 );
  446. if (motiontype & STUDIO_LINEAR)
  447. {
  448. v0 = v1 = p2.Length();
  449. }
  450. else if (v0 < 0.0f)
  451. {
  452. v0 = 0.0;
  453. v1 = p2.Length() * 2.0;
  454. }
  455. else if (v1 < 0.0)
  456. {
  457. v0 = p2.Length() * 2.0;
  458. v1 = 0.0;
  459. }
  460. else if ((v0+v1) > 0.01 && (fabs(v0-v1) / (v0+v1)) < 0.2)
  461. {
  462. // if they're within 10% of each other, assum no acceleration
  463. v0 = v1 = p2.Length();
  464. }
  465. //printf("%f %f\n", v0, v1 );
  466. Vector v = p2;
  467. VectorNormalize( v );
  468. Vector A, B, C;
  469. if (motiontype & STUDIO_QUADRATIC_MOTION)
  470. {
  471. SolveInverseQuadratic( 0, 0, 0.5, p1.x, 1.0, p2.x, A.x, B.x, C.x );
  472. SolveInverseQuadratic( 0, 0, 0.5, p1.y, 1.0, p2.y, A.y, B.y, C.y );
  473. SolveInverseQuadratic( 0, 0, 0.5, p1.z, 1.0, p2.z, A.z, B.z, C.z );
  474. }
  475. Vector adjpos;
  476. RadianEuler adjangle;
  477. matrix3x4_t bonematrix;
  478. for (j = 0; j < numframes; j++)
  479. {
  480. float t = (j / n);
  481. if (motiontype & STUDIO_QUADRATIC_MOTION)
  482. {
  483. adjpos.x = t * t * A.x + t * B.x + C.x;
  484. adjpos.y = t * t * A.y + t * B.y + C.y;
  485. adjpos.z = t * t * A.z + t * B.z + C.z;
  486. }
  487. else
  488. {
  489. VectorScale( v, v0 * t + 0.5 * (v1 - v0) * t * t, adjpos );
  490. }
  491. VectorScale( rot, t, adjangle );
  492. AngleMatrix( adjangle, adjpos, adjmatrix );
  493. MatrixInvert( adjmatrix, adjmatrix );
  494. for (k = 0; k < g_numbones; k++)
  495. {
  496. if (g_bonetable[k].parent == -1)
  497. {
  498. // printf(" %.1f %.1f %.1f : ", adjpos[0], adjpos[1], RAD2DEG( adjangle[2] ));
  499. // printf(" %.1f %.1f %.1f\n", adjpos[0], adjpos[1], adjpos[2] );
  500. AngleMatrix( panim->sanim[j+iStartFrame][k].rot, panim->sanim[j+iStartFrame][k].pos, bonematrix );
  501. ConcatTransforms( adjmatrix, bonematrix, bonematrix );
  502. MatrixAngles( bonematrix, panim->sanim[j+iStartFrame][k].rot, panim->sanim[j+iStartFrame][k].pos );
  503. // printf("%d : %.1f %.1f %.1f\n", j, panim->sanim[j+iStartFrame][k].pos.x, panim->sanim[j+iStartFrame][k].pos.y, RAD2DEG( panim->sanim[j+iStartFrame][k].rot.z ) );
  504. }
  505. }
  506. }
  507. for (; j+iStartFrame < panim->numframes; j++)
  508. {
  509. for (k = 0; k < g_numbones; k++)
  510. {
  511. if (g_bonetable[k].parent == -1)
  512. {
  513. AngleMatrix( panim->sanim[j+iStartFrame][k].rot, panim->sanim[j+iStartFrame][k].pos, bonematrix );
  514. ConcatTransforms( adjmatrix, bonematrix, bonematrix );
  515. MatrixAngles( bonematrix, panim->sanim[j+iStartFrame][k].rot, panim->sanim[j+iStartFrame][k].pos );
  516. }
  517. }
  518. }
  519. // create piecewise motion paths
  520. s_linearmove_t *pmove = &panim->piecewisemove[panim->numpiecewisekeys++];
  521. pmove->endframe = iEndFrame;
  522. pmove->flags = motiontype;
  523. // concatinate xforms
  524. if (panim->numpiecewisekeys > 1)
  525. {
  526. AngleMatrix( adjangle, adjpos, bonematrix );
  527. AngleMatrix( pmove[-1].rot, pmove[-1].pos, adjmatrix );
  528. ConcatTransforms( adjmatrix, bonematrix, bonematrix );
  529. MatrixAngles( bonematrix, pmove[0].rot, pmove[0].pos );
  530. pmove->vector = pmove[0].pos - pmove[-1].pos;
  531. }
  532. else
  533. {
  534. VectorCopy( adjpos, pmove[0].pos );
  535. VectorCopy( adjangle, pmove[0].rot );
  536. pmove->vector = pmove[0].pos;
  537. }
  538. VectorNormalize( pmove->vector );
  539. // printf("%d : %.1f %.1f %.1f\n", iEndFrame, pmove[0].pos.x, pmove[0].pos.y, RAD2DEG( pmove[0].rot.z ) );
  540. pmove->v0 = v0;
  541. pmove->v1 = v1;
  542. }
  543. //-----------------------------------------------------------------------------
  544. // Purpose: process the "piecewise movement" commands and return where the animation
  545. // would move to on a given frame (assuming frame 0 is at the origin)
  546. //-----------------------------------------------------------------------------
  547. Vector calcPosition( s_animation_t *panim, int iFrame )
  548. {
  549. Vector vecPos;
  550. vecPos.Init();
  551. if (panim->numpiecewisekeys == 0)
  552. return vecPos;
  553. if (panim->numframes == 1)
  554. return vecPos;
  555. int iLoops = 0;
  556. while (iFrame >= (panim->numframes - 1))
  557. {
  558. iLoops++;
  559. iFrame = iFrame - (panim->numframes - 1);
  560. }
  561. float prevframe = 0.0f;
  562. for (int i = 0; i < panim->numpiecewisekeys; i++)
  563. {
  564. s_linearmove_t *pmove = &panim->piecewisemove[i];
  565. if (pmove->endframe >= iFrame)
  566. {
  567. float f = (iFrame - prevframe) / (pmove->endframe - prevframe);
  568. float d = pmove->v0 * f + 0.5 * (pmove->v1 - pmove->v0) * f * f;
  569. vecPos = vecPos + d * pmove->vector;
  570. if (iLoops != 0)
  571. {
  572. s_linearmove_t *pmove = &panim->piecewisemove[panim->numpiecewisekeys - 1];
  573. vecPos = vecPos + iLoops * pmove->pos;
  574. }
  575. return vecPos;
  576. }
  577. else
  578. {
  579. prevframe = pmove->endframe;
  580. vecPos = pmove->pos;
  581. }
  582. }
  583. return vecPos;
  584. }
  585. //-----------------------------------------------------------------------------
  586. // Purpose: calculate how far an animation travels between two frames
  587. //-----------------------------------------------------------------------------
  588. Vector calcMovement( s_animation_t *panim, int iFrom, int iTo )
  589. {
  590. Vector p1 = calcPosition( panim, iFrom );
  591. Vector p2 = calcPosition( panim, iTo );
  592. return p2 - p1;
  593. }
  594. #if 0
  595. // FIXME: add in correct motion!!!
  596. int iFrame = pRule->peak - pRule->start - k;
  597. if (pRule->start + k > panim->numframes - 1)
  598. {
  599. iFrame = iFrame + 1;
  600. }
  601. Vector pos = footfall;
  602. if (panim->numframes > 1)
  603. pos = pos + panim->piecewisemove[0].pos * (iFrame) / (panim->numframes - 1.0f);
  604. #endif
  605. //-----------------------------------------------------------------------------
  606. // Purpose: try to calculate a "missing" frame of animation, i.e the overlapping frame
  607. //-----------------------------------------------------------------------------
  608. void fixupMissingFrame( s_animation_t *panim )
  609. {
  610. // the animations DIDN'T have the end frame the same as the start frame, so fudge it
  611. int size = g_numbones * sizeof( s_bone_t );
  612. int j = panim->numframes;
  613. float scale = 1 / (j - 1.0f);
  614. panim->sanim[j] = (s_bone_t *)kalloc( 1, size );
  615. Vector deltapos;
  616. for (int k = 0; k < g_numbones; k++)
  617. {
  618. VectorSubtract( panim->sanim[j-1][k].pos, panim->sanim[0][k].pos, deltapos );
  619. VectorMA( panim->sanim[j-1][k].pos, scale, deltapos, panim->sanim[j][k].pos );
  620. VectorCopy( panim->sanim[0][k].rot, panim->sanim[j][k].rot );
  621. }
  622. panim->numframes = j + 1;
  623. }
  624. //-----------------------------------------------------------------------------
  625. // Purpose: shift the frames of the animation so that it starts on the desired frame
  626. //-----------------------------------------------------------------------------
  627. void realignLooping( s_animation_t *panim )
  628. {
  629. int j, k;
  630. // realign looping animations
  631. if (panim->numframes > 1 && panim->looprestart)
  632. {
  633. if (panim->looprestart >= panim->numframes)
  634. {
  635. MdlError( "loopstart (%d) out of range for animation %s (%d)", panim->looprestart, panim->name, panim->numframes );
  636. }
  637. for (k = 0; k < g_numbones; k++)
  638. {
  639. int n;
  640. Vector shiftpos[MAXSTUDIOANIMFRAMES];
  641. RadianEuler shiftrot[MAXSTUDIOANIMFRAMES];
  642. // printf("%f %f %f\n", motion[0], motion[1], motion[2] );
  643. for (j = 0; j < panim->numframes - 1; j++)
  644. {
  645. n = (j + panim->looprestart) % (panim->numframes - 1);
  646. VectorCopy( panim->sanim[n][k].pos, shiftpos[j] );
  647. VectorCopy( panim->sanim[n][k].rot, shiftrot[j] );
  648. }
  649. n = panim->looprestart;
  650. j = panim->numframes - 1;
  651. VectorCopy( panim->sanim[n][k].pos, shiftpos[j] );
  652. VectorCopy( panim->sanim[n][k].rot, shiftrot[j] );
  653. for (j = 0; j < panim->numframes; j++)
  654. {
  655. VectorCopy( shiftpos[j], panim->sanim[j][k].pos );
  656. VectorCopy( shiftrot[j], panim->sanim[j][k].rot );
  657. }
  658. }
  659. }
  660. }
  661. void extractUnusedMotion( s_animation_t *panim )
  662. {
  663. int j, k;
  664. int type = panim->motiontype;
  665. for (k = 0; k < g_numbones; k++)
  666. {
  667. if (g_bonetable[k].parent == -1)
  668. {
  669. float motion[6];
  670. motion[0] = panim->sanim[0][k].pos[0];
  671. motion[1] = panim->sanim[0][k].pos[1];
  672. motion[2] = panim->sanim[0][k].pos[2];
  673. motion[3] = panim->sanim[0][k].rot[0];
  674. motion[4] = panim->sanim[0][k].rot[1];
  675. motion[5] = panim->sanim[0][k].rot[2];
  676. for (j = 0; j < panim->numframes; j++)
  677. {
  678. if (type & STUDIO_X)
  679. panim->sanim[j][k].pos[0] = motion[0];
  680. if (type & STUDIO_Y)
  681. panim->sanim[j][k].pos[1] = motion[1];
  682. if (type & STUDIO_Z)
  683. panim->sanim[j][k].pos[2] = motion[2];
  684. if (type & STUDIO_XR)
  685. panim->sanim[j][k].rot[0] = motion[3];
  686. if (type & STUDIO_YR)
  687. panim->sanim[j][k].rot[1] = motion[4];
  688. if (type & STUDIO_ZR)
  689. panim->sanim[j][k].rot[2] = motion[5];
  690. }
  691. }
  692. }
  693. }
  694. //-----------------------------------------------------------------------------
  695. // Purpose: find the difference between the src and dest animations, then add that
  696. // difference to all the frames of the dest animation.
  697. //-----------------------------------------------------------------------------
  698. void processMatch( s_animation_t *psrc, s_animation_t *pdest, int flags )
  699. {
  700. int j, k;
  701. // process "match"
  702. Vector delta_pos[MAXSTUDIOSRCBONES];
  703. Quaternion delta_q[MAXSTUDIOSRCBONES];
  704. for (k = 0; k < g_numbones; k++)
  705. {
  706. if (flags)
  707. VectorSubtract( psrc->sanim[0][k].pos, pdest->sanim[0][k].pos, delta_pos[k] );
  708. QuaternionSM( -1, pdest->sanim[0][k].rot, psrc->sanim[0][k].rot, delta_q[k] );
  709. }
  710. // printf("%.2f %.2f %.2f\n", adj.x, adj.y, adj.z );
  711. for (j = 0; j < pdest->numframes; j++)
  712. {
  713. for (k = 0; k < g_numbones; k++)
  714. {
  715. if (pdest->weight[k] > 0)
  716. {
  717. if (flags)
  718. VectorAdd( pdest->sanim[j][k].pos, delta_pos[k], pdest->sanim[j][k].pos );
  719. QuaternionMAAngles( pdest->sanim[j][k].rot, 1.0, delta_q[k], pdest->sanim[j][k].rot );
  720. }
  721. }
  722. }
  723. }
  724. //-----------------------------------------------------------------------------
  725. // Purpose: blend the psrc animation overtop the pdest animation, but blend the
  726. // quaternions in world space instead of parent bone space.
  727. // Also, blend bone lengths, but only for non root animations.
  728. //-----------------------------------------------------------------------------
  729. void worldspaceBlend( s_animation_t *psrc, s_animation_t *pdest, int srcframe, int flags )
  730. {
  731. int j, k, n;
  732. // process "match"
  733. Quaternion srcQ[MAXSTUDIOSRCBONES];
  734. Vector srcPos[MAXSTUDIOSRCBONES];
  735. Vector tmp;
  736. matrix3x4_t srcBoneToWorld[MAXSTUDIOBONES];
  737. matrix3x4_t destBoneToWorld[MAXSTUDIOBONES];
  738. if (!flags)
  739. {
  740. CalcBoneTransforms( psrc, srcframe, srcBoneToWorld );
  741. for (k = 0; k < g_numbones; k++)
  742. {
  743. MatrixAngles( srcBoneToWorld[k], srcQ[k], tmp );
  744. srcPos[k] = psrc->sanim[srcframe][k].pos;
  745. }
  746. }
  747. Quaternion targetQ, destQ;
  748. // printf("%.2f %.2f %.2f\n", adj.x, adj.y, adj.z );
  749. for (j = 0; j < pdest->numframes; j++)
  750. {
  751. if (flags)
  752. {
  753. // pull from a looping source
  754. float flCycle = (float)j / (pdest->numframes - 1);
  755. flCycle += (float)srcframe / (psrc->numframes - 1);
  756. CalcBoneTransformsCycle( psrc, psrc, flCycle, srcBoneToWorld );
  757. for (k = 0; k < g_numbones; k++)
  758. {
  759. MatrixAngles( srcBoneToWorld[k], srcQ[k], tmp );
  760. n = g_bonetable[k].parent;
  761. if (n == -1)
  762. {
  763. MatrixPosition( srcBoneToWorld[k], srcPos[k] );
  764. }
  765. else
  766. {
  767. matrix3x4_t worldToBone;
  768. MatrixInvert( srcBoneToWorld[n], worldToBone );
  769. matrix3x4_t local;
  770. ConcatTransforms( worldToBone, srcBoneToWorld[k], local );
  771. MatrixPosition( local, srcPos[k] );
  772. }
  773. }
  774. }
  775. CalcBoneTransforms( pdest, j, destBoneToWorld );
  776. for (k = 0; k < g_numbones; k++)
  777. {
  778. if (pdest->weight[k] > 0)
  779. {
  780. // blend the boneToWorld transforms in world space
  781. MatrixAngles( destBoneToWorld[k], destQ, tmp );
  782. QuaternionSlerp( destQ, srcQ[k], pdest->weight[k], targetQ );
  783. AngleMatrix( targetQ, tmp, destBoneToWorld[k] );
  784. }
  785. // back solve
  786. n = g_bonetable[k].parent;
  787. if (n == -1)
  788. {
  789. MatrixAngles( destBoneToWorld[k], pdest->sanim[j][k].rot, tmp );
  790. // FIXME: it's not clear if this should blend position or not....it'd be
  791. // better if weight lists could do quat and pos independently.
  792. }
  793. else
  794. {
  795. matrix3x4_t worldToBone;
  796. MatrixInvert( destBoneToWorld[n], worldToBone );
  797. matrix3x4_t local;
  798. ConcatTransforms( worldToBone, destBoneToWorld[k], local );
  799. MatrixAngles( local, pdest->sanim[j][k].rot, tmp );
  800. // blend bone lengths (local space)
  801. pdest->sanim[j][k].pos = Lerp( pdest->posweight[k], pdest->sanim[j][k].pos, srcPos[k] );
  802. }
  803. }
  804. }
  805. }
  806. //-----------------------------------------------------------------------------
  807. // Purpose: match one animations position/orientation to another animations position/orientation
  808. //-----------------------------------------------------------------------------
  809. void processAutoorigin( s_animation_t *psrc, s_animation_t *pdest, int motiontype, int srcframe, int destframe, int bone )
  810. {
  811. int j, k;
  812. matrix3x4_t adjmatrix;
  813. matrix3x4_t srcBoneToWorld[MAXSTUDIOBONES];
  814. matrix3x4_t destBoneToWorld[MAXSTUDIOBONES];
  815. CalcBoneTransforms( psrc, srcframe, srcBoneToWorld );
  816. CalcBoneTransforms( pdest, destframe, destBoneToWorld );
  817. // find rotation
  818. RadianEuler rot( 0, 0, 0 );
  819. Quaternion q0;
  820. Quaternion q2;
  821. Vector srcPos;
  822. Vector destPos;
  823. MatrixAngles( srcBoneToWorld[bone], q0, srcPos );
  824. MatrixAngles( destBoneToWorld[bone], q2, destPos );
  825. if (motiontype & (STUDIO_LXR | STUDIO_LYR | STUDIO_LZR | STUDIO_XR | STUDIO_YR | STUDIO_ZR))
  826. {
  827. Quaternion deltaQ2;
  828. QuaternionMA( q2, -1, q0, deltaQ2 );
  829. RadianEuler a3;
  830. if (motiontype & (STUDIO_LXR | STUDIO_XR))
  831. {
  832. Quaternion q4;
  833. q4.Init( deltaQ2.x, 0, 0, deltaQ2.w );
  834. QuaternionNormalize( q4 );
  835. QuaternionAngles( q4, a3 );
  836. rot.x = a3.x;
  837. }
  838. if (motiontype & (STUDIO_LYR | STUDIO_YR))
  839. {
  840. Quaternion q4;
  841. q4.Init( 0, deltaQ2.y, 0, deltaQ2.w );
  842. QuaternionNormalize( q4 );
  843. QuaternionAngles( q4, a3 );
  844. rot.y = a3.y;
  845. }
  846. if (motiontype & (STUDIO_LZR | STUDIO_ZR))
  847. {
  848. Quaternion q4;
  849. q4.Init( 0, 0, deltaQ2.z, deltaQ2.w );
  850. QuaternionNormalize( q4 );
  851. QuaternionAngles( q4, a3 );
  852. rot.z = a3.z;
  853. }
  854. if ((motiontype & STUDIO_XR) && (motiontype & STUDIO_YR) && (motiontype & STUDIO_ZR))
  855. {
  856. QuaternionAngles( deltaQ2, rot );
  857. }
  858. }
  859. // find movement
  860. Vector p0 = srcPos;
  861. Vector p2;
  862. AngleMatrix(rot, adjmatrix );
  863. MatrixInvert( adjmatrix, adjmatrix );
  864. VectorRotate( destPos, adjmatrix, p2 );
  865. Vector adj = p0 - p2;
  866. if (!(motiontype & (STUDIO_X | STUDIO_LX)))
  867. adj.x = 0;
  868. if (!(motiontype & (STUDIO_Y | STUDIO_LY)))
  869. adj.y = 0;
  870. if (!(motiontype & (STUDIO_Z | STUDIO_LZ)))
  871. adj.z = 0;
  872. PositionMatrix( adj, adjmatrix );
  873. if (g_verbose && bone != g_rootIndex)
  874. {
  875. printf("%s aligning to %s - %.2f %.2f %.2f\n", pdest->name, g_bonetable[bone].name, adj.x, adj.y, adj.z );
  876. }
  877. for (k = 0; k < g_numbones; k++)
  878. {
  879. if (g_bonetable[k].parent == -1)
  880. {
  881. for (j = 0; j < pdest->numframes; j++)
  882. {
  883. matrix3x4_t bonematrix;
  884. AngleMatrix( pdest->sanim[j][k].rot, pdest->sanim[j][k].pos, bonematrix );
  885. ConcatTransforms( adjmatrix, bonematrix, bonematrix );
  886. MatrixAngles( bonematrix, pdest->sanim[j][k].rot, pdest->sanim[j][k].pos );
  887. }
  888. }
  889. }
  890. }
  891. //-----------------------------------------------------------------------------
  892. // Purpose: subtract one animaiton from animation to create an animation of the "difference"
  893. //-----------------------------------------------------------------------------
  894. void subtractBaseAnimations( s_animation_t *psrc, s_animation_t *pdest, int srcframe, int flags )
  895. {
  896. int j, k;
  897. // create delta animations
  898. s_bone_t src[MAXSTUDIOSRCBONES];
  899. if (srcframe >= psrc->numframes)
  900. {
  901. MdlError( "subtract frame %d out of range for %s\n", srcframe, psrc->name );
  902. }
  903. for (k = 0; k < g_numbones; k++)
  904. {
  905. VectorCopy( psrc->sanim[srcframe][k].pos, src[k].pos );
  906. VectorCopy( psrc->sanim[srcframe][k].rot, src[k].rot );
  907. }
  908. for (k = 0; k < g_numbones; k++)
  909. {
  910. for (j = 0; j < pdest->numframes; j++)
  911. {
  912. if (pdest->weight[k] > 0)
  913. {
  914. /*
  915. printf("%2d : %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
  916. k,
  917. src[k].pos[0], src[k].pos[1], src[k].pos[2],
  918. src[k].rot[0], src[k].rot[1], src[k].rot[2] );
  919. printf(" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
  920. RAD2DEG(pdest->sanim[j][k].pos[0]), RAD2DEG(pdest->sanim[j][k].pos[1]), RAD2DEG(pdest->sanim[j][k].pos[2]),
  921. RAD2DEG(pdest->sanim[j][k].rot[0]), RAD2DEG(pdest->sanim[j][k].rot[1]), RAD2DEG(pdest->sanim[j][k].rot[2]) );
  922. */
  923. // calc differences between two rotations
  924. if (flags & STUDIO_POST)
  925. {
  926. // find pdest in src's reference frame
  927. QuaternionSMAngles( -1, src[k].rot, pdest->sanim[j][k].rot, pdest->sanim[j][k].rot );
  928. VectorSubtract( pdest->sanim[j][k].pos, src[k].pos, pdest->sanim[j][k].pos );
  929. }
  930. else
  931. {
  932. // find src in pdest's reference frame?
  933. QuaternionMAAngles( pdest->sanim[j][k].rot, -1, src[k].rot, pdest->sanim[j][k].rot );
  934. VectorSubtract( src[k].pos, pdest->sanim[j][k].pos, pdest->sanim[j][k].pos );
  935. }
  936. /*
  937. printf(" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
  938. pdest->sanim[j][k].pos[0], pdest->sanim[j][k].pos[1], pdest->sanim[j][k].pos[2],
  939. RAD2DEG(pdest->sanim[j][k].rot[0]), RAD2DEG(pdest->sanim[j][k].rot[1]), RAD2DEG(pdest->sanim[j][k].rot[2]) );
  940. */
  941. }
  942. }
  943. }
  944. #if 0
  945. // cleanup weightlists
  946. for (k = 0; k < g_numbones; k++)
  947. {
  948. panim->weight[k] = 0.0;
  949. }
  950. for (k = 0; k < g_numbones; k++)
  951. {
  952. if (g_weightlist[panim->weightlist].weight[k] > 0.0)
  953. {
  954. for (j = 0; j < panim->numframes; j++)
  955. {
  956. if (fabs(panim->sanim[j][k].pos[0]) > 0.001 ||
  957. fabs(panim->sanim[j][k].pos[1]) > 0.001 ||
  958. fabs(panim->sanim[j][k].pos[2]) > 0.001 ||
  959. fabs(panim->sanim[j][k].rot[0]) > 0.001 ||
  960. fabs(panim->sanim[j][k].rot[1]) > 0.001 ||
  961. fabs(panim->sanim[j][k].rot[2]) > 0.001)
  962. {
  963. panim->weight[k] = g_weightlist[panim->weightlist].weight[k];
  964. break;
  965. }
  966. }
  967. }
  968. }
  969. #endif
  970. }
  971. //-----------------------------------------------------------------------------
  972. // Purpose:
  973. //-----------------------------------------------------------------------------
  974. void QuaternionSlerp( const RadianEuler &r0, const RadianEuler &r1, float t, RadianEuler &r2 )
  975. {
  976. Quaternion q0, q1, q2;
  977. AngleQuaternion( r0, q0 );
  978. AngleQuaternion( r1, q1 );
  979. QuaternionSlerp( q0, q1, t, q2 );
  980. QuaternionAngles( q2, r2 );
  981. }
  982. //-----------------------------------------------------------------------------
  983. // Purpose: subtract each frame running interpolation of the first frame to the last frame
  984. //-----------------------------------------------------------------------------
  985. void linearDelta( s_animation_t *psrc, s_animation_t *pdest, int srcframe, int flags )
  986. {
  987. int j, k;
  988. // create delta animations
  989. s_bone_t src0[MAXSTUDIOSRCBONES];
  990. s_bone_t src1[MAXSTUDIOSRCBONES];
  991. for (k = 0; k < g_numbones; k++)
  992. {
  993. VectorCopy( psrc->sanim[0][k].pos, src0[k].pos );
  994. VectorCopy( psrc->sanim[0][k].rot, src0[k].rot );
  995. VectorCopy( psrc->sanim[srcframe][k].pos, src1[k].pos );
  996. VectorCopy( psrc->sanim[srcframe][k].rot, src1[k].rot );
  997. }
  998. if (pdest->numframes == 1)
  999. {
  1000. MdlWarning( "%s too short for splinedelta\n", pdest->name );
  1001. }
  1002. for (k = 0; k < g_numbones; k++)
  1003. {
  1004. for (j = 0; j < pdest->numframes; j++)
  1005. {
  1006. float s = 1;
  1007. if (pdest->numframes > 1)
  1008. {
  1009. s = (float)j / (pdest->numframes - 1);
  1010. }
  1011. // make it a spline curve
  1012. if (flags & STUDIO_AL_SPLINE)
  1013. {
  1014. s = 3 * s * s - 2 * s * s * s;
  1015. }
  1016. if (pdest->weight[k] > 0)
  1017. {
  1018. /*
  1019. printf("%2d : %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
  1020. k,
  1021. src[k].pos[0], src[k].pos[1], src[k].pos[2],
  1022. src[k].rot[0], src[k].rot[1], src[k].rot[2] );
  1023. printf(" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
  1024. RAD2DEG(pdest->sanim[j][k].pos[0]), RAD2DEG(pdest->sanim[j][k].pos[1]), RAD2DEG(pdest->sanim[j][k].pos[2]),
  1025. RAD2DEG(pdest->sanim[j][k].rot[0]), RAD2DEG(pdest->sanim[j][k].rot[1]), RAD2DEG(pdest->sanim[j][k].rot[2]) );
  1026. */
  1027. s_bone_t src;
  1028. src.pos = src0[k].pos * (1 - s) + src1[k].pos * s;
  1029. QuaternionSlerp( src0[k].rot, src1[k].rot, s, src.rot );
  1030. // calc differences between two rotations
  1031. if (flags & STUDIO_AL_POST)
  1032. {
  1033. // find pdest in src's reference frame
  1034. QuaternionSMAngles( -1, src.rot, pdest->sanim[j][k].rot, pdest->sanim[j][k].rot );
  1035. VectorSubtract( pdest->sanim[j][k].pos, src.pos, pdest->sanim[j][k].pos );
  1036. }
  1037. else
  1038. {
  1039. // find src in pdest's reference frame?
  1040. QuaternionMAAngles( pdest->sanim[j][k].rot, -1, src.rot, pdest->sanim[j][k].rot );
  1041. VectorSubtract( src.pos, pdest->sanim[j][k].pos, pdest->sanim[j][k].pos );
  1042. }
  1043. /*
  1044. printf(" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
  1045. pdest->sanim[j][k].pos[0], pdest->sanim[j][k].pos[1], pdest->sanim[j][k].pos[2],
  1046. RAD2DEG(pdest->sanim[j][k].rot[0]), RAD2DEG(pdest->sanim[j][k].rot[1]), RAD2DEG(pdest->sanim[j][k].rot[2]) );
  1047. */
  1048. }
  1049. }
  1050. }
  1051. }
  1052. //-----------------------------------------------------------------------------
  1053. // Purpose: turn the animation into a lower fps encoded version
  1054. //-----------------------------------------------------------------------------
  1055. void reencodeAnimation( s_animation_t *panim, int frameskip )
  1056. {
  1057. int j, k, n;
  1058. n = 1;
  1059. for (j = frameskip; j < panim->numframes; j += frameskip)
  1060. {
  1061. for (k = 0; k < g_numbones; k++)
  1062. {
  1063. panim->sanim[n][k] = panim->sanim[j][k];
  1064. }
  1065. n++;
  1066. }
  1067. panim->numframes = n;
  1068. panim->fps = panim->fps / frameskip;
  1069. }
  1070. //-----------------------------------------------------------------------------
  1071. // Purpose: clip or pad the animation as nessesary to be a specified number of frames
  1072. //-----------------------------------------------------------------------------
  1073. void forceNumframes( s_animation_t *panim, int numframes )
  1074. {
  1075. int j;
  1076. int size = g_numbones * sizeof( s_bone_t );
  1077. // copy
  1078. for (j = panim->numframes; j < numframes; j++)
  1079. {
  1080. panim->sanim[j] = (s_bone_t *)kalloc( 1, size );
  1081. memcpy( panim->sanim[j], panim->sanim[panim->numframes-1], size );
  1082. }
  1083. panim->numframes = numframes;
  1084. }
  1085. //-----------------------------------------------------------------------------
  1086. // Purpose: subtract each frame from the previous to calculate the animations derivative
  1087. //-----------------------------------------------------------------------------
  1088. void createDerivative( s_animation_t *panim, float scale )
  1089. {
  1090. int j, k;
  1091. s_bone_t orig[MAXSTUDIOSRCBONES];
  1092. j = panim->numframes - 1;
  1093. if (panim->flags & STUDIO_LOOPING)
  1094. {
  1095. j--;
  1096. }
  1097. for (k = 0; k < g_numbones; k++)
  1098. {
  1099. VectorCopy( panim->sanim[j][k].pos, orig[k].pos );
  1100. VectorCopy( panim->sanim[j][k].rot, orig[k].rot );
  1101. }
  1102. for (j = panim->numframes - 1; j >= 0; j--)
  1103. {
  1104. s_bone_t *psrc;
  1105. s_bone_t *pdest;
  1106. if (j - 1 >= 0)
  1107. {
  1108. psrc = panim->sanim[j-1];
  1109. }
  1110. else
  1111. {
  1112. psrc = orig;
  1113. }
  1114. pdest = panim->sanim[j];
  1115. for (k = 0; k < g_numbones; k++)
  1116. {
  1117. if (panim->weight[k] > 0)
  1118. {
  1119. /*
  1120. {
  1121. printf("%2d : %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
  1122. k,
  1123. psrc[k].pos[0], psrc[k].pos[1], psrc[k].pos[2],
  1124. RAD2DEG(psrc[k].rot[0]), RAD2DEG(psrc[k].rot[1]), RAD2DEG(psrc[k].rot[2]) );
  1125. printf(" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
  1126. pdest[k].pos[0], pdest[k].pos[1], pdest[k].pos[2],
  1127. RAD2DEG(pdest[k].rot[0]), RAD2DEG(pdest[k].rot[1]), RAD2DEG(pdest[k].rot[2]) );
  1128. }
  1129. */
  1130. // find pdest in src's reference frame
  1131. QuaternionSMAngles( -1, psrc[k].rot, pdest[k].rot, pdest[k].rot );
  1132. VectorSubtract( pdest[k].pos, psrc[k].pos, pdest[k].pos );
  1133. // rescale results (not sure what basis physics system is expecting)
  1134. {
  1135. // QuaternionScale( pdest[k].rot, scale, pdest[k].rot );
  1136. Quaternion q;
  1137. AngleQuaternion( pdest[k].rot, q );
  1138. QuaternionScale( q, scale, q );
  1139. QuaternionAngles( q, pdest[k].rot );
  1140. VectorScale( pdest[k].pos, scale, pdest[k].pos );
  1141. }
  1142. /*
  1143. {
  1144. printf(" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
  1145. pdest[k].pos[0], pdest[k].pos[1], pdest[k].pos[2],
  1146. RAD2DEG(pdest[k].rot[0]), RAD2DEG(pdest[k].rot[1]), RAD2DEG(pdest[k].rot[2]) );
  1147. }
  1148. */
  1149. }
  1150. }
  1151. }
  1152. }
  1153. //-----------------------------------------------------------------------------
  1154. // Purpose: subtract each frame from the previous to calculate the animations derivative
  1155. //-----------------------------------------------------------------------------
  1156. void clearAnimations( s_animation_t *panim )
  1157. {
  1158. panim->flags |= STUDIO_DELTA;
  1159. panim->flags |= STUDIO_ALLZEROS;
  1160. panim->numframes = 1;
  1161. panim->startframe = 0;
  1162. panim->endframe = 1;
  1163. int k;
  1164. for (k = 0; k < g_numbones; k++)
  1165. {
  1166. panim->sanim[0][k].pos = Vector( 0, 0, 0 );
  1167. panim->sanim[0][k].rot = RadianEuler( 0, 0, 0 );
  1168. panim->weight[k] = 0.0;
  1169. panim->posweight[k] = 0.0;
  1170. }
  1171. }
  1172. //-----------------------------------------------------------------------------
  1173. // Purpose: remove all world rotation from a bone
  1174. //-----------------------------------------------------------------------------
  1175. void counterRotateBone( s_animation_t *panim, int iBone, QAngle target )
  1176. {
  1177. matrix3x4_t boneToWorld[MAXSTUDIOBONES];
  1178. Vector pos;
  1179. matrix3x4_t defaultBoneToWorld;
  1180. int j;
  1181. AngleMatrix( target, defaultBoneToWorld );
  1182. for (j = 0; j < panim->numframes; j++)
  1183. {
  1184. CalcBoneTransforms( panim, j, boneToWorld );
  1185. MatrixPosition( boneToWorld[iBone], pos );
  1186. PositionMatrix( pos, defaultBoneToWorld );
  1187. boneToWorld[iBone] = defaultBoneToWorld;
  1188. solveBone( panim, j, iBone, boneToWorld );
  1189. }
  1190. }
  1191. //-----------------------------------------------------------------------------
  1192. // Purpose: build transforms in source space, assuming source bones
  1193. //-----------------------------------------------------------------------------
  1194. void BuildRawTransforms( const s_source_t *psource, const char *pAnimationName,
  1195. int frame, float scale, Vector const &shift, RadianEuler const &rotate, int flags, matrix3x4_t* boneToWorld )
  1196. {
  1197. int k;
  1198. Vector tmp;
  1199. Vector pos;
  1200. RadianEuler rot;
  1201. matrix3x4_t bonematrix;
  1202. matrix3x4_t rootxform;
  1203. AngleMatrix( rotate, rootxform );
  1204. const s_sourceanim_t *pSourceAnim = FindSourceAnim( psource, pAnimationName );
  1205. if ( !pSourceAnim )
  1206. {
  1207. MdlError( "Unknown animation name %s\n", pAnimationName );
  1208. return;
  1209. }
  1210. if ( flags & STUDIO_LOOPING )
  1211. {
  1212. if ( frame )
  1213. {
  1214. while ( frame < 0)
  1215. frame += pSourceAnim->numframes;
  1216. frame = frame % pSourceAnim->numframes;
  1217. }
  1218. }
  1219. else
  1220. {
  1221. frame = clamp( frame, 0, pSourceAnim->numframes - 1 );
  1222. }
  1223. // build source space local to world transforms
  1224. for (k = 0; k < psource->numbones; k++)
  1225. {
  1226. VectorScale( pSourceAnim->rawanim.Element(frame)[k].pos, scale, pos );
  1227. VectorCopy( pSourceAnim->rawanim.Element(frame)[k].rot, rot );
  1228. if ( psource->localBone[k].parent == -1 )
  1229. {
  1230. // translate
  1231. VectorSubtract( pos, shift, tmp );
  1232. // rotate
  1233. VectorRotate( tmp, rootxform, pos );
  1234. matrix3x4_t m;
  1235. AngleMatrix( rot, m );
  1236. ConcatTransforms( rootxform, m, bonematrix );
  1237. MatrixAngles( bonematrix, rot );
  1238. clip_rotations( rot );
  1239. }
  1240. AngleMatrix( rot, pos, bonematrix );
  1241. if ( psource->localBone[k].parent == -1 )
  1242. {
  1243. MatrixCopy( bonematrix, boneToWorld[k] );
  1244. }
  1245. else
  1246. {
  1247. ConcatTransforms( boneToWorld[psource->localBone[k].parent], bonematrix, boneToWorld[k] );
  1248. // ConcatTransforms( worldToBone[psource->localBone[k].parent], boneToWorld[k], bonematrix );
  1249. // B * C => A
  1250. // C <= B-1 * A
  1251. }
  1252. }
  1253. }
  1254. void BuildRawTransforms( const s_source_t *psource, const char *pAnimationName, int frame, matrix3x4_t* boneToWorld )
  1255. {
  1256. BuildRawTransforms( psource, pAnimationName, frame, 1.0f, Vector( 0, 0, 0 ), RadianEuler( 0, 0, 0 ), 0, boneToWorld );
  1257. }
  1258. //-----------------------------------------------------------------------------
  1259. // Purpose: convert source bone animation into global bone animation
  1260. //-----------------------------------------------------------------------------
  1261. void TranslateAnimations( const s_source_t *pSource, const matrix3x4_t *pSrcBoneToWorld, matrix3x4_t *pDestBoneToWorld )
  1262. {
  1263. matrix3x4_t bonematrix;
  1264. for (int k = 0; k < g_numbones; k++)
  1265. {
  1266. int q = pSource->boneGlobalToLocal[k];
  1267. if ( q == -1 )
  1268. {
  1269. // unknown bone, copy over defaults
  1270. if ( g_bonetable[k].parent >= 0 )
  1271. {
  1272. AngleMatrix( g_bonetable[k].rot, g_bonetable[k].pos, bonematrix );
  1273. ConcatTransforms( pDestBoneToWorld[g_bonetable[k].parent], bonematrix, pDestBoneToWorld[k] );
  1274. }
  1275. else
  1276. {
  1277. AngleMatrix( g_bonetable[k].rot, g_bonetable[k].pos, pDestBoneToWorld[k] );
  1278. }
  1279. }
  1280. else
  1281. {
  1282. ConcatTransforms( pSrcBoneToWorld[q], g_bonetable[k].srcRealign, pDestBoneToWorld[k] );
  1283. }
  1284. }
  1285. }
  1286. //-----------------------------------------------------------------------------
  1287. // Purpose: convert source bone animation into global bone animation
  1288. //-----------------------------------------------------------------------------
  1289. void ConvertAnimation( const s_source_t *psource, const char *pAnimationName, int frame, float scale, Vector const &shift, RadianEuler const &rotate, s_bone_t *dest )
  1290. {
  1291. int k;
  1292. matrix3x4_t srcBoneToWorld[MAXSTUDIOSRCBONES];
  1293. //matrix3x4_t srcWorldToBone[MAXSTUDIOSRCBONES];
  1294. matrix3x4_t destBoneToWorld[MAXSTUDIOSRCBONES];
  1295. matrix3x4_t destWorldToBone[MAXSTUDIOSRCBONES];
  1296. matrix3x4_t bonematrix;
  1297. BuildRawTransforms( psource, pAnimationName, frame, scale, shift, rotate, 0, srcBoneToWorld );
  1298. /*
  1299. for (k = 0; k < psource->numbones; k++)
  1300. {
  1301. MatrixInvert( srcBoneToWorld[k], srcWorldToBone[k] );
  1302. }
  1303. */
  1304. TranslateAnimations( psource, srcBoneToWorld, destBoneToWorld );
  1305. for (k = 0; k < g_numbones; k++)
  1306. {
  1307. MatrixInvert( destBoneToWorld[k], destWorldToBone[k] );
  1308. }
  1309. // convert source_space_local_to_world transforms to shared_space_local_to_world transforms
  1310. for (k = 0; k < g_numbones; k++)
  1311. {
  1312. if (g_bonetable[k].parent == -1)
  1313. {
  1314. MatrixCopy( destBoneToWorld[k], bonematrix );
  1315. }
  1316. else
  1317. {
  1318. // convert my transform into parent relative space
  1319. ConcatTransforms( destWorldToBone[g_bonetable[k].parent], destBoneToWorld[k], bonematrix );
  1320. // printf("%s : %s\n", psource->localBone[q2].name, psource->localBone[q].name );
  1321. // B * C => A
  1322. // C <= B-1 * A
  1323. }
  1324. MatrixAngles( bonematrix, dest[k].rot, dest[k].pos );
  1325. clip_rotations( dest[k].rot );
  1326. }
  1327. }
  1328. //-----------------------------------------------------------------------------
  1329. // Purpose: copy the raw animation data from the source files into the individual animations
  1330. //-----------------------------------------------------------------------------
  1331. void RemapAnimations(void)
  1332. {
  1333. int i, j;
  1334. // copy source animations
  1335. for (i = 0; i < g_numani; i++)
  1336. {
  1337. s_animation_t *panim = g_panimation[i];
  1338. s_source_t *psource = panim->source;
  1339. s_sourceanim_t *pSourceAnim = FindSourceAnim( psource, panim->animationname );
  1340. int size = g_numbones * sizeof( s_bone_t );
  1341. int n = panim->startframe - pSourceAnim->startframe;
  1342. // printf("%s %d:%d\n", g_panimation[i]->filename, g_panimation[i]->startframe, pSourceAnim->startframe );
  1343. for (j = 0; j < panim->numframes; j++)
  1344. {
  1345. panim->sanim[j] = (s_bone_t *)kalloc( 1, size );
  1346. ConvertAnimation( psource, panim->animationname, n + j, panim->scale, panim->adjust, panim->rotation, panim->sanim[j] );
  1347. }
  1348. }
  1349. }
  1350. void buildAnimationWeights()
  1351. {
  1352. int i, j, k;
  1353. // rlink animation weights
  1354. for (i = 0; i < g_numweightlist; i++)
  1355. {
  1356. if (i == 0)
  1357. {
  1358. // initialize weights
  1359. for (j = 0; j < g_numbones; j++)
  1360. {
  1361. if (g_bonetable[j].parent != -1)
  1362. {
  1363. // set child bones to uninitialized
  1364. g_weightlist[i].weight[j] = -1;
  1365. }
  1366. else if (i == 0)
  1367. {
  1368. // set root bones to 1
  1369. g_weightlist[i].weight[j] = 1;
  1370. g_weightlist[i].posweight[j] = 1;
  1371. }
  1372. }
  1373. }
  1374. else
  1375. {
  1376. // initialize weights
  1377. for (j = 0; j < g_numbones; j++)
  1378. {
  1379. if (g_bonetable[j].parent != -1)
  1380. {
  1381. // set child bones to uninitialized
  1382. g_weightlist[i].weight[j] = g_weightlist[0].weight[j];
  1383. g_weightlist[i].posweight[j] = g_weightlist[0].posweight[j];
  1384. }
  1385. else
  1386. {
  1387. // set root bones to 0
  1388. g_weightlist[i].weight[j] = 0;
  1389. g_weightlist[i].posweight[j] = 0;
  1390. }
  1391. }
  1392. }
  1393. // match up weights
  1394. for (j = 0; j < g_weightlist[i].numbones; j++)
  1395. {
  1396. k = findGlobalBone( g_weightlist[i].bonename[j] );
  1397. if (k == -1)
  1398. {
  1399. MdlError("unknown bone reference '%s' in weightlist '%s'\n", g_weightlist[i].bonename[j], g_weightlist[i].name );
  1400. }
  1401. g_weightlist[i].weight[k] = g_weightlist[i].boneweight[j];
  1402. g_weightlist[i].posweight[k] = g_weightlist[i].boneposweight[j];
  1403. }
  1404. }
  1405. for (i = 0; i < g_numweightlist; i++)
  1406. {
  1407. // copy weights forward
  1408. for (j = 0; j < g_numbones; j++)
  1409. {
  1410. if (g_weightlist[i].weight[j] < 0.0)
  1411. {
  1412. if (g_bonetable[j].parent != -1)
  1413. {
  1414. g_weightlist[i].weight[j] = g_weightlist[i].weight[g_bonetable[j].parent];
  1415. g_weightlist[i].posweight[j] = g_weightlist[i].posweight[g_bonetable[j].parent];
  1416. }
  1417. }
  1418. }
  1419. }
  1420. }
  1421. void setAnimationWeight( s_animation_t *panim, int index )
  1422. {
  1423. // copy weightlists to animations
  1424. for (int k = 0; k < g_numbones; k++)
  1425. {
  1426. panim->weight[k] = g_weightlist[index].weight[k];
  1427. panim->posweight[k] = g_weightlist[index].posweight[k];
  1428. }
  1429. }
  1430. void addDeltas( s_animation_t *panim, int frame, float s, Vector delta_pos[], Quaternion delta_q[] )
  1431. {
  1432. for (int k = 0; k < g_numbones; k++)
  1433. {
  1434. if (panim->weight[k] > 0)
  1435. {
  1436. QuaternionSMAngles( s, delta_q[k], panim->sanim[frame][k].rot, panim->sanim[frame][k].rot );
  1437. VectorMA( panim->sanim[frame][k].pos, s, delta_pos[k], panim->sanim[frame][k].pos );
  1438. }
  1439. }
  1440. }
  1441. //-----------------------------------------------------------------------------
  1442. // Purpose: find the difference between the overlapping frames and spread out
  1443. // the difference over multiple frames.
  1444. // start: negative number, specifies how far back from the end to start blending
  1445. // end: positive number, specifies how many frames from the beginning to blend
  1446. //-----------------------------------------------------------------------------
  1447. void fixupLoopingDiscontinuities( s_animation_t *panim, int start, int end )
  1448. {
  1449. int j, k, m, n;
  1450. // fix C0 errors on looping animations
  1451. m = panim->numframes - 1;
  1452. Vector delta_pos[MAXSTUDIOSRCBONES];
  1453. Quaternion delta_q[MAXSTUDIOSRCBONES];
  1454. // skip if there's nothing to smooth
  1455. if (m == 0)
  1456. return;
  1457. for (k = 0; k < g_numbones; k++)
  1458. {
  1459. VectorSubtract( panim->sanim[m][k].pos, panim->sanim[0][k].pos, delta_pos[k] );
  1460. QuaternionMA( panim->sanim[m][k].rot, -1, panim->sanim[0][k].rot, delta_q[k] );
  1461. QAngle ang;
  1462. QuaternionAngles( delta_q[k], ang );
  1463. // printf("%2d %.1f %.1f %.1f\n", k, ang.x, ang.y, ang.z );
  1464. }
  1465. // HACK: skip fixup for motion that'll be matched with linear extraction
  1466. // FIXME: remove when "global" extraction moved into normal ordered processing loop
  1467. for (k = 0; k < g_numbones; k++)
  1468. {
  1469. if (g_bonetable[k].parent == -1)
  1470. {
  1471. if (panim->motiontype & STUDIO_LX)
  1472. delta_pos[k].x = 0.0;
  1473. if (panim->motiontype & STUDIO_LY)
  1474. delta_pos[k].y = 0.0;
  1475. if (panim->motiontype & STUDIO_LZ)
  1476. delta_pos[k].z = 0.0;
  1477. // FIXME: add rotation
  1478. }
  1479. }
  1480. // make sure loop doesn't exceed animation length
  1481. if (end-start > panim->numframes)
  1482. {
  1483. end = panim->numframes + start;
  1484. if (end < 0)
  1485. {
  1486. end = 0;
  1487. start = -(panim->numframes - 1);
  1488. }
  1489. }
  1490. // FIXME: figure out S
  1491. float s = 0;
  1492. float nf = end - start;
  1493. for (j = start + 1; j <= 0; j++)
  1494. {
  1495. n = j - start;
  1496. s = (n / nf);
  1497. s = 3 * s * s - 2 * s * s * s;
  1498. // printf("%d : %d (%lf)\n", m+j, n, -s );
  1499. addDeltas( panim, m+j, -s, delta_pos, delta_q );
  1500. }
  1501. for (j = 0; j < end; j++)
  1502. {
  1503. n = end - j;
  1504. s = (n / nf);
  1505. s = 3 * s * s - 2 * s * s * s;
  1506. //printf("%d : %d (%lf)\n", j, n, s );
  1507. addDeltas( panim, j, s, delta_pos, delta_q );
  1508. }
  1509. }
  1510. void matchBlend( s_animation_t *pDestAnim, s_animation_t *pSrcAnimation, int iSrcFrame, int iDestFrame, int iPre, int iPost )
  1511. {
  1512. int j, k;
  1513. if (pDestAnim->flags & STUDIO_LOOPING)
  1514. {
  1515. iPre = max( iPre, -pDestAnim->numframes );
  1516. iPost = min( iPost, pDestAnim->numframes );
  1517. }
  1518. else
  1519. {
  1520. iPre = max( iPre, -iDestFrame );
  1521. iPost = min( iPost, pDestAnim->numframes - iDestFrame );
  1522. }
  1523. Vector delta_pos[MAXSTUDIOSRCBONES];
  1524. Quaternion delta_q[MAXSTUDIOSRCBONES];
  1525. for (k = 0; k < g_numbones; k++)
  1526. {
  1527. VectorSubtract( pSrcAnimation->sanim[iSrcFrame][k].pos, pDestAnim->sanim[iDestFrame][k].pos, delta_pos[k] );
  1528. QuaternionMA( pSrcAnimation->sanim[iSrcFrame][k].rot, -1, pDestAnim->sanim[iDestFrame][k].rot, delta_q[k] );
  1529. /*
  1530. QAngle ang;
  1531. QuaternionAngles( delta_q[k], ang );
  1532. printf("%2d %.1f %.1f %.1f\n", k, ang.x, ang.y, ang.z );
  1533. */
  1534. }
  1535. // HACK: skip fixup for motion that'll be matched with linear extraction
  1536. // FIXME: remove when "global" extraction moved into normal ordered processing loop
  1537. for (k = 0; k < g_numbones; k++)
  1538. {
  1539. if (g_bonetable[k].parent == -1)
  1540. {
  1541. if (pDestAnim->motiontype & STUDIO_LX)
  1542. delta_pos[k].x = 0.0;
  1543. if (pDestAnim->motiontype & STUDIO_LY)
  1544. delta_pos[k].y = 0.0;
  1545. if (pDestAnim->motiontype & STUDIO_LZ)
  1546. delta_pos[k].z = 0.0;
  1547. // FIXME: add rotation
  1548. }
  1549. }
  1550. // FIXME: figure out S
  1551. float s = 0;
  1552. for (j = iPre; j <= iPost; j++)
  1553. {
  1554. if (j < 0)
  1555. {
  1556. s = j / (float)(iPre-1);
  1557. }
  1558. else
  1559. {
  1560. s = j / (float)(iPost+1);
  1561. }
  1562. s = SimpleSpline( 1 - s );
  1563. k = iDestFrame + j;
  1564. if (k < 0)
  1565. {
  1566. k += (pDestAnim->numframes - 1);
  1567. }
  1568. else
  1569. {
  1570. k = k % (pDestAnim->numframes - 1);
  1571. }
  1572. //printf("%d : %d (%lf)\n", iDestFrame + j, k, s );
  1573. addDeltas( pDestAnim, k, s, delta_pos, delta_q );
  1574. // make sure final frame of a looping animation matches frame 0
  1575. if ((pDestAnim->flags & STUDIO_LOOPING) && k == 0)
  1576. {
  1577. addDeltas( pDestAnim, pDestAnim->numframes - 1, s, delta_pos, delta_q );
  1578. }
  1579. }
  1580. }
  1581. //-----------------------------------------------------------------------------
  1582. // Purpose: copy the first frame overtop the last frame
  1583. //-----------------------------------------------------------------------------
  1584. void forceAnimationLoop( s_animation_t *panim )
  1585. {
  1586. int k, m, n;
  1587. // force looping animations to be looping
  1588. if (panim->flags & STUDIO_LOOPING)
  1589. {
  1590. n = 0;
  1591. m = panim->numframes - 1;
  1592. for (k = 0; k < g_numbones; k++)
  1593. {
  1594. int type = panim->motiontype;
  1595. if (!(type & STUDIO_LX))
  1596. panim->sanim[m][k].pos[0] = panim->sanim[n][k].pos[0];
  1597. if (!(type & STUDIO_LY))
  1598. panim->sanim[m][k].pos[1] = panim->sanim[n][k].pos[1];
  1599. if (!(type & STUDIO_LZ))
  1600. panim->sanim[m][k].pos[2] = panim->sanim[n][k].pos[2];
  1601. if (!(type & STUDIO_LXR))
  1602. panim->sanim[m][k].rot[0] = panim->sanim[n][k].rot[0];
  1603. if (!(type & STUDIO_LYR))
  1604. panim->sanim[m][k].rot[1] = panim->sanim[n][k].rot[1];
  1605. if (!(type & STUDIO_LZR))
  1606. panim->sanim[m][k].rot[2] = panim->sanim[n][k].rot[2];
  1607. }
  1608. }
  1609. // printf("\n");
  1610. }
  1611. //-----------------------------------------------------------------------------
  1612. // Purpose: calculate an single bones animation in a different parent's reference frame
  1613. //-----------------------------------------------------------------------------
  1614. void localHierarchy( s_animation_t *panim, char *pBonename, char *pParentname, int start, int peak, int tail, int end )
  1615. {
  1616. s_localhierarchy_t *pRule;
  1617. pRule = &panim->localhierarchy[ panim->numlocalhierarchy ];
  1618. panim->numlocalhierarchy++;
  1619. pRule->start = start;
  1620. pRule->peak = peak;
  1621. pRule->tail = tail;
  1622. pRule->end = end;
  1623. if (pRule->start == 0 && pRule->peak == 0 && pRule->tail == 0 && pRule->end == 0)
  1624. {
  1625. pRule->tail = panim->numframes - 1;
  1626. pRule->end = panim->numframes - 1;
  1627. }
  1628. if (pRule->start != -1 && pRule->peak == -1 && pRule->tail == -1 && pRule->end != -1)
  1629. {
  1630. pRule->peak = (pRule->start + pRule->end) / 2;
  1631. pRule->tail = (pRule->start + pRule->end) / 2;
  1632. }
  1633. if (pRule->start != -1 && pRule->peak == -1 && pRule->tail != -1)
  1634. {
  1635. pRule->peak = (pRule->start + pRule->tail) / 2;
  1636. }
  1637. if (pRule->peak != -1 && pRule->tail == -1 && pRule->end != -1)
  1638. {
  1639. pRule->tail = (pRule->peak + pRule->end) / 2;
  1640. }
  1641. if (pRule->peak == -1)
  1642. {
  1643. pRule->start = 0;
  1644. pRule->peak = 0;
  1645. }
  1646. if (pRule->tail == -1)
  1647. {
  1648. pRule->tail = panim->numframes - 1;
  1649. pRule->end = panim->numframes - 1;
  1650. }
  1651. // check for wrapping
  1652. if (pRule->peak < pRule->start)
  1653. {
  1654. pRule->peak += panim->numframes - 1;
  1655. }
  1656. if (pRule->tail < pRule->peak)
  1657. {
  1658. pRule->tail += panim->numframes - 1;
  1659. }
  1660. if (pRule->end < pRule->tail)
  1661. {
  1662. pRule->end += panim->numframes - 1;
  1663. }
  1664. pRule->localData.numerror = pRule->end - pRule->start + 1;
  1665. if (pRule->end >= panim->numframes)
  1666. pRule->localData.numerror = pRule->localData.numerror + 2;
  1667. pRule->localData.pError = (s_streamdata_t *)kalloc( pRule->localData.numerror, sizeof( s_streamdata_t ));
  1668. matrix3x4_t boneToWorld[MAXSTUDIOBONES];
  1669. matrix3x4_t worldToBone;
  1670. matrix3x4_t local;
  1671. pRule->bone = findGlobalBone( pBonename );
  1672. if (pRule->bone == -1)
  1673. {
  1674. MdlError("anim '%s' references unknown bone '%s' in localhierarchy\n", panim->name, pBonename );
  1675. }
  1676. if (strlen( pParentname ) == 0)
  1677. {
  1678. pRule->newparent = -1;
  1679. }
  1680. else
  1681. {
  1682. pRule->newparent = findGlobalBone( pParentname );
  1683. if (pRule->newparent == -1)
  1684. {
  1685. MdlError("anim '%s' references unknown bone '%s' in localhierarchy\n", panim->name, pParentname );
  1686. }
  1687. }
  1688. int k;
  1689. const char *pAnimationName = panim->animationname;
  1690. s_sourceanim_t *pSourceAnim = FindSourceAnim( panim->source, pAnimationName );
  1691. for (k = 0; k < pRule->localData.numerror; k++)
  1692. {
  1693. matrix3x4_t srcBoneToWorld[MAXSTUDIOSRCBONES];
  1694. BuildRawTransforms( panim->source, pAnimationName, k + pRule->start + panim->startframe - pSourceAnim->startframe, panim->scale, panim->adjust, panim->rotation, panim->flags, srcBoneToWorld );
  1695. TranslateAnimations( panim->source, srcBoneToWorld, boneToWorld );
  1696. if (pRule->newparent != -1)
  1697. {
  1698. MatrixInvert( boneToWorld[pRule->newparent], worldToBone );
  1699. ConcatTransforms( worldToBone, boneToWorld[pRule->bone], local );
  1700. }
  1701. else
  1702. {
  1703. MatrixCopy( boneToWorld[pRule->bone], local );
  1704. }
  1705. MatrixAngles( local, pRule->localData.pError[k].q, pRule->localData.pError[k].pos );
  1706. /*
  1707. QAngle ang;
  1708. QuaternionAngles( pRule->errorData.pError[k].q, ang );
  1709. printf("%d %.1f %.1f %.1f : %.1f %.1f %.1f\n",
  1710. k,
  1711. pRule->errorData.pError[k].pos.x, pRule->errorData.pError[k].pos.y, pRule->errorData.pError[k].pos.z,
  1712. ang.x, ang.y, ang.z );
  1713. */
  1714. }
  1715. }
  1716. //-----------------------------------------------------------------------------
  1717. // Purpose: rotate the animation so that it's moving in the specified angle
  1718. //-----------------------------------------------------------------------------
  1719. void makeAngle( s_animation_t *panim, float angle )
  1720. {
  1721. float da = 0.0f;
  1722. if (panim->numpiecewisekeys != 0)
  1723. {
  1724. // look for movement in total piecewise movement
  1725. Vector pos = panim->piecewisemove[panim->numpiecewisekeys-1].pos;
  1726. if (pos[0] != 0 || pos[1] != 0)
  1727. {
  1728. float a = atan2( pos[1], pos[0] ) * (180 / M_PI);
  1729. da = angle - a;
  1730. }
  1731. for (int i = 0; i < panim->numpiecewisekeys; i++)
  1732. {
  1733. VectorYawRotate( panim->piecewisemove[i].pos, da, panim->piecewisemove[i].pos );
  1734. VectorYawRotate( panim->piecewisemove[i].vector, da, panim->piecewisemove[i].vector );
  1735. }
  1736. }
  1737. else
  1738. {
  1739. // look for movement in root bone
  1740. Vector pos = panim->sanim[(panim->numframes - 1)][g_rootIndex].pos - panim->sanim[0][g_rootIndex].pos;
  1741. if (pos[0] != 0 || pos[1] != 0)
  1742. {
  1743. float a = atan2( pos[1], pos[0] ) * (180 / M_PI);
  1744. da = angle - a;
  1745. }
  1746. }
  1747. /*
  1748. if (da > -0.01 && da < 0.01)
  1749. return;
  1750. */
  1751. matrix3x4_t rootxform;
  1752. matrix3x4_t src;
  1753. matrix3x4_t dest;
  1754. AngleMatrix( QAngle( 0, da, 0), rootxform );
  1755. for (int j = 0; j < panim->numframes; j++)
  1756. {
  1757. for (int k = 0; k < g_numbones; k++)
  1758. {
  1759. if (g_bonetable[k].parent == -1)
  1760. {
  1761. AngleMatrix( panim->sanim[j][k].rot, panim->sanim[j][k].pos, src );
  1762. ConcatTransforms( rootxform, src, dest );
  1763. MatrixAngles( dest, panim->sanim[j][k].rot, panim->sanim[j][k].pos );
  1764. }
  1765. }
  1766. }
  1767. // FIXME: not finished
  1768. }
  1769. //-----------------------------------------------------------------------------
  1770. // Purpose: convert pBoneToWorld back into rot/pos data
  1771. //-----------------------------------------------------------------------------
  1772. void solveBone(
  1773. s_animation_t *panim,
  1774. int iFrame,
  1775. int iBone,
  1776. matrix3x4_t* pBoneToWorld
  1777. )
  1778. {
  1779. int iParent = g_bonetable[iBone].parent;
  1780. if (iParent == -1)
  1781. {
  1782. MatrixAngles( pBoneToWorld[iBone], panim->sanim[iFrame][iBone].rot, panim->sanim[iFrame][iBone].pos );
  1783. return;
  1784. }
  1785. matrix3x4_t worldToBone;
  1786. MatrixInvert( pBoneToWorld[iParent], worldToBone );
  1787. matrix3x4_t local;
  1788. ConcatTransforms( worldToBone, pBoneToWorld[iBone], local );
  1789. iFrame = iFrame % panim->numframes;
  1790. MatrixAngles( local, panim->sanim[iFrame][iBone].rot, panim->sanim[iFrame][iBone].pos );
  1791. }
  1792. //-----------------------------------------------------------------------------
  1793. // Purpose: calc the influence of a ik rule for a specific point in the animation cycle
  1794. //-----------------------------------------------------------------------------
  1795. float IKRuleWeight( s_ikrule_t *pRule, float flCycle )
  1796. {
  1797. if (pRule->end > 1.0f && flCycle < pRule->start)
  1798. {
  1799. flCycle = flCycle + 1.0f;
  1800. }
  1801. float value = 0.0f;
  1802. if (flCycle < pRule->start)
  1803. {
  1804. return 0.0f;
  1805. }
  1806. else if (flCycle < pRule->peak )
  1807. {
  1808. value = (flCycle - pRule->start) / (pRule->peak - pRule->start);
  1809. }
  1810. else if (flCycle < pRule->tail )
  1811. {
  1812. return 1.0f;
  1813. }
  1814. else if (flCycle < pRule->end )
  1815. {
  1816. value = 1.0f - ((flCycle - pRule->tail) / (pRule->end - pRule->tail));
  1817. }
  1818. return 3.0f * value * value - 2.0f * value * value * value;
  1819. }
  1820. //-----------------------------------------------------------------------------
  1821. // Purpose: Lock the ik target to a specific location in order to clean up bad animations (shouldn't be needed).
  1822. //-----------------------------------------------------------------------------
  1823. void fixupIKErrors( s_animation_t *panim, s_ikrule_t *pRule )
  1824. {
  1825. int k;
  1826. if (pRule->start == 0 && pRule->peak == 0 && pRule->tail == 0 && pRule->end == 0)
  1827. {
  1828. pRule->tail = panim->numframes - 1;
  1829. pRule->end = panim->numframes - 1;
  1830. }
  1831. // check for wrapping
  1832. if (pRule->peak < pRule->start)
  1833. {
  1834. pRule->peak += panim->numframes - 1;
  1835. }
  1836. if (pRule->tail < pRule->peak)
  1837. {
  1838. pRule->tail += panim->numframes - 1;
  1839. }
  1840. if (pRule->end < pRule->tail)
  1841. {
  1842. pRule->end += panim->numframes - 1;
  1843. }
  1844. if (pRule->contact == -1)
  1845. {
  1846. pRule->contact = pRule->peak;
  1847. }
  1848. if (panim->numframes <= 1)
  1849. return;
  1850. pRule->errorData.numerror = pRule->end - pRule->start + 1;
  1851. switch( pRule->type )
  1852. {
  1853. case IK_SELF:
  1854. #if 0
  1855. // this code has never been run.....
  1856. {
  1857. matrix3x4_t boneToWorld[MAXSTUDIOBONES];
  1858. matrix3x4_t worldToBone;
  1859. matrix3x4_t local;
  1860. Vector targetPos;
  1861. Quaternion targetQuat;
  1862. pRule->bone = findGlobalBone( pRule->bonename );
  1863. if (pRule->bone == -1)
  1864. {
  1865. MdlError("unknown bone '%s' in ikrule\n", pRule->bonename );
  1866. }
  1867. matrix3x4_t srcBoneToWorld[MAXSTUDIOSRCBONES];
  1868. BuildRawTransforms( panim->source, pRule->contact + panim->startframe - panim->source->startframe, srcBoneToWorld );
  1869. TranslateAnimations( panim->source, srcBoneToWorld, boneToWorld );
  1870. MatrixInvert( boneToWorld[pRule->bone], worldToBone );
  1871. ConcatTransforms( worldToBone, boneToWorld[g_ikchain[pRule->chain].link[2].bone], local );
  1872. MatrixAngles( local, targetQuat, targetPos );
  1873. for (k = 0; k < pRule->errorData.numerror; k++)
  1874. {
  1875. BuildRawTransforms( panim->source, k + pRule->start + panim->startframe - panim->source->startframe, srcBoneToWorld );
  1876. TranslateAnimations( panim->source, srcBoneToWorld, boneToWorld );
  1877. float cycle = (panim->numframes <= 1) ? 0 : (k + pRule->start) / (panim->numframes - 1);
  1878. float s = IKRuleWeight( pRule, cycle );
  1879. Quaternion curQuat;
  1880. Vector curPos;
  1881. // convert into rule bone space
  1882. MatrixInvert( boneToWorld[pRule->bone], worldToBone );
  1883. ConcatTransforms( worldToBone, boneToWorld[g_ikchain[pRule->chain].link[2].bone], local );
  1884. MatrixAngles( local, curQuat, curPos );
  1885. // find blended rule bone relative position
  1886. Vector rulePos = curPos * s + targetPos * (1.0 - s);
  1887. Quaternion ruleQuat;
  1888. QuaternionSlerp( curQuat, targetQuat, s, ruleQuat );
  1889. QuaternionMatrix( ruleQuat, rulePos, local );
  1890. Vector worldPos;
  1891. VectorTransform( rulePos, boneToWorld[pRule->bone], worldPos );
  1892. // printf("%d (%d) : %.1f %.1f %1.f\n", k + pRule->start, pRule->peak, pos.x, pos.y, pos.z );
  1893. Studio_SolveIK(
  1894. g_ikchain[pRule->chain].link[0].bone,
  1895. g_ikchain[pRule->chain].link[1].bone,
  1896. g_ikchain[pRule->chain].link[2].bone,
  1897. worldPos,
  1898. boneToWorld );
  1899. // slam final matrix
  1900. // FIXME: this isn't taking into account the IK may have failed
  1901. ConcatTransforms( boneToWorld[pRule->bone], local, boneToWorld[g_ikchain[pRule->chain].link[2].bone] );
  1902. solveBone( panim, k + pRule->start, g_ikchain[pRule->chain].link[0].bone, boneToWorld );
  1903. solveBone( panim, k + pRule->start, g_ikchain[pRule->chain].link[1].bone, boneToWorld );
  1904. solveBone( panim, k + pRule->start, g_ikchain[pRule->chain].link[2].bone, boneToWorld );
  1905. }
  1906. }
  1907. #endif
  1908. break;
  1909. case IK_WORLD:
  1910. case IK_GROUND:
  1911. {
  1912. matrix3x4_t boneToWorld[MAXSTUDIOBONES];
  1913. int bone = g_ikchain[pRule->chain].link[2].bone;
  1914. CalcBoneTransforms( panim, pRule->contact, boneToWorld );
  1915. // FIXME: add in motion
  1916. Vector footfall;
  1917. MatrixGetColumn( boneToWorld[bone], 3, footfall );
  1918. //printf("%d %d %d %d (%d)\n", pRule->start, pRule->peak, pRule->tail, pRule->end, pRule->errorData.numerror );
  1919. for (k = 0; k < pRule->errorData.numerror; k++)
  1920. {
  1921. CalcBoneTransforms( panim, k + pRule->start, boneToWorld );
  1922. float cycle = (panim->numframes <= 1) ? 0 : (float)(k + pRule->start) / (panim->numframes - 1);
  1923. float s = IKRuleWeight( pRule, cycle );
  1924. s = 1.0; // FIXME - the weight rule is wrong
  1925. Vector orig;
  1926. MatrixPosition( boneToWorld[g_ikchain[pRule->chain].link[2].bone], orig );
  1927. Vector pos = (footfall + calcMovement( panim, k + pRule->start, pRule->contact )) * s + orig * (1.0 - s);
  1928. //printf("%d (%.1f:%.1f) : %.1f %.1f %1.f\n", k + pRule->start, cycle, s, pos.x, pos.y, pos.z );
  1929. Studio_SolveIK(
  1930. g_ikchain[pRule->chain].link[0].bone,
  1931. g_ikchain[pRule->chain].link[1].bone,
  1932. g_ikchain[pRule->chain].link[2].bone,
  1933. pos,
  1934. boneToWorld );
  1935. solveBone( panim, k + pRule->start, g_ikchain[pRule->chain].link[0].bone, boneToWorld );
  1936. solveBone( panim, k + pRule->start, g_ikchain[pRule->chain].link[1].bone, boneToWorld );
  1937. solveBone( panim, k + pRule->start, g_ikchain[pRule->chain].link[2].bone, boneToWorld );
  1938. }
  1939. }
  1940. }
  1941. forceAnimationLoop( panim ); // !!!
  1942. }
  1943. //-----------------------------------------------------------------------------
  1944. // Purpose: map the vertex animations to their equivalent vertex in the base animations
  1945. //-----------------------------------------------------------------------------
  1946. static void ComputeSideAndScale( const s_flexkey_t &flexKey, s_vertanim_t *pVAnim, float *pSide, float *pScale )
  1947. {
  1948. *pScale = 1.0f;
  1949. *pSide = 0.0f;
  1950. if ( flexKey.split > 0.0f )
  1951. {
  1952. if ( pVAnim->pos.x > flexKey.split )
  1953. {
  1954. *pScale = 0.0f;
  1955. }
  1956. else if ( pVAnim->pos.x < -flexKey.split )
  1957. {
  1958. *pScale = 1.0f;
  1959. }
  1960. else
  1961. {
  1962. float t = ( flexKey.split - pVAnim->pos.x ) / (2.0 * flexKey.split);
  1963. *pScale = 3.0f * t * t - 2.0f * t * t * t;
  1964. // printf( "%.1f : %.2f\n", pSrcAnim->pos.x, *pScale );
  1965. }
  1966. }
  1967. else if ( flexKey.split < 0.0f )
  1968. {
  1969. if ( pVAnim->pos.x < flexKey.split)
  1970. {
  1971. *pScale = 0.0f;
  1972. }
  1973. else if ( pVAnim->pos.x > -flexKey.split)
  1974. {
  1975. *pScale = 1.0f;
  1976. }
  1977. else
  1978. {
  1979. float t = ( flexKey.split - pVAnim->pos.x ) / ( 2.0f * flexKey.split );
  1980. *pScale = 3.0f * t * t - 2.0f * t * t * t;
  1981. // printf( "%.1f : %.2f\n", pSrcAnim->pos.x, *pScale );
  1982. }
  1983. }
  1984. if ( flexKey.flexpair != 0)
  1985. {
  1986. // paired flexes are full scale but variable side to side
  1987. *pSide = 1.0 - *pScale;
  1988. *pScale = 1.0;
  1989. }
  1990. else
  1991. {
  1992. // unpaired flexes are variable scale, one sided
  1993. *pSide = 0;
  1994. }
  1995. }
  1996. //-----------------------------------------------------------------------------
  1997. // Purpose: map the vertex animations to their equivalent vertex in the base animations
  1998. //-----------------------------------------------------------------------------
  1999. static void ComputeVertexAnimationSpeed( s_flexkey_t& flexKey )
  2000. {
  2001. // calc max total scale for deltas
  2002. float flScale = 0.0f;
  2003. for ( int m = 0; m < flexKey.numvanims; m++ )
  2004. {
  2005. float s =flexKey.vanim[m].pos.Length();
  2006. if ( s > flScale )
  2007. {
  2008. flScale = s;
  2009. }
  2010. }
  2011. if ( flScale == 0.0f )
  2012. {
  2013. flScale = 0.01f;
  2014. }
  2015. // set
  2016. for ( int m = 0; m < flexKey.numvanims; m++ )
  2017. {
  2018. if ( flexKey.decay == 0.0f )
  2019. {
  2020. flexKey.vanim[m].speed = 1.0f;
  2021. }
  2022. else
  2023. {
  2024. flexKey.vanim[m].speed = clamp( flexKey.vanim[m].pos.Length() / (flScale * flexKey.decay), 0.0f, 1.0f );
  2025. }
  2026. }
  2027. }
  2028. //-----------------------------------------------------------------------------
  2029. // Purpose: map the vertex animations to their equivalent vertex in the base animations
  2030. //-----------------------------------------------------------------------------
  2031. static void BuildVAnimFlags( s_source_t *pVSource, s_sourceanim_t *pVSourceAnim, int nCurrentFlexKey )
  2032. {
  2033. pVSourceAnim->vanim_flag = (int *)kalloc( pVSource->numvertices, sizeof( int ));
  2034. for ( int n = nCurrentFlexKey; n < g_numflexkeys; n++ )
  2035. {
  2036. // make sure it's the current flex file and that it's not frame 0 (happens with eyeball stuff).
  2037. if ( g_flexkey[n].source != pVSource )
  2038. continue;
  2039. if ( Q_stricmp( g_flexkey[n].animationname, pVSourceAnim->animationname ) )
  2040. continue;
  2041. const s_sourceanim_t *pAnim = FindSourceAnim( g_flexkey[n].source, g_flexkey[n].animationname );
  2042. if ( !pAnim )
  2043. continue;
  2044. if ( pAnim->newStyleVertexAnimations != pVSourceAnim->newStyleVertexAnimations )
  2045. continue;
  2046. if ( !pAnim->newStyleVertexAnimations && g_flexkey[n].frame == 0 )
  2047. continue;
  2048. int k = g_flexkey[n].frame;
  2049. for ( int m = 0; m < pVSourceAnim->numvanims[k]; m++ )
  2050. {
  2051. pVSourceAnim->vanim_flag[ pVSourceAnim->vanim[k][m].vertex ] = 1;
  2052. }
  2053. }
  2054. }
  2055. //-----------------------------------------------------------------------------
  2056. // Purpose: Build an array indexed by model vertex which indicates which vanim vertex corresponds best to it
  2057. //-----------------------------------------------------------------------------
  2058. static void BuildModelToVAnimMap( s_source_t *pVSource, s_sourceanim_t *pVSourceAnim, s_loddata_t *pmLodSource, bool bNewVertexAnimations, int *pModelToVAnim )
  2059. {
  2060. static float imapdist[MAXSTUDIOVERTS]; // distance from src vert to vanim vert
  2061. static float imapdot[MAXSTUDIOVERTS]; // dot product of src norm to vanim normal
  2062. Vector tmp;
  2063. // find frame 0 vertices to closest g_model vertex
  2064. for ( int j = 0; j < pmLodSource->numvertices; j++ )
  2065. {
  2066. imapdist[j] = 1E30;
  2067. imapdot[j] = -1.0;
  2068. pModelToVAnim[j] = -1;
  2069. }
  2070. int nMinLod = min( g_minLod, g_ScriptLODs.Count() - 1 );
  2071. for ( int j = 0; j < pVSource->numvertices; j++ )
  2072. {
  2073. float flMinDist = 1E30;
  2074. int n = -1;
  2075. for ( int k = 0; k < pmLodSource->numvertices; k++ )
  2076. {
  2077. // go ahead and skip vertices that are just going to be stripped later
  2078. // TODO: take this out when the lod clamping stuff gets moved into the LOD code instead of being a post process
  2079. if ( nMinLod && !( pmLodSource->vertex[k].lodFlag & (0xFFFFFF << nMinLod) ) )
  2080. continue;
  2081. const Vector& vecModelPos = bNewVertexAnimations ? pVSource->vertex[j].position : pVSourceAnim->vanim[0][j].pos;
  2082. // TODO: Length() gives inconsistent results in release build
  2083. VectorSubtract( pmLodSource->vertex[k].position, vecModelPos, tmp );
  2084. float flDist = tmp.LengthSqr();
  2085. if ( flDist >= 0.15f )
  2086. continue;
  2087. const Vector& vecModelNormal = bNewVertexAnimations ? pVSource->vertex[j].normal : pVSourceAnim->vanim[0][j].normal;
  2088. float flDot = DotProduct( pmLodSource->vertex[k].normal, vecModelNormal );
  2089. if ( flDist < imapdist[k] || ( flDist == imapdist[k] && flDot > imapdot[k]))
  2090. {
  2091. imapdist[k] = flDist;
  2092. imapdot[k] = flDot;
  2093. pModelToVAnim[k] = j;
  2094. }
  2095. if ( flDist < flMinDist )
  2096. {
  2097. flMinDist = flDist;
  2098. n = j;
  2099. }
  2100. }
  2101. if ( flMinDist > 0.01 )
  2102. {
  2103. // printf("vert %d dist %.4f\n", j, minDist );
  2104. // printf("%.4f %.4f %.4f\n", pvsource->vanim[0][j].pos[0], pvsource->vanim[0][j].pos[1], pvsource->vanim[0][j].pos[2] );
  2105. }
  2106. // VectorSubtract( modelpos[n], pvsource->vanim[0][j].pos, matchdelta[j] );
  2107. if ( n == -1 )
  2108. {
  2109. // printf("no match for animated vertex %d : %.4f %.4f %.4f\n", j, pVSourceAnim->vanim[0][j].pos[0], pVSourceAnim->vanim[0][j].pos[1], pVSourceAnim->vanim[0][j].pos[2] );
  2110. }
  2111. }
  2112. /*
  2113. for (j = 0; j < pmsource->numvertices; j++)
  2114. {
  2115. printf("%4d : %7.4f %7.4f : %5d", j, imapdist[j], imapdot[j], model_to_vanim_vert_imap[j] );
  2116. printf(" : %8.4f %8.4f %8.4f", modelpos[j][0], modelpos[j][1], modelpos[j][2] );
  2117. printf("\n");
  2118. }
  2119. */
  2120. /*
  2121. for (j = 0; j < pmsource->numvertices; j++)
  2122. {
  2123. if (fabs( modelpos[j][2] - 64.36) > 0.01)
  2124. continue;
  2125. printf("%4d : %8.4f %8.4f %8.4f\n", j, modelpos[j][0], modelpos[j][1], modelpos[j][2] );
  2126. }
  2127. for (j = 0; j < pvsource->numvertices; j++)
  2128. {
  2129. if (!pvsource->vanim_flag[j])
  2130. continue;
  2131. printf("%4d : %8.2f %8.2f %8.2f : ", j, pvsource->vanim[0][j].pos[0], pvsource->vanim[0][j].pos[1], pvsource->vanim[0][j].pos[2] );
  2132. for (k = 0; k < pmsource->numvertices; k++)
  2133. {
  2134. if (model_to_vanim_vert_imap[k] == j)
  2135. printf(" %d", k );
  2136. }
  2137. printf("\n");
  2138. }
  2139. */
  2140. }
  2141. //-----------------------------------------------------------------------------
  2142. // Purpose: Build an array indexed by model vertex which indicates which vanim vertex corresponds best to it
  2143. //-----------------------------------------------------------------------------
  2144. static void BuildVAnimMap( s_source_t *pVSource, s_sourceanim_t *pVSourceAnim, s_loddata_t *pmLodSource, const int *pModelToVAnim )
  2145. {
  2146. // indexed by vertex anim vertex index
  2147. static int *mapp[MAXSTUDIOVERTS*4];
  2148. // count number of times each vanim vert connectes to a model vert
  2149. int n = 0;
  2150. pVSourceAnim->vanim_mapcount = (int *)kalloc( pVSource->numvertices, sizeof( int ) );
  2151. for ( int j = 0; j < pmLodSource->numvertices; j++ )
  2152. {
  2153. if ( pModelToVAnim[j] != -1 )
  2154. {
  2155. pVSourceAnim->vanim_mapcount[ pModelToVAnim[j] ]++;
  2156. n++;
  2157. }
  2158. }
  2159. pVSourceAnim->vanim_map = (int **)kalloc( pVSource->numvertices, sizeof( int * ));
  2160. int *vmap = (int *)kalloc( n, sizeof( int ) );
  2161. // build mapping arrays
  2162. for ( int j = 0; j < pVSource->numvertices; j++ )
  2163. {
  2164. if ( pVSourceAnim->vanim_mapcount[j] )
  2165. {
  2166. pVSourceAnim->vanim_map[j] = vmap;
  2167. mapp[j] = vmap;
  2168. vmap += pVSourceAnim->vanim_mapcount[j];
  2169. }
  2170. else if ( pVSourceAnim->vanim_flag[j] )
  2171. {
  2172. // printf("%d animates but no matching vertex\n", j );
  2173. }
  2174. }
  2175. for ( int j = 0; j < pmLodSource->numvertices; j++ )
  2176. {
  2177. if (pModelToVAnim[j] != -1)
  2178. {
  2179. *(mapp[ pModelToVAnim[j] ]++) = j;
  2180. }
  2181. }
  2182. }
  2183. //-----------------------------------------------------------------------------
  2184. // Computes the number of unique desination vanims, allocates space for it
  2185. //-----------------------------------------------------------------------------
  2186. static void AllocateDestVAnim( s_flexkey_t &flexKey, s_sourceanim_t *pVSourceAnim )
  2187. {
  2188. int nVAnimCount = pVSourceAnim->numvanims[ flexKey.frame ];
  2189. s_vertanim_t *pVAnim = pVSourceAnim->vanim[ flexKey.frame ];
  2190. // frame 0 is special. Always assume zero vertex animations
  2191. if ( !pVSourceAnim->newStyleVertexAnimations && flexKey.frame == 0 )
  2192. {
  2193. nVAnimCount = 0;
  2194. }
  2195. // count total possible remapped animations
  2196. int nNumDestVAnims = 0;
  2197. for ( int m = 0; m < nVAnimCount; m++)
  2198. {
  2199. nNumDestVAnims += pVSourceAnim->vanim_mapcount[ pVAnim[m].vertex ];
  2200. }
  2201. // allocate room to all possible resulting deltas
  2202. s_vertanim_t *pDestAnim = (s_vertanim_t *)kalloc( nNumDestVAnims, sizeof( s_vertanim_t ) );
  2203. flexKey.vanim = pDestAnim;
  2204. flexKey.vanimtype = STUDIO_VERT_ANIM_NORMAL; // default
  2205. }
  2206. //-----------------------------------------------------------------------------
  2207. // Purpose: map the vertex animations to their equivalent vertex in the base animations
  2208. //-----------------------------------------------------------------------------
  2209. void RemapVertexAnimations(void)
  2210. {
  2211. int i, j, k;
  2212. int n, m;
  2213. s_source_t *pvsource; // vertex animation source
  2214. const char *pAnimationName;
  2215. s_sourceanim_t *pSourceAnim;
  2216. s_loddata_t *pmLodSource; // original model source
  2217. Vector tmp;
  2218. // index by vertex in targets root LOD
  2219. static int model_to_vanim_vert_imap[MAXSTUDIOVERTS]; // model vert to vanim vert mapping
  2220. // for all the sources of flexes, find a mapping of vertex animations to base model.
  2221. // There can be multiple "vertices" in the base model for each animated vertex since vertices
  2222. // are duplicated along material boundaries.
  2223. for ( i = 0; i < g_numflexkeys; i++ )
  2224. {
  2225. s_source_t *pVSource = g_flexkey[i].source;
  2226. s_sourceanim_t *pVSourceAnim = FindSourceAnim( pVSource, g_flexkey[i].animationname );
  2227. // We only do old-style vertex animations
  2228. if ( pVSourceAnim->newStyleVertexAnimations )
  2229. continue;
  2230. // skip if it's already been done or if has doesn't have any animations
  2231. if ( pVSourceAnim->vanim_flag )
  2232. continue;
  2233. // flag all the vertices that animate (builds the vanim_flag field of the source anim)
  2234. BuildVAnimFlags( pVSource, pVSourceAnim, i );
  2235. s_loddata_t *pLodData = g_model[ g_flexkey[i].imodel ]->m_pLodData;
  2236. // Map vertex indices specified in the model to ones specified in the vanim data
  2237. BuildModelToVAnimMap( pVSource, pVSourceAnim, pLodData, false, model_to_vanim_vert_imap );
  2238. // Build the vanim_mapcount, vanim_map fields of the source anim
  2239. BuildVAnimMap( pVSource, pVSourceAnim, pLodData, model_to_vanim_vert_imap );
  2240. }
  2241. #if 0
  2242. s_vertanim_t *defaultanims = NULL;
  2243. if (g_defaultflexkey)
  2244. {
  2245. defaultanims = g_defaultflexkey->source->vanim[g_defaultflexkey->frame];
  2246. }
  2247. else
  2248. {
  2249. defaultanims = g_flexkey[0].source->vanim[0];
  2250. }
  2251. #endif
  2252. // reset model to be default animations
  2253. if ( g_defaultflexkey )
  2254. {
  2255. pvsource = g_defaultflexkey->source;
  2256. pAnimationName = g_defaultflexkey->animationname;
  2257. pSourceAnim = FindSourceAnim( pvsource, pAnimationName );
  2258. pmLodSource = g_model[g_defaultflexkey->imodel]->m_pLodData;
  2259. int numsrcanims = pSourceAnim->numvanims[g_defaultflexkey->frame];
  2260. s_vertanim_t *psrcanim = pSourceAnim->vanim[g_defaultflexkey->frame];
  2261. for (m = 0; m < numsrcanims; m++)
  2262. {
  2263. if ( pSourceAnim->vanim_mapcount[psrcanim->vertex]) // bah, only do it for ones that found a match!
  2264. {
  2265. for (n = 0; n < pSourceAnim->vanim_mapcount[psrcanim->vertex]; n++)
  2266. {
  2267. // copy "default" pos to original model
  2268. k = pSourceAnim->vanim_map[psrcanim->vertex][n];
  2269. VectorCopy( psrcanim->pos, pmLodSource->vertex[k].position );
  2270. VectorCopy( psrcanim->normal, pmLodSource->vertex[k].normal );
  2271. // copy "default" pos to frame 0 of vertex animation source
  2272. // FIXME: this needs to copy to all sources of vertex animation.
  2273. // FIXME: the "default" pose needs to be in each vertex animation source since it's likely that the vertices won't be numbered the same in each file.
  2274. VectorCopy( psrcanim->pos, pSourceAnim->vanim[0][psrcanim->vertex].pos );
  2275. VectorCopy( psrcanim->normal, pSourceAnim->vanim[0][psrcanim->vertex].normal );
  2276. }
  2277. }
  2278. psrcanim++;
  2279. }
  2280. }
  2281. static bool doesMove[MAXSTUDIOVERTS];
  2282. int numMoved;
  2283. memset( doesMove, 0, MAXSTUDIOVERTS * sizeof( bool ) );
  2284. numMoved = 0;
  2285. for (i = 0; i < g_numflexkeys; i++)
  2286. {
  2287. pvsource = g_flexkey[i].source;
  2288. pAnimationName = g_flexkey[i].animationname;
  2289. pSourceAnim = FindSourceAnim( pvsource, pAnimationName );
  2290. if ( pSourceAnim->newStyleVertexAnimations )
  2291. continue;
  2292. pmLodSource = g_model[g_flexkey[i].imodel]->m_pLodData;
  2293. // Allocate g_flexkey[i].vanim
  2294. AllocateDestVAnim( g_flexkey[i], pSourceAnim );
  2295. s_vertanim_t *psrcanim = pSourceAnim->vanim[g_flexkey[i].frame];
  2296. s_vertanim_t *pdestanim = g_flexkey[i].vanim;
  2297. // frame 0 is special. Always assume zero vertex animations
  2298. int numsrcanims = ( g_flexkey[i].frame != 0 ) ? pSourceAnim->numvanims[g_flexkey[i].frame] : 0;
  2299. for (m = 0; m < numsrcanims; m++, psrcanim++)
  2300. {
  2301. Vector delta, ndelta;
  2302. float flSide, flScale;
  2303. ComputeSideAndScale( g_flexkey[i], psrcanim, &flSide, &flScale );
  2304. // bah, only do it for ones that found a match!
  2305. if ( flScale <= 0.0f || !pSourceAnim->vanim_mapcount[psrcanim->vertex] )
  2306. continue;
  2307. j = pSourceAnim->vanim_map[psrcanim->vertex][0];
  2308. //VectorSubtract( psrcanim->pos, pSourceAnim->vanim[0][psrcanim->vertex].pos, tmp );
  2309. //VectorTransform( tmp, pmsource->bonefixup[k].im, delta );
  2310. VectorSubtract( psrcanim->pos, pSourceAnim->vanim[0][psrcanim->vertex].pos, delta );
  2311. //VectorSubtract( psrcanim->normal, pSourceAnim->vanim[0][psrcanim->vertex].normal, tmp );
  2312. //VectorTransform( tmp, pmsource->bonefixup[k].im, ndelta );
  2313. VectorSubtract( psrcanim->normal, pSourceAnim->vanim[0][psrcanim->vertex].normal, ndelta );
  2314. // if the changes are too small, skip 'em
  2315. // FIXME: the clamp needs to be paired with the other matching positions.
  2316. // currently this is set to the float16 min value. Sucky.
  2317. if (DotProduct( delta, delta ) <= (0.001f*0.001f) /* 0.0001 */ && DotProduct( ndelta, ndelta ) <= 0.001)
  2318. {
  2319. // printf("%4d %6.4f %6.4f %6.4f\n", pdestanim->vertex, delta.x, delta.y, delta.z );
  2320. continue;
  2321. }
  2322. for (n = 0; n < pSourceAnim->vanim_mapcount[psrcanim->vertex]; n++)
  2323. {
  2324. pdestanim->vertex = pSourceAnim->vanim_map[psrcanim->vertex][n];
  2325. VectorScale( delta, flScale, pdestanim->pos );
  2326. VectorScale( ndelta, flScale, pdestanim->normal );
  2327. pdestanim->side = flSide;
  2328. // count all the unique verts that actually move
  2329. if (!doesMove[pdestanim->vertex])
  2330. {
  2331. doesMove[pdestanim->vertex] = true;
  2332. numMoved++;
  2333. }
  2334. /*
  2335. printf("%4d %6.2f %6.2f %6.2f : %4d %5.2f %5.2f %5.2f\n",
  2336. pdestanim->vertex,
  2337. // pmsource->vertex[pdestanim->vertex][0], pmsource->vertex[pdestanim->vertex][1], pmsource->vertex[pdestanim->vertex][2],
  2338. modelpos[pdestanim->vertex][0], modelpos[pdestanim->vertex][1], modelpos[pdestanim->vertex][2],
  2339. psrcanim->vertex,
  2340. pdestanim->pos[0], pdestanim->pos[1], pdestanim->pos[2] );
  2341. */
  2342. g_flexkey[i].numvanims++;
  2343. pdestanim++;
  2344. }
  2345. }
  2346. ComputeVertexAnimationSpeed( g_flexkey[i] );
  2347. }
  2348. if (numMoved > MAXSTUDIOFLEXVERTS)
  2349. {
  2350. MdlError( "Too many flexed verts %d (%d)\n", numMoved, MAXSTUDIOFLEXVERTS );
  2351. }
  2352. else if (numMoved > 0 && !g_quiet)
  2353. {
  2354. printf("Max flex verts %d\n", numMoved );
  2355. }
  2356. }
  2357. //-----------------------------------------------------------------------------
  2358. // Purpose: map the vertex animations to their equivalent vertex in the base animations
  2359. //-----------------------------------------------------------------------------
  2360. static int FlexKeysSortFunc( const void *pv1, const void *pv2 )
  2361. {
  2362. const s_flexkey_t *pKey1 = (const s_flexkey_t*)pv1;
  2363. const s_flexkey_t *pKey2 = (const s_flexkey_t*)pv2;
  2364. if ( pKey1->source != pKey2->source )
  2365. return (size_t)pKey1->source - (size_t)pKey2->source;
  2366. return Q_stricmp( pKey1->animationname, pKey2->animationname );
  2367. }
  2368. static int SortFlexKeys( s_flexkey_t **ppSortedFlexKeys )
  2369. {
  2370. int nSortedFlexKeyCount = 0;
  2371. for ( int i = 0; i < g_numflexkeys; i++ )
  2372. {
  2373. s_source_t *pVSource = g_flexkey[i].source;
  2374. s_sourceanim_t *pVSourceAnim = FindSourceAnim( pVSource, g_flexkey[i].animationname );
  2375. // We only do new-style vertex animations
  2376. if ( !pVSourceAnim->newStyleVertexAnimations )
  2377. continue;
  2378. ppSortedFlexKeys[nSortedFlexKeyCount++] = &g_flexkey[i];
  2379. }
  2380. if ( nSortedFlexKeyCount > 0 )
  2381. {
  2382. qsort( ppSortedFlexKeys, nSortedFlexKeyCount, sizeof(s_flexkey_t*), FlexKeysSortFunc );
  2383. }
  2384. return nSortedFlexKeyCount;
  2385. }
  2386. static void RemapVertexAnimationsNewVersion(void)
  2387. {
  2388. // index by vertex in targets root LOD
  2389. static int model_to_vanim_vert_imap[MAXSTUDIOVERTS];
  2390. // Sort flexkeys by source
  2391. s_flexkey_t **ppSortedFlexKeys = (s_flexkey_t**)_alloca( g_numflexkeys * sizeof(s_flexkey_t*) );
  2392. int nSortedFlexKeyCount = SortFlexKeys( ppSortedFlexKeys );
  2393. if ( nSortedFlexKeyCount == 0 )
  2394. return;
  2395. // for all the sources of flexes, find a mapping of vertex animations to base model.
  2396. // There can be multiple "vertices" in the base model for each animated vertex since vertices
  2397. // are duplicated along material boundaries.
  2398. s_source_t *pVLastSource = NULL;
  2399. for ( int i = 0; i < nSortedFlexKeyCount; i++ )
  2400. {
  2401. s_flexkey_t *pFlexKey = ppSortedFlexKeys[i];
  2402. s_source_t *pVSource = pFlexKey->source;
  2403. s_sourceanim_t *pVSourceAnim = FindSourceAnim( pVSource, pFlexKey->animationname );
  2404. s_loddata_t *pLodSource = g_model[ pFlexKey->imodel ]->m_pLodData;
  2405. if ( pVSource != pVLastSource )
  2406. {
  2407. // Map vertex indices specified in the model to ones specified in the vanim data
  2408. BuildModelToVAnimMap( pVSource, NULL, pLodSource, true, model_to_vanim_vert_imap );
  2409. pVLastSource = pVSource;
  2410. }
  2411. // We only do new-style vertex animations
  2412. Assert( pVSourceAnim->newStyleVertexAnimations );
  2413. // skip if it's already been done or if has doesn't have any animations
  2414. if ( pVSourceAnim->vanim_flag )
  2415. continue;
  2416. pVSourceAnim->vanim_flag = (int *)kalloc( pVSource->numvertices, sizeof( int ));
  2417. // flag all the vertices that animate (builds the vanim_flag field of the source anim)
  2418. int j;
  2419. for ( j = i+1; j < nSortedFlexKeyCount; ++j )
  2420. {
  2421. if ( ( ppSortedFlexKeys[j]->source != pVSource ) ||
  2422. Q_stricmp( ppSortedFlexKeys[j]->animationname, pFlexKey->animationname ) )
  2423. break;
  2424. }
  2425. for ( ; i < j; ++i )
  2426. {
  2427. int k = ppSortedFlexKeys[i]->frame;
  2428. for ( int m = 0; m < pVSourceAnim->numvanims[k]; m++ )
  2429. {
  2430. pVSourceAnim->vanim_flag[ pVSourceAnim->vanim[k][m].vertex ] = 1;
  2431. }
  2432. }
  2433. --i;
  2434. // Build the vanim_mapcount, vanim_map fields of the source anim
  2435. BuildVAnimMap( pVSource, pVSourceAnim, pLodSource, model_to_vanim_vert_imap );
  2436. }
  2437. int nNumMoved = 0;
  2438. static bool pDoesMove[MAXSTUDIOVERTS];
  2439. memset( pDoesMove, 0, MAXSTUDIOVERTS * sizeof( bool ) );
  2440. for ( int i = 0; i < g_numflexkeys; i++ )
  2441. {
  2442. s_source_t *pVSource = g_flexkey[i].source;
  2443. s_sourceanim_t *pVSourceAnim = FindSourceAnim( pVSource, g_flexkey[i].animationname );
  2444. if ( !pVSourceAnim->newStyleVertexAnimations )
  2445. continue;
  2446. // Allocate g_flexkey[i].vanim
  2447. AllocateDestVAnim( g_flexkey[i], pVSourceAnim );
  2448. int nNumSrcVAnims = pVSourceAnim->numvanims[ g_flexkey[i].frame ];
  2449. s_vertanim_t *pSrcVAnim = pVSourceAnim->vanim[ g_flexkey[i].frame ];
  2450. s_vertanim_t *pDestVAnim = g_flexkey[i].vanim;
  2451. for ( int m = 0; m < nNumSrcVAnims; m++, pSrcVAnim++ )
  2452. {
  2453. // bah, only do it for ones that found a match!
  2454. if ( !pVSourceAnim->vanim_mapcount[pSrcVAnim->vertex] )
  2455. continue;
  2456. // if the changes are too small, skip 'em
  2457. // FIXME: the clamp needs to be paired with the other matching positions.
  2458. // currently this is set to the float16 min value. Sucky.
  2459. if ( DotProduct( pSrcVAnim->pos, pSrcVAnim->pos ) <= (0.001f*0.001f) /* 0.0001 */ && DotProduct( pSrcVAnim->normal, pSrcVAnim->normal ) <= 0.001f && pSrcVAnim->wrinkle <= 0.001f )
  2460. {
  2461. // printf("%4d %6.4f %6.4f %6.4f\n", pDestAnim->vertex, delta.x, delta.y, delta.z );
  2462. continue;
  2463. }
  2464. for ( int n = 0; n < pVSourceAnim->vanim_mapcount[pSrcVAnim->vertex]; n++ )
  2465. {
  2466. memcpy( pDestVAnim, pSrcVAnim, sizeof(s_vertanim_t) );
  2467. pDestVAnim->vertex = pVSourceAnim->vanim_map[pSrcVAnim->vertex][n];
  2468. if ( pDestVAnim->wrinkle != 0.0f )
  2469. {
  2470. g_flexkey[i].vanimtype = STUDIO_VERT_ANIM_WRINKLE;
  2471. }
  2472. // count all the unique verts that actually move
  2473. if ( !pDoesMove[pDestVAnim->vertex] )
  2474. {
  2475. pDoesMove[pDestVAnim->vertex] = true;
  2476. nNumMoved++;
  2477. }
  2478. g_flexkey[i].numvanims++;
  2479. pDestVAnim++;
  2480. }
  2481. }
  2482. }
  2483. if ( nNumMoved > MAXSTUDIOFLEXVERTS )
  2484. {
  2485. MdlError( "Too many flexed verts %d (%d)\n", nNumMoved, MAXSTUDIOFLEXVERTS );
  2486. }
  2487. else if ( nNumMoved > 0 && !g_quiet )
  2488. {
  2489. printf("Max flex verts %d\n", nNumMoved );
  2490. }
  2491. }
  2492. // Finds the bone index for a particular source
  2493. extern int FindLocalBoneNamed( const s_source_t *pSource, const char *pName );
  2494. //-----------------------------------------------------------------------------
  2495. // Purpose: finds the bone index in the global bone table
  2496. //-----------------------------------------------------------------------------
  2497. int findGlobalBone( const char *name )
  2498. {
  2499. name = RenameBone( name );
  2500. for ( int k = 0; k < g_numbones; k++ )
  2501. {
  2502. if ( !Q_stricmp( g_bonetable[k].name, name ) )
  2503. return k;
  2504. }
  2505. return -1;
  2506. }
  2507. bool IsGlobalBoneXSI( const char *name, const char *bonename )
  2508. {
  2509. name = RenameBone( name );
  2510. int len = strlen( name );
  2511. int len2 = strlen( bonename );
  2512. if ( len2 == len && strchr( bonename, '.' ) == NULL && stricmp( bonename, name ) == 0 )
  2513. return true;
  2514. if (len2 > len)
  2515. {
  2516. if (bonename[len2-len-1] == '.')
  2517. {
  2518. if (stricmp( &bonename[len2-len], name ) == 0)
  2519. {
  2520. return true;
  2521. }
  2522. }
  2523. }
  2524. return false;
  2525. }
  2526. int findGlobalBoneXSI( const char *name )
  2527. {
  2528. int k;
  2529. name = RenameBone( name );
  2530. for (k = 0; k < g_numbones; k++)
  2531. {
  2532. if (IsGlobalBoneXSI( name, g_bonetable[k].name ))
  2533. {
  2534. return k;
  2535. }
  2536. }
  2537. return -1;
  2538. }
  2539. //-----------------------------------------------------------------------------
  2540. // Purpose: Acculumate quaternions and try to find the swept area of rotation
  2541. // so that a "midpoint" of the rotation area can be found
  2542. //-----------------------------------------------------------------------------
  2543. void findAnimQuaternionAlignment( int k, int i, Quaternion &qBase, Quaternion &qMin, Quaternion &qMax )
  2544. {
  2545. int j;
  2546. AngleQuaternion( g_panimation[i]->sanim[0][k].rot, qBase );
  2547. qMin = qBase;
  2548. float dMin = 1.0;
  2549. qMax = qBase;
  2550. float dMax = 1.0;
  2551. for (j = 1; j < g_panimation[i]->numframes; j++)
  2552. {
  2553. Quaternion q;
  2554. AngleQuaternion( g_panimation[i]->sanim[j][k].rot, q );
  2555. QuaternionAlign( qBase, q, q );
  2556. float d0 = QuaternionDotProduct( q, qBase );
  2557. float d1 = QuaternionDotProduct( q, qMin );
  2558. float d2 = QuaternionDotProduct( q, qMax );
  2559. /*
  2560. if (i != 0)
  2561. printf("%f %f %f : %f\n", d0, d1, d2, QuaternionDotProduct( qMin, qMax ) );
  2562. */
  2563. if (d1 >= d0)
  2564. {
  2565. if (d0 < dMin)
  2566. {
  2567. qMin = q;
  2568. dMin = d0;
  2569. if (dMax == 1.0)
  2570. {
  2571. QuaternionMA( qBase, -0.01, qMin, qMax );
  2572. QuaternionAlign( qBase, qMax, qMax );
  2573. }
  2574. }
  2575. }
  2576. else if (d2 >= d0)
  2577. {
  2578. if (d0 < dMax)
  2579. {
  2580. qMax = q;
  2581. dMax = d0;
  2582. }
  2583. }
  2584. /*
  2585. if (i != 0)
  2586. printf("%f ", QuaternionDotProduct( qMin, qMax ) );
  2587. */
  2588. QuaternionSlerpNoAlign( qMin, qMax, 0.5, qBase );
  2589. Assert( qBase.IsValid() );
  2590. /*
  2591. if (i != 0)
  2592. {
  2593. QAngle ang;
  2594. QuaternionAngles( qMin, ang );
  2595. printf("(%.1f %.1f %.1f) ", ang.x, ang.y, ang.z );
  2596. QuaternionAngles( qMax, ang );
  2597. printf("(%.1f %.1f %.1f) ", ang.x, ang.y, ang.z );
  2598. QuaternionAngles( qBase, ang );
  2599. printf("(%.1f %.1f %.1f)\n", ang.x, ang.y, ang.z );
  2600. }
  2601. */
  2602. dMin = QuaternionDotProduct( qBase, qMin );
  2603. dMax = QuaternionDotProduct( qBase, qMax );
  2604. }
  2605. // printf("%s (%s): %.3f :%.3f\n", g_bonetable[k].name, g_panimation[i]->name, QuaternionDotProduct( qMin, qMax ), QuaternionDotProduct( qMin, qBase ) );
  2606. /*
  2607. if (i != 0)
  2608. exit(0);
  2609. */
  2610. }
  2611. //-----------------------------------------------------------------------------
  2612. // Purpose: For specific bones, try to find the total valid area of rotation so
  2613. // that their mid point of rotation can be used at run time to "pre-align"
  2614. // the quaternions so that rotations > 180 degrees don't get blended the
  2615. // "short way round".
  2616. //-----------------------------------------------------------------------------
  2617. void limitBoneRotations( void )
  2618. {
  2619. int i, j, k;
  2620. for (i = 0; i < g_numlimitrotation; i++)
  2621. {
  2622. Quaternion qBase;
  2623. k = findGlobalBone( g_limitrotation[i].name );
  2624. if (k == -1)
  2625. {
  2626. MdlError("unknown bone \"%s\" in $limitrotation\n", g_limitrotation[i].name );
  2627. }
  2628. AngleQuaternion( g_bonetable[k].rot, qBase );
  2629. if (g_limitrotation[i].numseq == 0)
  2630. {
  2631. for (j = 0; j < g_numani; j++)
  2632. {
  2633. if (!(g_panimation[j]->flags & STUDIO_DELTA) && g_panimation[j]->numframes > 3)
  2634. {
  2635. Quaternion qBase2, qMin2, qMax2;
  2636. findAnimQuaternionAlignment( k, j, qBase2, qMin2, qMax2 );
  2637. QuaternionAdd( qBase, qBase2, qBase );
  2638. }
  2639. }
  2640. QuaternionNormalize( qBase );
  2641. }
  2642. else
  2643. {
  2644. for (j = 0; j < g_limitrotation[i].numseq; j++)
  2645. {
  2646. }
  2647. }
  2648. /*
  2649. QAngle ang;
  2650. QuaternionAngles( qBase, ang );
  2651. printf("%s : (%.1f %.1f %.1f) \n", g_bonetable[k].name, ang.x, ang.y, ang.z );
  2652. */
  2653. g_bonetable[k].qAlignment = qBase;
  2654. g_bonetable[k].flags |= BONE_FIXED_ALIGNMENT;
  2655. // QuaternionAngles( qBase, g_panimation[0]->sanim[0][k].rot );
  2656. }
  2657. }
  2658. //-----------------------------------------------------------------------------
  2659. // Purpose: For specific bones, try to find the total valid area of rotation so
  2660. // that their mid point of rotation can be used at run time to "pre-align"
  2661. // the quaternions so that rotations > 180 degrees don't get blended the
  2662. // "short way round".
  2663. //-----------------------------------------------------------------------------
  2664. void limitIKChainLength( void )
  2665. {
  2666. int i, j, k;
  2667. matrix3x4_t boneToWorld[MAXSTUDIOSRCBONES]; // bone transformation matrix
  2668. for (k = 0; k < g_numikchains; k++)
  2669. {
  2670. bool needsFixup = false;
  2671. bool hasKnees = false;
  2672. Vector kneeDir = g_ikchain[k].link[0].kneeDir;
  2673. if (kneeDir.Length() > 0.0)
  2674. {
  2675. hasKnees = true;
  2676. }
  2677. else
  2678. {
  2679. for (i = 0; i < g_numani; i++)
  2680. {
  2681. s_animation_t *panim = g_panimation[i];
  2682. if (panim->flags & STUDIO_DELTA)
  2683. continue;
  2684. if (panim->flags & STUDIO_HIDDEN)
  2685. continue;
  2686. for (j = 0; j < panim->numframes; j++)
  2687. {
  2688. CalcBoneTransforms( panim, j, boneToWorld );
  2689. Vector worldThigh;
  2690. Vector worldKnee;
  2691. Vector worldFoot;
  2692. MatrixPosition( boneToWorld[ g_ikchain[k].link[0].bone ], worldThigh );
  2693. MatrixPosition( boneToWorld[ g_ikchain[k].link[1].bone ], worldKnee );
  2694. MatrixPosition( boneToWorld[ g_ikchain[k].link[2].bone ], worldFoot );
  2695. float l1 = (worldKnee-worldThigh).Length();
  2696. float l2 = (worldFoot-worldKnee).Length();
  2697. float l3 = (worldFoot-worldThigh).Length();
  2698. Vector ikHalf = (worldFoot+worldThigh) * 0.5;
  2699. // FIXME: what to do when the knee completely straight?
  2700. Vector ikKneeDir = worldKnee - ikHalf;
  2701. VectorNormalize( ikKneeDir );
  2702. // ikTargetKnee = ikKnee + ikKneeDir * l1;
  2703. // leg too straight to figure out knee?
  2704. if (l3 > (l1 + l2) * 0.999)
  2705. {
  2706. needsFixup = true;
  2707. }
  2708. else
  2709. {
  2710. // rotate knee into local space
  2711. Vector tmp;
  2712. VectorIRotate( ikKneeDir, boneToWorld[ g_ikchain[k].link[0].bone ], tmp );
  2713. float bend = (((DotProduct( worldThigh - worldKnee, worldFoot - worldKnee ) ) / (l1 * l3)) + 1) / 2.0;
  2714. kneeDir += tmp * bend;
  2715. hasKnees = true;
  2716. }
  2717. }
  2718. }
  2719. }
  2720. if (!needsFixup)
  2721. continue;
  2722. if (!hasKnees)
  2723. {
  2724. MdlWarning( "ik rules for %s but no clear knee direction\n", g_ikchain[k].name );
  2725. continue;
  2726. }
  2727. VectorNormalize( kneeDir );
  2728. g_ikchain[k].link[0].kneeDir = kneeDir;
  2729. if (g_verbose)
  2730. {
  2731. printf("knee %s %f %f %f\n", g_ikchain[k].name, kneeDir.x, kneeDir.y, kneeDir.z );
  2732. }
  2733. #if 0
  2734. // don't bother for now, storing the knee direction should fix the runtime problems.
  2735. for (i = 0; i < g_numani; i++)
  2736. {
  2737. s_animation_t *panim = g_panimation[i];
  2738. if (panim->flags & STUDIO_DELTA)
  2739. continue;
  2740. for (j = 0; j < panim->numframes; j++)
  2741. {
  2742. CalcBoneTransforms( panim, j, boneToWorld );
  2743. Vector worldFoot;
  2744. MatrixPosition( boneToWorld[ g_ikchain[k].link[2].bone ], worldFoot );
  2745. Vector targetKneeDir;
  2746. VectorRotate( kneeDir, boneToWorld[ g_ikchain[k].link[0].bone ], targetKneeDir );
  2747. // run it through the normal IK solver, this should move the foot positions to someplace legal
  2748. Studio_SolveIK( g_ikchain[k].link[0].bone, g_ikchain[k].link[1].bone, g_ikchain[k].link[2].bone, worldFoot, targetKneeDir, boneToWorld );
  2749. solveBone( panim, j, g_ikchain[k].link[0].bone, boneToWorld );
  2750. solveBone( panim, j, g_ikchain[k].link[1].bone, boneToWorld );
  2751. solveBone( panim, j, g_ikchain[k].link[2].bone, boneToWorld );
  2752. }
  2753. }
  2754. #endif
  2755. }
  2756. }
  2757. //-----------------------------------------------------------------------------
  2758. // Purpose: build "next node" table that links every transition "node" to
  2759. // every other transition "node", if possible
  2760. //-----------------------------------------------------------------------------
  2761. void MakeTransitions( )
  2762. {
  2763. int i, j, k;
  2764. bool iHit = g_bMultistageGraph;
  2765. // add in direct node transitions
  2766. for (i = 0; i < g_sequence.Count(); i++)
  2767. {
  2768. if (g_sequence[i].entrynode != g_sequence[i].exitnode)
  2769. {
  2770. g_xnode[g_sequence[i].entrynode-1][g_sequence[i].exitnode-1] = g_sequence[i].exitnode;
  2771. if (g_sequence[i].nodeflags)
  2772. {
  2773. g_xnode[g_sequence[i].exitnode-1][g_sequence[i].entrynode-1] = g_sequence[i].entrynode;
  2774. }
  2775. }
  2776. }
  2777. // calculate multi-stage transitions
  2778. while (iHit)
  2779. {
  2780. iHit = false;
  2781. for (i = 1; i <= g_numxnodes; i++)
  2782. {
  2783. for (j = 1; j <= g_numxnodes; j++)
  2784. {
  2785. // if I can't go there directly
  2786. if (i != j && g_xnode[i-1][j-1] == 0)
  2787. {
  2788. for (k = 1; k <= g_numxnodes; k++)
  2789. {
  2790. // but I found someone who knows how that I can get to
  2791. if (g_xnode[k-1][j-1] > 0 && g_xnode[i-1][k-1] > 0)
  2792. {
  2793. // then go to them
  2794. g_xnode[i-1][j-1] = -g_xnode[i-1][k-1];
  2795. iHit = true;
  2796. break;
  2797. }
  2798. }
  2799. }
  2800. }
  2801. }
  2802. // reset previous pass so the links can be used in the next pass
  2803. for (i = 1; i <= g_numxnodes; i++)
  2804. {
  2805. for (j = 1; j <= g_numxnodes; j++)
  2806. {
  2807. g_xnode[i-1][j-1] = abs( g_xnode[i-1][j-1] );
  2808. }
  2809. }
  2810. }
  2811. // add in allowed "skips"
  2812. for (i = 0; i < g_numxnodeskips; i++)
  2813. {
  2814. g_xnode[g_xnodeskip[i][0]-1][g_xnodeskip[i][1]-1] = 0;
  2815. }
  2816. if (g_bDumpGraph)
  2817. {
  2818. for (j = 1; j <= g_numxnodes; j++)
  2819. {
  2820. printf("%2d : %s\n", j, g_xnodename[j] );
  2821. }
  2822. printf(" " );
  2823. for (j = 1; j <= g_numxnodes; j++)
  2824. {
  2825. printf("%2d ", j );
  2826. }
  2827. printf("\n" );
  2828. for (i = 1; i <= g_numxnodes; i++)
  2829. {
  2830. printf("%2d: ", i );
  2831. for (j = 1; j <= g_numxnodes; j++)
  2832. {
  2833. printf("%2d ", g_xnode[i-1][j-1] );
  2834. }
  2835. printf("\n" );
  2836. }
  2837. }
  2838. }
  2839. int VectorCompareEpsilon(const Vector& v1, const Vector& v2, float epsilon)
  2840. {
  2841. int i;
  2842. for (i=0 ; i<3 ; i++)
  2843. if (fabs(v1[i] - v2[i]) > epsilon)
  2844. return 0;
  2845. return 1;
  2846. }
  2847. int RadianEulerCompareEpsilon(const RadianEuler& v1, const RadianEuler& v2, float epsilon)
  2848. {
  2849. int i;
  2850. for (i=0 ; i<3 ; i++)
  2851. {
  2852. // clamp to 2pi
  2853. float a1 = fmod(v1[i],(float) (2*M_PI));
  2854. float a2 = fmod(v2[i],(float) (2*M_PI));
  2855. float delta = fabs(a1-a2);
  2856. // use the smaller angle (359 == 1 degree off)
  2857. if ( delta > M_PI )
  2858. {
  2859. delta = 2*M_PI - delta;
  2860. }
  2861. if (delta > epsilon)
  2862. return 0;
  2863. }
  2864. return 1;
  2865. }
  2866. bool AnimationDifferent( const Vector& startPos, const RadianEuler& startRot, const Vector& pos, const RadianEuler& rot )
  2867. {
  2868. if ( !VectorCompareEpsilon( startPos, pos, 0.01 ) )
  2869. return true;
  2870. if ( !RadianEulerCompareEpsilon( startRot, rot, 0.01 ) )
  2871. return true;
  2872. return false;
  2873. }
  2874. bool BoneHasAnimation( const char *pName )
  2875. {
  2876. bool first = true;
  2877. Vector pos;
  2878. RadianEuler rot;
  2879. if ( !g_numani )
  2880. return false;
  2881. int globalIndex = findGlobalBone( pName );
  2882. // don't check root bones for animation
  2883. if (globalIndex >= 0 && g_bonetable[globalIndex].parent == -1)
  2884. return true;
  2885. // find used bones per g_model
  2886. for (int i = 0; i < g_numani; i++)
  2887. {
  2888. s_source_t *psource = g_panimation[i]->source;
  2889. const char *pAnimationName = g_panimation[i]->animationname;
  2890. s_sourceanim_t *pSourceAnim = FindSourceAnim( psource, pAnimationName );
  2891. int boneIndex = FindLocalBoneNamed(psource, pName);
  2892. // not in this source?
  2893. if (boneIndex < 0)
  2894. continue;
  2895. // this is not right, but enough of the bones are moved unintentionally between
  2896. // animations that I put this in to catch them.
  2897. first = true;
  2898. int n = g_panimation[i]->startframe - pSourceAnim->startframe;
  2899. // printf("%s %d:%d\n", g_panimation[i]->filename, g_panimation[i]->startframe, psource->startframe );
  2900. for (int j = 0; j < g_panimation[i]->numframes; j++)
  2901. {
  2902. if ( first )
  2903. {
  2904. VectorCopy( pSourceAnim->rawanim[j+n][boneIndex].pos, pos );
  2905. VectorCopy( pSourceAnim->rawanim[j+n][boneIndex].rot, rot );
  2906. first = false;
  2907. }
  2908. else
  2909. {
  2910. if ( AnimationDifferent( pos, rot, pSourceAnim->rawanim[j+n][boneIndex].pos, pSourceAnim->rawanim[j+n][boneIndex].rot ) )
  2911. return true;
  2912. }
  2913. }
  2914. }
  2915. return false;
  2916. }
  2917. bool BoneHasAttachments( char const *pname )
  2918. {
  2919. for (int k = 0; k < g_numattachments; k++)
  2920. {
  2921. if ( !stricmp( g_attachment[k].bonename, pname ) )
  2922. {
  2923. return true;
  2924. }
  2925. }
  2926. return false;
  2927. }
  2928. bool BoneIsProcedural( char const *pname )
  2929. {
  2930. int k;
  2931. for (k = 0; k < g_numaxisinterpbones; k++)
  2932. {
  2933. if (! stricmp( g_axisinterpbones[k].bonename, pname ) )
  2934. {
  2935. return true;
  2936. }
  2937. }
  2938. for (k = 0; k < g_numquatinterpbones; k++)
  2939. {
  2940. if (IsGlobalBoneXSI( g_quatinterpbones[k].bonename, pname ) )
  2941. {
  2942. return true;
  2943. }
  2944. }
  2945. for (k = 0; k < g_numaimatbones; k++)
  2946. {
  2947. if (IsGlobalBoneXSI( g_aimatbones[k].bonename, pname ) )
  2948. {
  2949. return true;
  2950. }
  2951. }
  2952. for (k = 0; k < g_numjigglebones; k++)
  2953. {
  2954. if (! stricmp( g_jigglebones[k].bonename, pname ) )
  2955. {
  2956. return true;
  2957. }
  2958. }
  2959. return false;
  2960. }
  2961. bool BoneIsIK( char const *pname )
  2962. {
  2963. int k;
  2964. // tag bones used by ikchains
  2965. for (k = 0; k < g_numikchains; k++)
  2966. {
  2967. if ( !stricmp( g_ikchain[k].bonename, pname ) )
  2968. {
  2969. return true;
  2970. }
  2971. }
  2972. return false;
  2973. }
  2974. bool BoneShouldCollapse( char const *pname )
  2975. {
  2976. int k;
  2977. for (k = 0; k < g_collapse.Count(); k++)
  2978. {
  2979. if (stricmp( g_collapse[k], pname ) == 0)
  2980. {
  2981. return true;
  2982. }
  2983. }
  2984. return (!BoneHasAnimation( pname ) && !BoneIsProcedural( pname ) && !BoneIsIK( pname ) /* && !BoneHasAttachments( pname ) */);
  2985. }
  2986. //-----------------------------------------------------------------------------
  2987. // Purpose: Collapse vertex assignments up to parent on bones that are not needed
  2988. // This can optimize a model substantially if the animator is using
  2989. // lots of helper bones with no animation.
  2990. //-----------------------------------------------------------------------------
  2991. void CollapseBones( void )
  2992. {
  2993. int j, k;
  2994. int count = 0;
  2995. for (k = 0; k < g_numbones; k++)
  2996. {
  2997. if ( g_bonetable[k].bDontCollapse )
  2998. continue;
  2999. if ( (g_bonetable[k].flags != 0 || g_bonetable[k].bPreDefined) && !BoneShouldCollapse( g_bonetable[k].name ) )
  3000. {
  3001. // printf("skipping %s : %d\n", g_bonetable[k].name, g_bonetable[k].flags );
  3002. continue;
  3003. }
  3004. count++;
  3005. if( !g_quiet && g_verbose )
  3006. {
  3007. printf("collapsing %s\n", g_bonetable[k].name );
  3008. }
  3009. g_numbones--;
  3010. int m = g_bonetable[k].parent;
  3011. for (j = k; j < g_numbones; j++)
  3012. {
  3013. g_bonetable[j] = g_bonetable[j+1];
  3014. if (g_bonetable[j].parent == k)
  3015. {
  3016. g_bonetable[j].parent = m;
  3017. }
  3018. else if (g_bonetable[j].parent >= k)
  3019. {
  3020. g_bonetable[j].parent = g_bonetable[j].parent - 1;
  3021. }
  3022. }
  3023. k--;
  3024. }
  3025. if( !g_quiet && count)
  3026. {
  3027. printf("Collapsed %d bones\n", count );
  3028. }
  3029. }
  3030. //-----------------------------------------------------------------------------
  3031. // Purpose: replace all animation, rotation and translation, etc. with a single bone
  3032. //-----------------------------------------------------------------------------
  3033. void MakeStaticProp()
  3034. {
  3035. int i, j, k;
  3036. matrix3x4_t rotated;
  3037. AngleMatrix( g_defaultrotation, rotated );
  3038. // FIXME: missing attachment point recalcs!
  3039. // replace bone 0 with "static_prop" bone and attach everything to it.
  3040. for (i = 0; i < g_numsources; i++)
  3041. {
  3042. s_source_t *psource = g_source[i];
  3043. strcpy( psource->localBone[0].name, "static_prop" );
  3044. psource->localBone[0].parent = -1;
  3045. for (k = 1; k < psource->numbones; k++)
  3046. {
  3047. psource->localBone[k].parent = -1;
  3048. }
  3049. rotated[0][3] = g_defaultadjust[0];
  3050. rotated[1][3] = g_defaultadjust[1];
  3051. rotated[2][3] = g_defaultadjust[2];
  3052. Vector mins, maxs;
  3053. ClearBounds( mins, maxs );
  3054. for (j = 0; j < psource->numvertices; j++)
  3055. {
  3056. for (k = 0; k < psource->vertex[j].boneweight.numbones; k++)
  3057. {
  3058. // attach everything to root
  3059. psource->vertex[j].boneweight.bone[k] = 0;
  3060. }
  3061. // **shift everything into identity space**
  3062. // position
  3063. Vector tmp;
  3064. VectorTransform( psource->vertex[j].position, rotated, tmp );
  3065. VectorCopy( tmp, psource->vertex[j].position );
  3066. // normal
  3067. VectorRotate( psource->vertex[j].normal, rotated, tmp );
  3068. VectorCopy( tmp, psource->vertex[j].normal );
  3069. // tangentS
  3070. VectorRotate( psource->vertex[j].tangentS.AsVector3D(), rotated, tmp );
  3071. VectorCopy( tmp, psource->vertex[j].tangentS.AsVector3D() );
  3072. // incrementally compute identity space bbox
  3073. AddPointToBounds( psource->vertex[j].position, mins, maxs );
  3074. }
  3075. if ( g_centerstaticprop )
  3076. {
  3077. const char *pAttachmentName = "placementOrigin";
  3078. bool bFound = false;
  3079. for ( k = 0; k < g_numattachments; k++ )
  3080. {
  3081. if ( !Q_stricmp( g_attachment[k].name, pAttachmentName ) )
  3082. {
  3083. bFound = true;
  3084. break;
  3085. }
  3086. }
  3087. if ( !bFound )
  3088. {
  3089. g_PropCenterOffset = -0.5f * (mins + maxs);
  3090. }
  3091. for ( j = 0; j < psource->numvertices; j++ )
  3092. {
  3093. psource->vertex[j].position += g_PropCenterOffset;
  3094. }
  3095. if ( !bFound )
  3096. {
  3097. // now add an attachment point to store this offset
  3098. Q_strncpy( g_attachment[g_numattachments].name, pAttachmentName, sizeof(g_attachment[g_numattachments].name) );
  3099. Q_strncpy( g_attachment[g_numattachments].bonename, "static_prop", sizeof(g_attachment[g_numattachments].name) );
  3100. g_attachment[g_numattachments].bone = 0;
  3101. g_attachment[g_numattachments].type = 0;
  3102. AngleMatrix( vec3_angle, g_PropCenterOffset, g_attachment[g_numattachments].local );
  3103. g_numattachments++;
  3104. }
  3105. }
  3106. // force the animation to be identity
  3107. s_sourceanim_t *pSourceAnim = FindSourceAnim( psource, "BindPose" );
  3108. pSourceAnim->rawanim[0][0].pos = Vector( 0, 0, 0 );
  3109. pSourceAnim->rawanim[0][0].rot = RadianEuler( 0, 0, 0 );
  3110. // make an identity boneToPose transform
  3111. AngleMatrix( QAngle( 0, 0, 0 ), psource->boneToPose[0] );
  3112. // make it all a single frame animation
  3113. pSourceAnim->numframes = 1;
  3114. pSourceAnim->startframe = 0;
  3115. pSourceAnim->endframe = 1;
  3116. }
  3117. // throw away all animations
  3118. g_numani = 1;
  3119. g_panimation[0]->numframes = 1;
  3120. g_panimation[0]->startframe = 0;
  3121. g_panimation[0]->endframe = 1;
  3122. Q_strncpy( g_panimation[0]->animationname, "BindPose", sizeof(g_panimation[0]->animationname) );
  3123. g_panimation[0]->rotation = RadianEuler( 0, 0, 0 );
  3124. g_panimation[0]->adjust = Vector( 0, 0, 0 );
  3125. // throw away all vertex animations
  3126. g_numflexkeys = 0;
  3127. g_defaultflexkey = NULL;
  3128. // Recalc attachment points:
  3129. for( i = 0; i < g_numattachments; i++ )
  3130. {
  3131. if( g_centerstaticprop && ( i == g_numattachments - 1 ) )
  3132. continue;
  3133. ConcatTransforms( rotated, g_attachment[i].local, g_attachment[i].local );
  3134. Q_strncpy( g_attachment[i].bonename, "static_prop", sizeof(g_attachment[i].name) );
  3135. g_attachment[i].bone = 0;
  3136. g_attachment[i].type = 0;
  3137. }
  3138. }
  3139. //-----------------------------------------------------------------------------
  3140. // Marks the boneref all the way up the bone hierarchy
  3141. //-----------------------------------------------------------------------------
  3142. static void UpdateBonerefRecursive( s_source_t *psource, int nBoneIndex, int nFlags )
  3143. {
  3144. if ( nFlags == 0 )
  3145. return;
  3146. psource->boneref[nBoneIndex] |= nFlags;
  3147. // Chain the flag up the parent
  3148. int n = psource->localBone[nBoneIndex].parent;
  3149. while (n != -1)
  3150. {
  3151. psource->boneref[n] |= psource->boneref[nBoneIndex];
  3152. n = psource->localBone[n].parent;
  3153. }
  3154. }
  3155. //-----------------------------------------------------------------------------
  3156. // Purpose: Returns the axis of the bone after remapping. Axis 0:X, 1:Y, 2:Z
  3157. // If the bone has a parent, axis is returned as is, if bone does not
  3158. // have a parent then the $upaxis determines how the axes are mapped.
  3159. // Only $upaxis Y is supported (see comment in Cmd_UpAxis).
  3160. //-----------------------------------------------------------------------------
  3161. int GetRemappedBoneAxis( int nBoneIndex, int nAxis )
  3162. {
  3163. if ( nBoneIndex < 0 || nBoneIndex >= g_numbones )
  3164. return nAxis;
  3165. if ( g_bonetable[nBoneIndex].parent >= 0 )
  3166. return nAxis;
  3167. // Y Up
  3168. if ( g_defaultrotation.x == static_cast< float >( M_PI / 2.0f ) && g_defaultrotation.y == 0.0f && g_defaultrotation.z == static_cast< float >( M_PI / 2.0f ) )
  3169. {
  3170. static const int nAxisMap[3] = { 1, 2, 0 };
  3171. return nAxisMap[ nAxis ];
  3172. }
  3173. // Default Z Up
  3174. return nAxis;
  3175. }
  3176. //-----------------------------------------------------------------------------
  3177. // Purpose: Map the flex driver bones to the global bone table
  3178. // Also cleans up any that do not match to a global bone
  3179. //-----------------------------------------------------------------------------
  3180. void MapFlexDriveBonesToGlobalBoneTable()
  3181. {
  3182. CDmeBoneFlexDriverList *pDmeBoneFlexDriverList = GetElement< CDmeBoneFlexDriverList >( g_hDmeBoneFlexDriverList );
  3183. if ( !pDmeBoneFlexDriverList )
  3184. return;
  3185. // Loop backwards so we can remove elements as we go
  3186. for ( int i = pDmeBoneFlexDriverList->m_eBoneFlexDriverList.Count() - 1; i >= 0; --i )
  3187. {
  3188. CDmeBoneFlexDriver *pDmeBoneFlexDriver = pDmeBoneFlexDriverList->m_eBoneFlexDriverList[i];
  3189. if ( !pDmeBoneFlexDriver )
  3190. {
  3191. pDmeBoneFlexDriverList->m_eBoneFlexDriverList.Remove( i );
  3192. continue;
  3193. }
  3194. for ( int j = 0; j < g_numbones; ++j )
  3195. {
  3196. if ( !Q_stricmp( g_bonetable[j].name, pDmeBoneFlexDriver->m_sBoneName.Get() ) )
  3197. {
  3198. if ( g_bonetable[j].flags & BONE_ALWAYS_PROCEDURAL )
  3199. {
  3200. MdlWarning( "DmeBoneFlexDriver Bone: %s is marked procedural, Ignoring flex drivers\n", pDmeBoneFlexDriver->m_sBoneName.Get() );
  3201. pDmeBoneFlexDriverList->m_eBoneFlexDriverList.Remove( i );
  3202. pDmeBoneFlexDriver = NULL;
  3203. }
  3204. pDmeBoneFlexDriver->SetValue( "__boneIndex", j );
  3205. // Map the axis for Y up stuff
  3206. for ( int k = 0; k < pDmeBoneFlexDriver->m_eControlList.Count(); ++k )
  3207. {
  3208. pDmeBoneFlexDriver->m_eControlList[k]->m_nBoneComponent = GetRemappedBoneAxis( j, pDmeBoneFlexDriver->m_eControlList[k]->m_nBoneComponent );
  3209. }
  3210. break;
  3211. }
  3212. }
  3213. // Was removed because it was referencing a procedural bone
  3214. if ( !pDmeBoneFlexDriver )
  3215. continue;
  3216. CDmAttribute *pBoneIndexAttr = pDmeBoneFlexDriver->GetAttribute( "__boneIndex" );
  3217. if ( pBoneIndexAttr )
  3218. {
  3219. pBoneIndexAttr->AddFlag( FATTRIB_DONTSAVE );
  3220. }
  3221. else
  3222. {
  3223. MdlWarning( "DmeBoneFlexDriver Bone: %s - No Bone Found With That Name, Ignoring\n", pDmeBoneFlexDriver->m_sBoneName.Get() );
  3224. pDmeBoneFlexDriverList->m_eBoneFlexDriverList.Remove( i );
  3225. }
  3226. }
  3227. }
  3228. //-----------------------------------------------------------------------------
  3229. // Purpose: Tag bones in the specified source that are used as a bone flex driver
  3230. // Also cleans up any empty bone flex driver elements
  3231. // Also tags the DmeBoneFlexDriverControl with
  3232. //-----------------------------------------------------------------------------
  3233. void TagFlexDriverBones( s_source_t *pSource )
  3234. {
  3235. CDmeBoneFlexDriverList *pDmeBoneFlexDriverList = GetElement< CDmeBoneFlexDriverList >( g_hDmeBoneFlexDriverList );
  3236. if ( !pDmeBoneFlexDriverList )
  3237. return;
  3238. // Loop backwards so we can remove elements as we go
  3239. for ( int i = pDmeBoneFlexDriverList->m_eBoneFlexDriverList.Count() - 1; i >= 0; --i )
  3240. {
  3241. CDmeBoneFlexDriver *pDmeBoneFlexDriver = pDmeBoneFlexDriverList->m_eBoneFlexDriverList[i];
  3242. if ( !pDmeBoneFlexDriver )
  3243. {
  3244. pDmeBoneFlexDriverList->m_eBoneFlexDriverList.Remove( i );
  3245. continue;
  3246. }
  3247. for ( int j = pDmeBoneFlexDriver->m_eControlList.Count() - 1; j >= 0; --j )
  3248. {
  3249. CDmeBoneFlexDriverControl *pDmeBoneFlexDriverControl = pDmeBoneFlexDriver->m_eControlList[j];
  3250. if ( !pDmeBoneFlexDriverControl )
  3251. {
  3252. pDmeBoneFlexDriver->m_eControlList.Remove( j );
  3253. continue;
  3254. }
  3255. if ( pDmeBoneFlexDriverControl->m_nBoneComponent < STUDIO_BONE_FLEX_TX || pDmeBoneFlexDriverControl->m_nBoneComponent > STUDIO_BONE_FLEX_TZ )
  3256. {
  3257. MdlWarning( "DmeBoneFlexDriver Bone: %s - Flex Controller: %s, Bone Component Out Of Range: %d [0-2], Ignoring\n", pDmeBoneFlexDriver->m_sBoneName.Get(), pDmeBoneFlexDriverControl->m_sFlexControllerName.Get(), pDmeBoneFlexDriverControl->m_nBoneComponent.Get() );
  3258. pDmeBoneFlexDriver->m_eControlList.Remove( j );
  3259. continue;
  3260. }
  3261. for ( int k = 0; k < g_numflexcontrollers; ++k )
  3262. {
  3263. if ( !Q_stricmp( g_flexcontroller[k].name, pDmeBoneFlexDriverControl->m_sFlexControllerName.Get() ) )
  3264. {
  3265. pDmeBoneFlexDriverControl->SetValue( "__flexControlIndex", k );
  3266. break;
  3267. }
  3268. }
  3269. if ( !pDmeBoneFlexDriverControl->HasAttribute( "__flexControlIndex" ) )
  3270. {
  3271. MdlWarning( "DmeBoneFlexDriver Bone: %s - No Flex Controller Named: %s, Ignoring\n", pDmeBoneFlexDriver->m_sBoneName.Get(), pDmeBoneFlexDriverControl->m_sFlexControllerName.Get() );
  3272. pDmeBoneFlexDriver->m_eControlList.Remove( j );
  3273. }
  3274. }
  3275. if ( pDmeBoneFlexDriver->m_eControlList.Count() <= 0 )
  3276. {
  3277. MdlWarning( "DmeBoneFlexDriver Bone: %s - No Flex Controllers Defined, Ignoring\n", pDmeBoneFlexDriver->m_sBoneName.Get() );
  3278. pDmeBoneFlexDriverList->m_eBoneFlexDriverList.Remove( i );
  3279. continue;
  3280. }
  3281. for ( int j = 0; j < pSource->numbones; ++j )
  3282. {
  3283. if ( !Q_stricmp( pSource->localBone[j].name, pDmeBoneFlexDriver->m_sBoneName.Get() ) )
  3284. {
  3285. // Mark used by all LODs
  3286. pSource->boneflags[j] |= BONE_USED_BY_VERTEX_MASK;
  3287. }
  3288. }
  3289. }
  3290. }
  3291. //-----------------------------------------------------------------------------
  3292. // Purpose: set "boneref" for all the source bones used by vertices, attachments, eyeballs, etc.
  3293. //-----------------------------------------------------------------------------
  3294. void TagUsedBones( )
  3295. {
  3296. int i, j, k;
  3297. int n;
  3298. // find used bones per g_model
  3299. for (i = 0; i < g_numsources; i++)
  3300. {
  3301. s_source_t *psource = g_source[i];
  3302. for (k = 0; k < MAXSTUDIOSRCBONES; k++)
  3303. {
  3304. psource->boneflags[k] = 0;
  3305. psource->boneref[k] = 0;
  3306. }
  3307. if (!psource->isActiveModel)
  3308. continue;
  3309. // printf("active: %s\n", psource->filename );
  3310. for (j = 0; j < psource->numvertices; j++)
  3311. {
  3312. for (k = 0; k < psource->vertex[j].boneweight.numbones; k++)
  3313. {
  3314. psource->boneflags[psource->vertex[j].boneweight.bone[k]] |= BONE_USED_BY_VERTEX_LOD0;
  3315. }
  3316. }
  3317. }
  3318. // find used bones per g_model
  3319. for (i = 0; i < g_numsources; i++)
  3320. {
  3321. s_source_t *psource = g_source[i];
  3322. // FIXME: this is in the wrong place. The attachment may be rigid and it never defined in a reference file
  3323. for (k = 0; k < g_numattachments; k++)
  3324. {
  3325. for (j = 0; j < psource->numbones; j++)
  3326. {
  3327. if ( !stricmp( g_attachment[k].bonename, psource->localBone[j].name ) )
  3328. {
  3329. // this bone is a keeper with or without associated vertices
  3330. // because an attachment point depends on it.
  3331. if (g_attachment[k].type & IS_RIGID)
  3332. {
  3333. for (n = j; n != -1; n = psource->localBone[n].parent)
  3334. {
  3335. if (psource->boneflags[n] & BONE_USED_BY_VERTEX_LOD0)
  3336. {
  3337. psource->boneflags[n] |= BONE_USED_BY_ATTACHMENT;
  3338. break;
  3339. }
  3340. }
  3341. }
  3342. else
  3343. {
  3344. psource->boneflags[j] |= BONE_USED_BY_ATTACHMENT;
  3345. }
  3346. }
  3347. }
  3348. }
  3349. for (k = 0; k < g_numikchains; k++)
  3350. {
  3351. for (j = 0; j < psource->numbones; j++)
  3352. {
  3353. if ( !stricmp( g_ikchain[k].bonename, psource->localBone[j].name ) )
  3354. {
  3355. // this bone is a keeper with or without associated vertices
  3356. // because a ikchain depends on it.
  3357. psource->boneflags[j] |= BONE_USED_BY_ATTACHMENT;
  3358. }
  3359. }
  3360. }
  3361. for (k = 0; k < g_nummouths; k++)
  3362. {
  3363. for (j = 0; j < psource->numbones; j++)
  3364. {
  3365. if ( !stricmp( g_mouth[k].bonename, psource->localBone[j].name ) )
  3366. {
  3367. // this bone is a keeper with or without associated vertices
  3368. // because a mouth shader depends on it.
  3369. psource->boneflags[j] |= BONE_USED_BY_ATTACHMENT;
  3370. }
  3371. }
  3372. }
  3373. // Tag all bones marked as being used by bonemerge
  3374. int nBoneMergeCount = g_BoneMerge.Count();
  3375. for ( k = 0; k < nBoneMergeCount; ++k )
  3376. {
  3377. for ( j = 0; j < psource->numbones; j++ )
  3378. {
  3379. if ( stricmp( g_BoneMerge[k].bonename, psource->localBone[j].name ) )
  3380. continue;
  3381. psource->boneflags[j] |= BONE_USED_BY_BONE_MERGE;
  3382. }
  3383. }
  3384. // Tag bones used as bone flex drivers, these need to be client side only
  3385. TagFlexDriverBones( psource );
  3386. // NOTE: This must come last; after all flags have been set!
  3387. // tag bonerefs as being used the union of the boneflags all their children
  3388. for (k = 0; k < psource->numbones; k++)
  3389. {
  3390. UpdateBonerefRecursive( psource, k, psource->boneflags[k] );
  3391. }
  3392. }
  3393. // tag all eyeball bones
  3394. for (i = 0; i < g_nummodelsbeforeLOD; i++)
  3395. {
  3396. s_source_t *psource = g_model[i]->source;
  3397. for (k = 0; k < g_model[i]->numeyeballs; k++)
  3398. {
  3399. psource->boneref[g_model[i]->eyeball[k].bone] |= BONE_USED_BY_ATTACHMENT;
  3400. }
  3401. }
  3402. }
  3403. //-----------------------------------------------------------------------------
  3404. // Purpose: change the names in the source files for bones that max auto-renamed on us
  3405. //-----------------------------------------------------------------------------
  3406. void RenameBones( )
  3407. {
  3408. int i, j, k;
  3409. // rename source bones if needed
  3410. for (i = 0; i < g_numsources; i++)
  3411. {
  3412. for (j = 0; j < g_source[i]->numbones; j++)
  3413. {
  3414. for (k = 0; k < g_numrenamedbones; k++)
  3415. {
  3416. if (!stricmp( g_source[i]->localBone[j].name, g_renamedbone[k].from))
  3417. {
  3418. strcpy( g_source[i]->localBone[j].name, g_renamedbone[k].to );
  3419. break;
  3420. }
  3421. }
  3422. }
  3423. }
  3424. }
  3425. const char *RenameBone( const char *pName )
  3426. {
  3427. for ( int k = 0; k < g_numrenamedbones; k++)
  3428. {
  3429. if ( !Q_stricmp( pName, g_renamedbone[k].from ) )
  3430. return g_renamedbone[k].to;
  3431. }
  3432. return pName;
  3433. }
  3434. //-----------------------------------------------------------------------------
  3435. // Tags bones in the global bone table
  3436. //-----------------------------------------------------------------------------
  3437. void TagUsedImportedBones()
  3438. {
  3439. // NOTE: This has to happen because some bones referenced by bonemerge
  3440. // can be set up using the importbones feature
  3441. int k, j;
  3442. // Tag all bones marked as being used by bonemerge
  3443. int nBoneMergeCount = g_BoneMerge.Count();
  3444. for ( k = 0; k < nBoneMergeCount; ++k )
  3445. {
  3446. for ( j = 0; j < g_numbones; j++ )
  3447. {
  3448. if ( stricmp( g_BoneMerge[k].bonename, g_bonetable[j].name ) )
  3449. continue;
  3450. g_bonetable[j].flags |= BONE_USED_BY_BONE_MERGE;
  3451. }
  3452. }
  3453. }
  3454. //-----------------------------------------------------------------------------
  3455. // Purpose: look through all the sources and build a table of used bones
  3456. //-----------------------------------------------------------------------------
  3457. int BuildGlobalBonetable( )
  3458. {
  3459. int i, j, k, n;
  3460. int iError = 0;
  3461. g_numbones = 0;
  3462. for (i = 0; i < MAXSTUDIOSRCBONES; i++)
  3463. {
  3464. SetIdentityMatrix( g_bonetable[i].srcRealign );
  3465. }
  3466. // insert predefined bones first
  3467. for (i = 0; i < g_numimportbones; i++)
  3468. {
  3469. k = findGlobalBone( g_importbone[i].name );
  3470. if (k == -1)
  3471. {
  3472. k = g_numbones;
  3473. V_strcpy_safe( g_bonetable[k].name, g_importbone[i].name );
  3474. if ( strlen( g_importbone[i].parent ) == 0 )
  3475. {
  3476. g_bonetable[k].parent = -1;
  3477. }
  3478. else
  3479. {
  3480. // FIXME: This won't work if the imported bone refers to
  3481. // another imported bone which is further along in the list
  3482. g_bonetable[k].parent = findGlobalBone( g_importbone[i].parent );
  3483. if ( g_bonetable[k].parent == -1 )
  3484. {
  3485. Warning("Imported bone %s tried to access parent bone %s and failed!\n",
  3486. g_importbone[i].name, g_importbone[i].parent );
  3487. }
  3488. }
  3489. g_bonetable[k].bPreDefined = true;
  3490. g_bonetable[k].rawLocal = g_importbone[i].rawLocal;
  3491. g_bonetable[k].rawLocalOriginal = g_bonetable[k].rawLocal;
  3492. g_numbones++;
  3493. }
  3494. g_bonetable[k].bDontCollapse = true;
  3495. g_bonetable[k].srcRealign = g_importbone[i].srcRealign;
  3496. g_bonetable[k].bPreAligned = true;
  3497. }
  3498. TagUsedImportedBones();
  3499. // union of all used bones
  3500. for ( i = 0; i < g_numsources; i++ )
  3501. {
  3502. s_source_t *psource = g_source[i];
  3503. // skip sources with no bones
  3504. if (psource->numbones == 0)
  3505. continue;
  3506. matrix3x4_t srcBoneToWorld[MAXSTUDIOSRCBONES];
  3507. s_sourceanim_t *pSourceAnim = FindSourceAnim( psource, "BindPose" );
  3508. if ( !pSourceAnim )
  3509. {
  3510. pSourceAnim = &psource->m_Animations[0];
  3511. }
  3512. BuildRawTransforms( psource, pSourceAnim->animationname, 0, srcBoneToWorld );
  3513. for ( j = 0; j < psource->numbones; j++ )
  3514. {
  3515. if ( g_collapse_bones_aggressive )
  3516. {
  3517. if ( psource->boneflags[j] == 0 )
  3518. continue;
  3519. }
  3520. else
  3521. {
  3522. if ( psource->boneref[j] == 0 )
  3523. continue;
  3524. }
  3525. k = findGlobalBone( psource->localBone[j].name );
  3526. if (k == -1)
  3527. {
  3528. // create new bone
  3529. k = g_numbones;
  3530. V_strcpy_safe( g_bonetable[k].name, psource->localBone[j].name );
  3531. if ((n = psource->localBone[j].parent) != -1)
  3532. g_bonetable[k].parent = findGlobalBone( psource->localBone[n].name );
  3533. else
  3534. g_bonetable[k].parent = -1;
  3535. g_bonetable[k].bonecontroller = 0;
  3536. g_bonetable[k].flags = psource->boneflags[j];
  3537. if ( g_bonetable[k].parent == -1 || !g_bonetable[g_bonetable[k].parent].bPreAligned )
  3538. {
  3539. AngleMatrix( pSourceAnim->rawanim[0][j].rot, pSourceAnim->rawanim[0][j].pos, g_bonetable[k].rawLocal );
  3540. g_bonetable[k].rawLocalOriginal = g_bonetable[k].rawLocal;
  3541. }
  3542. else
  3543. {
  3544. // convert the local relative position into a realigned relative position
  3545. matrix3x4_t srcParentBoneToWorld;
  3546. ConcatTransforms( srcBoneToWorld[n], g_bonetable[g_bonetable[k].parent].srcRealign, srcParentBoneToWorld );
  3547. matrix3x4_t invSrcParentBoneToWorld;
  3548. MatrixInvert( srcParentBoneToWorld, invSrcParentBoneToWorld );
  3549. ConcatTransforms( invSrcParentBoneToWorld, srcBoneToWorld[j], g_bonetable[k].rawLocal );
  3550. }
  3551. g_bonetable[k].boneToPose.Invalidate();
  3552. // printf("%d : %s (%s)\n", k, g_bonetable[k].name, g_bonetable[g_bonetable[k].parent].name );
  3553. g_numbones++;
  3554. continue;
  3555. }
  3556. if (g_bOverridePreDefinedBones && g_bonetable[k].bPreDefined)
  3557. {
  3558. g_bonetable[k].flags |= psource->boneflags[j];
  3559. ConcatTransforms( srcBoneToWorld[j], g_bonetable[k].srcRealign, g_bonetable[k].boneToPose );
  3560. if (g_bonetable[k].parent == -1)
  3561. {
  3562. MatrixCopy( g_bonetable[k].boneToPose, g_bonetable[k].rawLocal );
  3563. }
  3564. else
  3565. {
  3566. matrix3x4_t tmp;
  3567. MatrixInvert( g_bonetable[g_bonetable[k].parent].boneToPose, tmp );
  3568. ConcatTransforms( tmp, g_bonetable[k].boneToPose, g_bonetable[k].rawLocal );
  3569. }
  3570. continue;
  3571. }
  3572. // accumlate flags
  3573. g_bonetable[k].flags |= psource->boneflags[j];
  3574. }
  3575. }
  3576. return iError;
  3577. }
  3578. //-----------------------------------------------------------------------------
  3579. // Purpose:
  3580. //-----------------------------------------------------------------------------
  3581. void BuildGlobalBoneToPose( )
  3582. {
  3583. int k;
  3584. // build reference pose
  3585. for (k = 0; k < g_numbones; k++)
  3586. {
  3587. if (g_bonetable[k].parent == -1)
  3588. {
  3589. MatrixCopy( g_bonetable[k].rawLocal, g_bonetable[k].boneToPose );
  3590. }
  3591. else
  3592. {
  3593. ConcatTransforms (g_bonetable[g_bonetable[k].parent].boneToPose, g_bonetable[k].rawLocal, g_bonetable[k].boneToPose);
  3594. }
  3595. }
  3596. }
  3597. //-----------------------------------------------------------------------------
  3598. // Purpose:
  3599. //-----------------------------------------------------------------------------
  3600. void RebuildLocalPose( )
  3601. {
  3602. int k;
  3603. matrix3x4_t boneToPose[MAXSTUDIOBONES];
  3604. // build reference pose
  3605. for (k = 0; k < g_numbones; k++)
  3606. {
  3607. MatrixCopy( g_bonetable[k].boneToPose, boneToPose[k] );
  3608. }
  3609. matrix3x4_t poseToBone[MAXSTUDIOBONES];
  3610. // rebuild local pose
  3611. for (k = 0; k < g_numbones; k++)
  3612. {
  3613. if (g_bonetable[k].parent == -1)
  3614. {
  3615. MatrixCopy( boneToPose[k], g_bonetable[k].rawLocal );
  3616. }
  3617. else
  3618. {
  3619. ConcatTransforms (poseToBone[g_bonetable[k].parent], boneToPose[k], g_bonetable[k].rawLocal );
  3620. }
  3621. MatrixAngles( g_bonetable[k].rawLocal, g_bonetable[k].rot, g_bonetable[k].pos );
  3622. MatrixCopy( boneToPose[k], g_bonetable[k].boneToPose );
  3623. MatrixInvert( boneToPose[k], poseToBone[k] );
  3624. // printf("%d \"%s\" %d\n", k, g_bonetable[k].name, g_bonetable[k].parent );
  3625. }
  3626. //exit(0);
  3627. }
  3628. //-----------------------------------------------------------------------------
  3629. // Purpose: attach bones to different parents if needed
  3630. //-----------------------------------------------------------------------------
  3631. void EnforceHierarchy( )
  3632. {
  3633. int i, j, k;
  3634. // force changes to hierarchy
  3635. for (i = 0; i < g_numforcedhierarchy; i++)
  3636. {
  3637. j = findGlobalBone( g_forcedhierarchy[i].parentname );
  3638. k = findGlobalBone( g_forcedhierarchy[i].childname );
  3639. if (j == -1 && strlen( g_forcedhierarchy[i].parentname ) > 0 )
  3640. {
  3641. MdlError( "unknown bone: \"%s\" in forced hierarchy\n", g_forcedhierarchy[i].parentname );
  3642. }
  3643. if (k == -1)
  3644. {
  3645. MdlError( "unknown bone: \"%s\" in forced hierarchy\n", g_forcedhierarchy[i].childname );
  3646. }
  3647. /*
  3648. if (j > k)
  3649. {
  3650. MdlError( "parent \"%s\" declared after child \"%s\" in forced hierarchy\n", g_forcedhierarchy[i].parentname, g_forcedhierarchy[i].childname );
  3651. }
  3652. */
  3653. /*
  3654. if (strlen(g_forcedhierarchy[i].subparentname) != 0)
  3655. {
  3656. int n, m;
  3657. m = findGlobalBone( g_forcedhierarchy[i].subparentname );
  3658. if (m != -1)
  3659. {
  3660. MdlError( "inserted bone \"%s\" matches name of existing bone in hierarchy\n", g_forcedhierarchy[i].parentname, g_forcedhierarchy[i].subparentname );
  3661. }
  3662. printf("inserting bone \"%s\"\n", g_forcedhierarchy[i].subparentname );
  3663. // shift the bone list up
  3664. for (n = g_numbones; n > k; n--)
  3665. {
  3666. g_bonetable[n] = g_bonetable[n-1];
  3667. if (g_bonetable[n].parent >= k)
  3668. {
  3669. g_bonetable[n].parent = g_bonetable[n].parent + 1;
  3670. }
  3671. MatrixCopy( boneToPose[n-1], boneToPose[n] );
  3672. }
  3673. g_numbones++;
  3674. // add the bone
  3675. strcpy( g_bonetable[k].name, g_forcedhierarchy[i].subparentname );
  3676. g_bonetable[k].parent = j;
  3677. g_bonetable[k].split = true;
  3678. g_bonetable[k+1].parent = k;
  3679. // split the bone
  3680. Quaternion q1, q2;
  3681. Vector p;
  3682. MatrixAngles( boneToPose[k], q1, p ); // FIXME: badly named!
  3683. // !!!!
  3684. // QuaternionScale( q1, 0.5, q2 );
  3685. // q2.Init( 0, 0, 0, 1 );
  3686. // AngleQuaternion( QAngle( 0, 0, 0 ), q2 );
  3687. //QuaternionMatrix( q2, p, boneToPose[k] );
  3688. QuaternionMatrix( q1, p, boneToPose[k] );
  3689. QuaternionMatrix( q1, p, boneToPose[k+1] );
  3690. }
  3691. else
  3692. */
  3693. {
  3694. g_bonetable[k].parent = j;
  3695. }
  3696. }
  3697. // resort hierarchy
  3698. bool bSort = true;
  3699. int count = 0;
  3700. while (bSort)
  3701. {
  3702. count++;
  3703. bSort = false;
  3704. for (i = 0; i < g_numbones; i++)
  3705. {
  3706. if (g_bonetable[i].parent > i)
  3707. {
  3708. // swap
  3709. j = g_bonetable[i].parent;
  3710. s_bonetable_t tmp;
  3711. tmp = g_bonetable[i];
  3712. g_bonetable[i] = g_bonetable[j];
  3713. g_bonetable[j] = tmp;
  3714. // relink parents
  3715. for (k = i; k < g_numbones; k++)
  3716. {
  3717. if (g_bonetable[k].parent == i)
  3718. {
  3719. g_bonetable[k].parent = j;
  3720. }
  3721. else if (g_bonetable[k].parent == j)
  3722. {
  3723. g_bonetable[k].parent = i;
  3724. }
  3725. }
  3726. bSort = true;
  3727. }
  3728. }
  3729. if (count > 1000)
  3730. {
  3731. MdlError( "Circular bone hierarchy\n");
  3732. }
  3733. }
  3734. }
  3735. //-----------------------------------------------------------------------------
  3736. // Purpose: find procedural bones and tag for inclusion even if they don't animate
  3737. //-----------------------------------------------------------------------------
  3738. void TagProceduralBones( )
  3739. {
  3740. int j;
  3741. // look for AxisInterp bone definitions
  3742. int numaxisinterpbones = 0;
  3743. for (j = 0; j < g_numaxisinterpbones; j++)
  3744. {
  3745. g_axisinterpbones[j].bone = findGlobalBone( g_axisinterpbones[j].bonename );
  3746. g_axisinterpbones[j].control = findGlobalBone( g_axisinterpbones[j].controlname );
  3747. if (g_axisinterpbones[j].bone == -1)
  3748. {
  3749. if (!g_quiet)
  3750. {
  3751. printf("axisinterpbone \"%s\" unused\n", g_axisinterpbones[j].bonename );
  3752. }
  3753. continue; // optimized out, don't complain
  3754. }
  3755. if (g_axisinterpbones[j].control == -1)
  3756. {
  3757. MdlError( "Missing control bone \"%s\" for procedural bone \"%s\"\n", g_axisinterpbones[j].bonename, g_axisinterpbones[j].controlname );
  3758. }
  3759. g_bonetable[g_axisinterpbones[j].bone].flags |= BONE_ALWAYS_PROCEDURAL; // ??? what about physics rules
  3760. g_axisinterpbonemap[numaxisinterpbones++] = j;
  3761. }
  3762. g_numaxisinterpbones = numaxisinterpbones;
  3763. // look for QuatInterp bone definitions
  3764. int numquatinterpbones = 0;
  3765. for (j = 0; j < g_numquatinterpbones; j++)
  3766. {
  3767. g_quatinterpbones[j].bone = findGlobalBoneXSI( g_quatinterpbones[j].bonename );
  3768. g_quatinterpbones[j].control = findGlobalBoneXSI( g_quatinterpbones[j].controlname );
  3769. if (g_quatinterpbones[j].bone == -1)
  3770. {
  3771. if (!g_quiet && !g_bCreateMakefile )
  3772. {
  3773. printf("quatinterpbone \"%s\" unused\n", g_quatinterpbones[j].bonename );
  3774. }
  3775. continue; // optimized out, don't complain
  3776. }
  3777. if (g_quatinterpbones[j].control == -1)
  3778. {
  3779. MdlError( "Missing control bone \"%s\" for procedural bone \"%s\"\n", g_quatinterpbones[j].bonename, g_quatinterpbones[j].controlname );
  3780. }
  3781. g_bonetable[g_quatinterpbones[j].bone].flags |= BONE_ALWAYS_PROCEDURAL; // ??? what about physics rules
  3782. g_quatinterpbonemap[numquatinterpbones++] = j;
  3783. }
  3784. g_numquatinterpbones = numquatinterpbones;
  3785. // look for AimAt bone definitions
  3786. int numaimatbones = 0;
  3787. for (j = 0; j < g_numaimatbones; j++)
  3788. {
  3789. g_aimatbones[j].bone = findGlobalBoneXSI( g_aimatbones[j].bonename );
  3790. if (g_aimatbones[j].bone == -1)
  3791. {
  3792. if (!g_quiet && !g_bCreateMakefile )
  3793. {
  3794. printf("<aimconstraint> \"%s\" unused\n", g_aimatbones[j].bonename );
  3795. }
  3796. continue; // optimized out, don't complain
  3797. }
  3798. g_aimatbones[j].parent = findGlobalBoneXSI( g_aimatbones[j].parentname );
  3799. if (g_aimatbones[j].parent == -1)
  3800. {
  3801. MdlError( "Missing parent control bone \"%s\" for procedural bone \"%s\"\n", g_aimatbones[j].parentname, g_aimatbones[j].bonename );
  3802. }
  3803. // Look for the aim bone as an attachment first
  3804. g_aimatbones[j].aimAttach = -1;
  3805. for ( int ai( 0 ); ai < g_numattachments; ++ai )
  3806. {
  3807. if ( strcmp( g_attachment[ ai ].name, g_aimatbones[j].aimname ) == 0 )
  3808. {
  3809. g_aimatbones[j].aimAttach = ai;
  3810. break;
  3811. }
  3812. }
  3813. if ( g_aimatbones[j].aimAttach == -1 )
  3814. {
  3815. g_aimatbones[j].aimBone = findGlobalBoneXSI( g_aimatbones[j].aimname );
  3816. if ( g_aimatbones[j].aimBone == -1 )
  3817. {
  3818. MdlError( "Missing aim control attachment or bone \"%s\" for procedural bone \"%s\"\n",
  3819. g_aimatbones[j].aimname, g_aimatbones[j].bonename );
  3820. }
  3821. }
  3822. g_bonetable[g_aimatbones[j].bone].flags |= BONE_ALWAYS_PROCEDURAL; // ??? what about physics rules
  3823. g_aimatbonemap[numaimatbones++] = j;
  3824. }
  3825. // look for Jiggle bone definitions
  3826. int numjigglebones = 0;
  3827. for (j = 0; j < g_numjigglebones; j++)
  3828. {
  3829. g_jigglebones[j].bone = findGlobalBone( g_jigglebones[j].bonename );
  3830. if (g_jigglebones[j].bone == -1)
  3831. {
  3832. if (!g_quiet)
  3833. {
  3834. printf("jigglebone \"%s\" unused\n", g_jigglebones[j].bonename );
  3835. }
  3836. continue; // optimized out, don't complain
  3837. }
  3838. g_bonetable[g_jigglebones[j].bone].flags |= BONE_ALWAYS_PROCEDURAL; // ??? what about physics rules
  3839. g_jigglebonemap[numjigglebones++] = j;
  3840. }
  3841. g_numjigglebones = numjigglebones;
  3842. }
  3843. //-----------------------------------------------------------------------------
  3844. // Purpose: convert original procedural bone info into correct values for existing skeleton
  3845. //-----------------------------------------------------------------------------
  3846. void RemapProceduralBones( )
  3847. {
  3848. int j;
  3849. // look for QuatInterp bone definitions
  3850. for (j = 0; j < g_numquatinterpbones; j++)
  3851. {
  3852. s_quatinterpbone_t *pInterp = &g_quatinterpbones[g_quatinterpbonemap[j]];
  3853. int origParent = findGlobalBoneXSI( pInterp->parentname );
  3854. int origControlParent = findGlobalBoneXSI( pInterp->controlparentname );
  3855. if (origParent == -1)
  3856. {
  3857. MdlError( "procedural bone \"%s\", can't find orig parent \"%s\"\n\n", pInterp->bonename, pInterp->parentname );
  3858. }
  3859. if (origControlParent == -1)
  3860. {
  3861. MdlError( "procedural bone \"%s\", can't find control parent \"%s\n\n", pInterp->bonename, pInterp->controlparentname );
  3862. }
  3863. if ( g_bonetable[pInterp->bone].parent != origParent)
  3864. {
  3865. MdlError( "unknown procedural bone parent remapping\n" );
  3866. }
  3867. if ( g_bonetable[pInterp->control].parent != origControlParent)
  3868. {
  3869. MdlError( "procedural bone \"%s\", parent remapping error, control parent was \"%s\", is now \"%s\"\n",
  3870. pInterp->bonename,
  3871. pInterp->controlparentname,
  3872. g_bonetable[g_bonetable[pInterp->control].parent].name );
  3873. }
  3874. // remap triggers and movements/rotations due to skeleton changes and realignment
  3875. for (int k = 0; k < pInterp->numtriggers; k++)
  3876. {
  3877. int parent = g_bonetable[pInterp->control].parent;
  3878. // triggers are the "control" bone relative to the control's parent bone
  3879. if (parent != -1)
  3880. {
  3881. matrix3x4_t invControlParentRealign;
  3882. MatrixInvert( g_bonetable[parent].srcRealign, invControlParentRealign );
  3883. matrix3x4_t srcControlParentBoneToPose;
  3884. ConcatTransforms( g_bonetable[parent].boneToPose, invControlParentRealign, srcControlParentBoneToPose );
  3885. matrix3x4_t srcControlRelative;
  3886. QuaternionMatrix( pInterp->trigger[k], srcControlRelative );
  3887. matrix3x4_t srcControlBoneToPose;
  3888. ConcatTransforms( srcControlParentBoneToPose, srcControlRelative, srcControlBoneToPose );
  3889. matrix3x4_t destControlParentBoneToPose;
  3890. ConcatTransforms( srcControlParentBoneToPose, g_bonetable[parent].srcRealign, destControlParentBoneToPose );
  3891. matrix3x4_t destControlBoneToPose;
  3892. ConcatTransforms( srcControlBoneToPose, g_bonetable[pInterp->control].srcRealign, destControlBoneToPose );
  3893. matrix3x4_t invDestControlParentBoneToPose;
  3894. MatrixInvert( destControlParentBoneToPose, invDestControlParentBoneToPose );
  3895. matrix3x4_t destControlRelative;
  3896. ConcatTransforms( invDestControlParentBoneToPose, destControlBoneToPose, destControlRelative );
  3897. Vector tmp;
  3898. MatrixAngles( destControlRelative, pInterp->trigger[k], tmp );
  3899. /*
  3900. Vector pos;
  3901. RadianEuler angles;
  3902. MatrixAngles( srcControlRelative, angles, pos );
  3903. printf("srcControlRelative : %7.2f %7.2f %7.2f\n", RAD2DEG( angles.x ), RAD2DEG( angles.y ), RAD2DEG( angles.z ) );
  3904. MatrixAngles( destControlRelative, angles, pos );
  3905. printf("destControlRelative : %7.2f %7.2f %7.2f\n", RAD2DEG( angles.x ), RAD2DEG( angles.y ), RAD2DEG( angles.z ) );
  3906. printf("\n");
  3907. */
  3908. }
  3909. // movements are relative to the bone's parent
  3910. parent = g_bonetable[pInterp->bone].parent;
  3911. if (parent != -1)
  3912. {
  3913. //printf("procedural bone \"%s\"\n", pInterp->bonename );
  3914. //printf("pre : %7.2f %7.2f %7.2f\n", pInterp->pos[k].x, pInterp->pos[k].y, pInterp->pos[k].z );
  3915. // get local transform
  3916. matrix3x4_t srcParentRelative;
  3917. QuaternionMatrix( pInterp->quat[k], pInterp->pos[k] + pInterp->basepos, srcParentRelative );
  3918. // get original boneToPose
  3919. matrix3x4_t invSrcRealign;
  3920. MatrixInvert( g_bonetable[parent].srcRealign, invSrcRealign );
  3921. matrix3x4_t origParentBoneToPose;
  3922. ConcatTransforms( g_bonetable[parent].boneToPose, invSrcRealign, origParentBoneToPose );
  3923. // move bone adjustment into world position
  3924. matrix3x4_t srcBoneToWorld;
  3925. ConcatTransforms( origParentBoneToPose, srcParentRelative, srcBoneToWorld );
  3926. // calculate local transform
  3927. matrix3x4_t parentPoseToBone;
  3928. MatrixInvert( g_bonetable[parent].boneToPose, parentPoseToBone );
  3929. matrix3x4_t destBoneToWorld;
  3930. ConcatTransforms( parentPoseToBone, srcBoneToWorld, destBoneToWorld );
  3931. // save out the local transform
  3932. MatrixAngles( destBoneToWorld, pInterp->quat[k], pInterp->pos[k] );
  3933. pInterp->pos[k] += g_bonetable[pInterp->control].pos * pInterp->percentage;
  3934. //printf("post : %7.2f %7.2f %7.2f\n", pInterp->pos[k].x, pInterp->pos[k].y, pInterp->pos[k].z );
  3935. }
  3936. }
  3937. }
  3938. // look for aimatbones
  3939. for (j = 0; j < g_numaimatbones; j++)
  3940. {
  3941. s_aimatbone_t *pAimAtBone = &g_aimatbones[g_aimatbonemap[j]];
  3942. int origParent = findGlobalBoneXSI( pAimAtBone->parentname );
  3943. if (origParent == -1)
  3944. {
  3945. MdlError( "<aimconstraint> bone \"%s\", can't find parent bone \"%s\"\n\n", pAimAtBone->bonename, pAimAtBone->parentname );
  3946. }
  3947. int origAim( -1 );
  3948. for ( int ai( 0 ); ai < g_numattachments; ++ai )
  3949. {
  3950. if ( strcmp( g_attachment[ ai ].name, pAimAtBone->aimname ) == 0 )
  3951. {
  3952. origAim = ai;
  3953. break;
  3954. }
  3955. }
  3956. if (origAim == -1)
  3957. {
  3958. MdlError( "<aimconstraint> bone \"%s\", can't find aim bone \"%s\n\n", pAimAtBone->bonename, pAimAtBone->aimname );
  3959. }
  3960. }
  3961. }
  3962. //-----------------------------------------------------------------------------
  3963. // Purpose: propogate procedural bone usage up its chain
  3964. //-----------------------------------------------------------------------------
  3965. void MarkProceduralBoneChain()
  3966. {
  3967. int j;
  3968. int k;
  3969. int fBoneFlags;
  3970. // look for QuatInterp bone definitions
  3971. for (j = 0; j < g_numquatinterpbones; j++)
  3972. {
  3973. s_quatinterpbone_t *pInterp = &g_quatinterpbones[g_quatinterpbonemap[j]];
  3974. fBoneFlags = g_bonetable[pInterp->bone].flags & BONE_USED_MASK;
  3975. // propogate the procedural bone usage up its hierarchy
  3976. k = pInterp->control;
  3977. while (k != -1)
  3978. {
  3979. g_bonetable[k].flags |= fBoneFlags;
  3980. k = g_bonetable[k].parent;
  3981. }
  3982. // propogate the procedural bone usage up its hierarchy
  3983. k = pInterp->bone;
  3984. while (k != -1)
  3985. {
  3986. g_bonetable[k].flags |= fBoneFlags;
  3987. k = g_bonetable[k].parent;
  3988. }
  3989. }
  3990. }
  3991. //-----------------------------------------------------------------------------
  3992. // Purpose: go through all source files and link local bone indices and global bonetable indicies
  3993. //-----------------------------------------------------------------------------
  3994. static int MapSourcesToGlobalBonetable( )
  3995. {
  3996. int i, j, k;
  3997. int iError = 0;
  3998. // map each source bone list to master list
  3999. for (i = 0; i < g_numsources; i++)
  4000. {
  4001. s_source_t *pSource = g_source[i];
  4002. memset( pSource->boneLocalToGlobal, 0xFF, sizeof(pSource->boneLocalToGlobal) );
  4003. memset( pSource->boneGlobalToLocal, 0xFF, sizeof(pSource->boneGlobalToLocal) );
  4004. for ( j = 0; j < pSource->numbones; j++ )
  4005. {
  4006. k = findGlobalBone( pSource->localBone[j].name );
  4007. if ( k >= 0 )
  4008. {
  4009. pSource->boneLocalToGlobal[j] = k;
  4010. pSource->boneGlobalToLocal[k] = j;
  4011. continue;
  4012. }
  4013. int m = pSource->localBone[j].parent;
  4014. while ( m != -1 && ( k = findGlobalBone( pSource->localBone[m].name ) ) == -1 )
  4015. {
  4016. m = pSource->localBone[m].parent;
  4017. }
  4018. if (k == -1)
  4019. {
  4020. /*
  4021. if (!g_quiet)
  4022. {
  4023. printf("unable to find connection for collapsed bone \"%s\" \n", pSource->localBone[j].name );
  4024. }
  4025. */
  4026. k = 0;
  4027. }
  4028. pSource->boneLocalToGlobal[j] = k;
  4029. }
  4030. }
  4031. return iError;
  4032. }
  4033. //-----------------------------------------------------------------------------
  4034. // Purpose: go through bone and find any that arent aligned on the X axis
  4035. //-----------------------------------------------------------------------------
  4036. void RealignBones( )
  4037. {
  4038. int k;
  4039. int childbone[MAXSTUDIOBONES];
  4040. for (k = 0; k < g_numbones; k++)
  4041. {
  4042. childbone[k] = -1;
  4043. }
  4044. // force bones with IK rules to realign themselves
  4045. for (int i = 0; i < g_numikchains; i++)
  4046. {
  4047. k = g_ikchain[i].link[0].bone;
  4048. if (childbone[k] == -1 || childbone[k] == g_ikchain[i].link[1].bone)
  4049. {
  4050. childbone[k] = g_ikchain[i].link[1].bone;
  4051. }
  4052. else
  4053. {
  4054. MdlError("Trying to realign bone \"%s\" with two children \"%s\", \"%s\"\n",
  4055. g_bonetable[k].name, g_bonetable[childbone[k]].name, g_bonetable[g_ikchain[i].link[1].bone].name );
  4056. }
  4057. k = g_ikchain[i].link[1].bone;
  4058. if (childbone[k] == -1 || childbone[k] == g_ikchain[i].link[2].bone)
  4059. {
  4060. childbone[k] = g_ikchain[i].link[2].bone;
  4061. }
  4062. else
  4063. {
  4064. MdlError("Trying to realign bone \"%s\" with two children \"%s\", \"%s\"\n",
  4065. g_bonetable[k].name, g_bonetable[childbone[k]].name, g_bonetable[g_ikchain[i].link[2].bone].name );
  4066. }
  4067. }
  4068. if (g_realignbones)
  4069. {
  4070. int children[MAXSTUDIOBONES];
  4071. // count children
  4072. for (k = 0; k < g_numbones; k++)
  4073. {
  4074. children[k] = 0;
  4075. }
  4076. for (k = 0; k < g_numbones; k++)
  4077. {
  4078. if (g_bonetable[k].parent != -1)
  4079. {
  4080. children[g_bonetable[k].parent]++;
  4081. }
  4082. }
  4083. // if my parent bone only has one child, then tell it to align to me
  4084. for (k = 0; k < g_numbones; k++)
  4085. {
  4086. if (g_bonetable[k].parent != -1 && children[g_bonetable[k].parent] == 1)
  4087. {
  4088. childbone[g_bonetable[k].parent] = k;
  4089. }
  4090. }
  4091. }
  4092. matrix3x4_t boneToPose[MAXSTUDIOBONES];
  4093. for (k = 0; k < g_numbones; k++)
  4094. {
  4095. MatrixCopy( g_bonetable[k].boneToPose, boneToPose[k] );
  4096. }
  4097. // look for bones that aren't on a primary X axis
  4098. for (k = 0; k < g_numbones; k++)
  4099. {
  4100. // printf("%s %.4f %.4f %.4f (%d)\n", g_bonetable[k].name, g_bonetable[k].pos.x, g_bonetable[k].pos.y, g_bonetable[k].pos.z, children[k] );
  4101. if (!g_bonetable[k].bPreAligned && childbone[k] != -1)
  4102. {
  4103. float d = g_bonetable[childbone[k]].pos.Length();
  4104. // check to see that it's on positive X
  4105. if (d - g_bonetable[childbone[k]].pos.x > 0.01)
  4106. {
  4107. Vector v2;
  4108. Vector v3;
  4109. // printf("%s:%s %.4f %.4f %.4f\n", g_bonetable[k].name, g_bonetable[childbone[k]].name, g_bonetable[childbone[k]].pos.x, g_bonetable[childbone[k]].pos.y, g_bonetable[childbone[k]].pos.z );
  4110. Vector forward, left, up;
  4111. // calc X axis
  4112. MatrixGetColumn( g_bonetable[childbone[k]].boneToPose, 3, v2 );
  4113. MatrixGetColumn( g_bonetable[k].boneToPose, 3, v3 );
  4114. forward = v2 - v3;
  4115. VectorNormalize( forward );
  4116. // try to align to existing bone/boundingbox by finding most perpendicular
  4117. // existing axis and aligning the new Z axis to it.
  4118. Vector forward2, left2, up2;
  4119. MatrixGetColumn( boneToPose[k], 0, forward2 );
  4120. MatrixGetColumn( boneToPose[k], 1, left2 );
  4121. MatrixGetColumn( boneToPose[k], 2, up2 );
  4122. float d1 = fabs(DotProduct( forward, forward2 ));
  4123. float d2 = fabs(DotProduct( forward, left2 ));
  4124. float d3 = fabs(DotProduct( forward, up2 ));
  4125. if (d1 <= d2 && d1 <= d3)
  4126. {
  4127. up = CrossProduct( forward, forward2 );
  4128. VectorNormalize( up );
  4129. }
  4130. else if (d2 <= d1 && d2 <= d3)
  4131. {
  4132. up = CrossProduct( forward, left2 );
  4133. VectorNormalize( up );
  4134. }
  4135. else
  4136. {
  4137. up = CrossProduct( forward, up2 );
  4138. VectorNormalize( up );
  4139. }
  4140. left = CrossProduct( up, forward );
  4141. // setup matrix
  4142. MatrixSetColumn( forward, 0, boneToPose[k] );
  4143. MatrixSetColumn( left, 1, boneToPose[k] );
  4144. MatrixSetColumn( up, 2, boneToPose[k] );
  4145. // check orthonormality of matrix
  4146. d = fabs( DotProduct( forward, left ) )
  4147. + fabs( DotProduct( left, up ) )
  4148. + fabs( DotProduct( up, forward ) )
  4149. + fabs( DotProduct( boneToPose[k][0], boneToPose[k][1] ) )
  4150. + fabs( DotProduct( boneToPose[k][1], boneToPose[k][2] ) )
  4151. + fabs( DotProduct( boneToPose[k][2], boneToPose[k][0] ) );
  4152. if (d > 0.0001)
  4153. {
  4154. MdlError( "error with realigning bone %s\n", g_bonetable[k].name );
  4155. }
  4156. // printf("%f %f %f\n", DotProduct( boneToPose[k][0], boneToPose[k][1] ), DotProduct( boneToPose[k][1], boneToPose[k][2] ), DotProduct( boneToPose[k][2], boneToPose[k][0] ) );
  4157. // printf("%f %f %f\n", DotProduct( forward, left ), DotProduct( left, up ), DotProduct( up, forward ) );
  4158. // VectorMatrix( forward, boneToPose[k] );
  4159. MatrixSetColumn( v3, 3, boneToPose[k] );
  4160. }
  4161. }
  4162. }
  4163. for (int i = 0; i < g_numforcedrealign; i++)
  4164. {
  4165. k = findGlobalBone( g_forcedrealign[i].name );
  4166. if (k == -1)
  4167. {
  4168. MdlError( "unknown bone %s in $forcedrealign\n", g_forcedrealign[i].name );
  4169. }
  4170. matrix3x4_t local;
  4171. matrix3x4_t tmp;
  4172. AngleMatrix( g_forcedrealign[i].rot, local );
  4173. ConcatTransforms( boneToPose[k], local, tmp );
  4174. MatrixCopy( tmp, boneToPose[k] );
  4175. }
  4176. // build realignment transforms
  4177. for (k = 0; k < g_numbones; k++)
  4178. {
  4179. if (!g_bonetable[k].bPreAligned)
  4180. {
  4181. matrix3x4_t poseToBone;
  4182. MatrixInvert( g_bonetable[k].boneToPose, poseToBone );
  4183. ConcatTransforms( poseToBone, boneToPose[k], g_bonetable[k].srcRealign );
  4184. MatrixCopy( boneToPose[k], g_bonetable[k].boneToPose );
  4185. }
  4186. }
  4187. // printf("\n");
  4188. // rebuild default angles, position, etc.
  4189. for (k = 0; k < g_numbones; k++)
  4190. {
  4191. if (!g_bonetable[k].bPreAligned)
  4192. {
  4193. matrix3x4_t bonematrix;
  4194. if (g_bonetable[k].parent == -1)
  4195. {
  4196. MatrixCopy( g_bonetable[k].boneToPose, bonematrix );
  4197. }
  4198. else
  4199. {
  4200. matrix3x4_t poseToBone;
  4201. // convert my transform into parent relative space
  4202. MatrixInvert( g_bonetable[g_bonetable[k].parent].boneToPose, poseToBone );
  4203. ConcatTransforms( poseToBone, g_bonetable[k].boneToPose, bonematrix );
  4204. }
  4205. MatrixAngles( bonematrix, g_bonetable[k].rot, g_bonetable[k].pos );
  4206. }
  4207. }
  4208. // exit(0);
  4209. // printf("\n");
  4210. // build reference pose
  4211. for (k = 0; k < g_numbones; k++)
  4212. {
  4213. matrix3x4_t bonematrix;
  4214. AngleMatrix( g_bonetable[k].rot, g_bonetable[k].pos, bonematrix );
  4215. // MatrixCopy( g_bonetable[k].rawLocal, bonematrix );
  4216. if (g_bonetable[k].parent == -1)
  4217. {
  4218. MatrixCopy( bonematrix, g_bonetable[k].boneToPose );
  4219. }
  4220. else
  4221. {
  4222. ConcatTransforms (g_bonetable[g_bonetable[k].parent].boneToPose, bonematrix, g_bonetable[k].boneToPose);
  4223. }
  4224. /*
  4225. Vector v1;
  4226. MatrixGetColumn( g_bonetable[k].boneToPose, 3, v1 );
  4227. printf("%s %.4f %.4f %.4f\n", g_bonetable[k].name, v1.x, v1.y, v1.z );
  4228. */
  4229. }
  4230. }
  4231. void CenterBonesOnVerts( void )
  4232. {
  4233. Vector bmin[MAXSTUDIOBONES];
  4234. Vector bmax[MAXSTUDIOBONES];
  4235. int i, j, k, n;
  4236. for (k = 0; k < g_numbones; k++)
  4237. {
  4238. bmin[k] = Vector( 1, 1, 1 ) * 99999999.0;
  4239. bmax[k] = Vector( 1, 1, 1 ) * -99999999.0;
  4240. }
  4241. // find domain of all the vertices
  4242. for (i = 0; i < g_numsources; i++)
  4243. {
  4244. s_source_t *pSource = g_source[i];
  4245. if ( !pSource->vertex )
  4246. continue;
  4247. s_sourceanim_t *pSourceAnim = FindSourceAnim( pSource, "BindPose" );
  4248. if ( !pSourceAnim )
  4249. {
  4250. pSourceAnim = &pSource->m_Animations[0];
  4251. }
  4252. pSource->m_GlobalVertices.AddMultipleToTail( pSource->numvertices );
  4253. Vector p;
  4254. for (j = 0; j < pSource->numvertices; j++)
  4255. {
  4256. for (n = 0; n < pSource->m_GlobalVertices[j].boneweight.numbones; n++)
  4257. {
  4258. k = pSource->m_GlobalVertices[j].boneweight.bone[n];
  4259. p = pSource->m_GlobalVertices[j].position;
  4260. bmin[k] = bmin[k].Min( p );
  4261. bmax[k] = bmax[k].Max( p );
  4262. }
  4263. }
  4264. }
  4265. // copy min/maxs up to parent
  4266. for (k = g_numbones - 1; k >= 0; k--)
  4267. {
  4268. if (bmin[k].x > bmax[k].x)
  4269. {
  4270. for (j = k + 1; j < g_numbones; j++)
  4271. {
  4272. if (g_bonetable[j].parent == k)
  4273. {
  4274. bmin[k] = bmin[k].Min( bmin[j] );
  4275. bmax[k] = bmax[k].Max( bmax[j] );
  4276. }
  4277. }
  4278. }
  4279. }
  4280. for (k = 0; k < g_numbones; k++)
  4281. {
  4282. if (bmin[k].x <= bmax[k].x)
  4283. {
  4284. Vector center = (bmin[k] + bmax[k]) * 0.5;
  4285. // printf("%d %.1f %.1f %.1f\n", k, center.x, center.y, center.z );
  4286. matrix3x4_t updateCenter;
  4287. MatrixCopy( g_bonetable[k].boneToPose, updateCenter );
  4288. PositionMatrix( center, updateCenter );
  4289. matrix3x4_t invPoseToBone;
  4290. MatrixInvert( g_bonetable[k].boneToPose, invPoseToBone );
  4291. ConcatTransforms( invPoseToBone, updateCenter, g_bonetable[k].srcRealign );
  4292. MatrixCopy( updateCenter, g_bonetable[k].boneToPose );
  4293. }
  4294. }
  4295. // rebuild default angles, position, etc.
  4296. for (k = 0; k < g_numbones; k++)
  4297. {
  4298. if (!g_bonetable[k].bPreAligned)
  4299. {
  4300. matrix3x4_t bonematrix;
  4301. if (g_bonetable[k].parent == -1)
  4302. {
  4303. MatrixCopy( g_bonetable[k].boneToPose, bonematrix );
  4304. }
  4305. else
  4306. {
  4307. matrix3x4_t poseToBone;
  4308. // convert my transform into parent relative space
  4309. MatrixInvert( g_bonetable[g_bonetable[k].parent].boneToPose, poseToBone );
  4310. ConcatTransforms( poseToBone, g_bonetable[k].boneToPose, bonematrix );
  4311. }
  4312. MatrixAngles( bonematrix, g_bonetable[k].rot, g_bonetable[k].pos );
  4313. }
  4314. }
  4315. }
  4316. //-----------------------------------------------------------------------------
  4317. // Purpose: find all the different bones used in all the source files and map everything
  4318. // to a common bonetable.
  4319. //-----------------------------------------------------------------------------
  4320. void RemapBones( )
  4321. {
  4322. int iError = 0;
  4323. if ( g_staticprop )
  4324. {
  4325. MakeStaticProp( );
  4326. }
  4327. else if ( g_centerstaticprop )
  4328. {
  4329. MdlWarning("Ignoring option $autocenter. Only supported on $staticprop models!!!\n" );
  4330. }
  4331. TagUsedBones( );
  4332. RenameBones( );
  4333. iError = BuildGlobalBonetable( );
  4334. BuildGlobalBoneToPose( );
  4335. EnforceHierarchy( );
  4336. {
  4337. int k, n;
  4338. for ( k = 0; k < g_numbones; k++ )
  4339. {
  4340. // tag parent bones as being in the same way as their children
  4341. n = g_bonetable[k].parent;
  4342. while (n != -1)
  4343. {
  4344. g_bonetable[n].flags |= g_bonetable[k].flags;
  4345. n = g_bonetable[n].parent;
  4346. }
  4347. }
  4348. }
  4349. if ( g_collapse_bones || g_numimportbones )
  4350. {
  4351. CollapseBones( );
  4352. }
  4353. if ( g_numbones >= MAXSTUDIOBONES )
  4354. {
  4355. MdlError( "Too many bones used in model, used %d, max %d\n", g_numbones, MAXSTUDIOBONES );
  4356. }
  4357. /*
  4358. for (i = 0; i < g_numbones; i++)
  4359. {
  4360. printf("%2d %s %d\n", i, g_bonetable[i].name, g_bonetable[i].parent );
  4361. }
  4362. */
  4363. RebuildLocalPose( );
  4364. TagProceduralBones( );
  4365. if ( iError && !(ignore_warnings) )
  4366. {
  4367. MdlError( "Exiting due to errors\n" );
  4368. }
  4369. MapSourcesToGlobalBonetable( );
  4370. if ( iError && !(ignore_warnings) )
  4371. {
  4372. MdlError( "Exiting due to errors\n" );
  4373. }
  4374. // Map the bone names to global bone indices for all BoneFlexDrivers
  4375. MapFlexDriveBonesToGlobalBoneTable();
  4376. }
  4377. //-----------------------------------------------------------------------------
  4378. // Purpose: calculate the bone to world transforms for a processed animation
  4379. //-----------------------------------------------------------------------------
  4380. void CalcBoneTransforms( s_animation_t *panimation, int frame, matrix3x4_t* pBoneToWorld )
  4381. {
  4382. CalcBoneTransforms( panimation, g_panimation[0], frame, pBoneToWorld );
  4383. }
  4384. void CalcBoneTransforms( s_animation_t *panimation, s_animation_t *pbaseanimation, int frame, matrix3x4_t* pBoneToWorld )
  4385. {
  4386. if ((panimation->flags & STUDIO_LOOPING) && panimation->numframes > 1)
  4387. {
  4388. while (frame >= (panimation->numframes - 1))
  4389. {
  4390. frame = frame - (panimation->numframes - 1);
  4391. }
  4392. }
  4393. if (frame < 0 || frame >= panimation->numframes)
  4394. {
  4395. MdlError("requested out of range frame on animation \"%s\" : %d (%d)\n", panimation->name, frame, panimation->numframes );
  4396. }
  4397. for (int k = 0; k < g_numbones; k++)
  4398. {
  4399. Vector angle;
  4400. matrix3x4_t bonematrix;
  4401. if (!(panimation->flags & STUDIO_DELTA))
  4402. {
  4403. AngleMatrix( panimation->sanim[frame][k].rot, panimation->sanim[frame][k].pos, bonematrix );
  4404. }
  4405. else if (pbaseanimation)
  4406. {
  4407. Quaternion q1, q2, q3;
  4408. Vector p3;
  4409. //AngleQuaternion( g_bonetable[k].rot, q1 );
  4410. AngleQuaternion( pbaseanimation->sanim[0][k].rot, q1 );
  4411. AngleQuaternion( panimation->sanim[frame][k].rot, q2 );
  4412. float s = panimation->weight[k];
  4413. QuaternionMA( q1, s, q2, q3 );
  4414. //p3 = g_bonetable[k].pos + s * panimation->sanim[frame][k].pos;
  4415. p3 = pbaseanimation->sanim[0][k].pos + s * panimation->sanim[frame][k].pos;
  4416. AngleMatrix( q3, p3, bonematrix );
  4417. }
  4418. else
  4419. {
  4420. Quaternion q1, q2, q3;
  4421. Vector p3;
  4422. AngleQuaternion( g_bonetable[k].rot, q1 );
  4423. AngleQuaternion( panimation->sanim[frame][k].rot, q2 );
  4424. float s = panimation->weight[k];
  4425. QuaternionMA( q1, s, q2, q3 );
  4426. //p3 = g_bonetable[k].pos + s * panimation->sanim[frame][k].pos;
  4427. p3 = pbaseanimation->sanim[0][k].pos + s * g_bonetable[k].pos;
  4428. AngleMatrix( q3, p3, bonematrix );
  4429. }
  4430. if (g_bonetable[k].parent == -1)
  4431. {
  4432. MatrixCopy( bonematrix, pBoneToWorld[k] );
  4433. }
  4434. else
  4435. {
  4436. ConcatTransforms (pBoneToWorld[g_bonetable[k].parent], bonematrix, pBoneToWorld[k]);
  4437. }
  4438. }
  4439. }
  4440. //-----------------------------------------------------------------------------
  4441. // Purpose: calculate the bone to world transforms for a processed animation
  4442. //-----------------------------------------------------------------------------
  4443. void CalcBoneTransformsCycle( s_animation_t *panimation, s_animation_t *pbaseanimation, float flCycle, matrix3x4_t* pBoneToWorld )
  4444. {
  4445. float fFrame = flCycle * (panimation->numframes - 1);
  4446. int iFrame = (int)fFrame;
  4447. float s = (fFrame - iFrame);
  4448. int iFrame1 = iFrame % (panimation->numframes - 1);
  4449. int iFrame2 = (iFrame + 1) % (panimation->numframes - 1);
  4450. for (int k = 0; k < g_numbones; k++)
  4451. {
  4452. Quaternion q1, q2, q3;
  4453. Vector p3;
  4454. matrix3x4_t bonematrix;
  4455. // if (!(panimation->flags & STUDIO_DELTA))
  4456. {
  4457. AngleQuaternion( panimation->sanim[iFrame1][k].rot, q1 );
  4458. AngleQuaternion( panimation->sanim[iFrame2][k].rot, q2 );
  4459. QuaternionSlerp( q1, q2, s, q3 );
  4460. VectorLerp( panimation->sanim[iFrame1][k].pos, panimation->sanim[iFrame2][k].pos, s, p3 );
  4461. AngleMatrix( q3, p3, bonematrix );
  4462. }
  4463. /*
  4464. else
  4465. {
  4466. Vector p3;
  4467. //AngleQuaternion( g_bonetable[k].rot, q1 );
  4468. AngleQuaternion( pbaseanimation->sanim[0][k].rot, q1 );
  4469. AngleQuaternion( panimation->sanim[frame][k].rot, q2 );
  4470. float s = panimation->weight[k];
  4471. QuaternionMA( q1, s, q2, q3 );
  4472. //p3 = g_bonetable[k].pos + s * panimation->sanim[frame][k].pos;
  4473. p3 = pbaseanimation->sanim[0][k].pos + s * panimation->sanim[frame][k].pos;
  4474. AngleMatrix( q3, p3, bonematrix );
  4475. }
  4476. */
  4477. if (g_bonetable[k].parent == -1)
  4478. {
  4479. MatrixCopy( bonematrix, pBoneToWorld[k] );
  4480. }
  4481. else
  4482. {
  4483. ConcatTransforms (pBoneToWorld[g_bonetable[k].parent], bonematrix, pBoneToWorld[k]);
  4484. }
  4485. }
  4486. }
  4487. //-----------------------------------------------------------------------------
  4488. // Purpose: calculate the bone to world transforms for a processed sequence
  4489. //-----------------------------------------------------------------------------
  4490. void SlerpBones(
  4491. Quaternion q1[MAXSTUDIOBONES],
  4492. Vector pos1[MAXSTUDIOBONES],
  4493. int sequence,
  4494. const Quaternion q2[MAXSTUDIOBONES],
  4495. const Vector pos2[MAXSTUDIOBONES],
  4496. float s )
  4497. {
  4498. int i;
  4499. Quaternion q3, q4;
  4500. float s1, s2;
  4501. s_sequence_t *pseqdesc = &g_sequence[sequence];
  4502. if (s <= 0.0f)
  4503. {
  4504. return;
  4505. }
  4506. else if (s > 1.0f)
  4507. {
  4508. s = 1.0f;
  4509. }
  4510. if (pseqdesc->flags & STUDIO_DELTA)
  4511. {
  4512. for (i = 0; i < g_numbones; i++)
  4513. {
  4514. s2 = s * pseqdesc->weight[i]; // blend in based on this bones weight
  4515. if (s2 > 0.0)
  4516. {
  4517. if (pseqdesc->flags & STUDIO_POST)
  4518. {
  4519. QuaternionMA( q1[i], s2, q2[i], q1[i] );
  4520. // FIXME: are these correct?
  4521. pos1[i][0] = pos1[i][0] + pos2[i][0] * s2;
  4522. pos1[i][1] = pos1[i][1] + pos2[i][1] * s2;
  4523. pos1[i][2] = pos1[i][2] + pos2[i][2] * s2;
  4524. }
  4525. else
  4526. {
  4527. QuaternionSM( s2, q2[i], q1[i], q1[i] );
  4528. // FIXME: are these correct?
  4529. pos1[i][0] = pos1[i][0] + pos2[i][0] * s2;
  4530. pos1[i][1] = pos1[i][1] + pos2[i][1] * s2;
  4531. pos1[i][2] = pos1[i][2] + pos2[i][2] * s2;
  4532. }
  4533. }
  4534. }
  4535. }
  4536. else
  4537. {
  4538. for (i = 0; i <g_numbones; i++)
  4539. {
  4540. s2 = s * pseqdesc->weight[i]; // blend in based on this animations weights
  4541. if (s2 > 0.0)
  4542. {
  4543. s1 = 1.0 - s2;
  4544. if (g_bonetable[i].flags & BONE_FIXED_ALIGNMENT)
  4545. {
  4546. QuaternionSlerpNoAlign( q2[i], q1[i], s1, q3 );
  4547. }
  4548. else
  4549. {
  4550. QuaternionSlerp( q2[i], q1[i], s1, q3 );
  4551. }
  4552. q1[i][0] = q3[0];
  4553. q1[i][1] = q3[1];
  4554. q1[i][2] = q3[2];
  4555. q1[i][3] = q3[3];
  4556. pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s2;
  4557. pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s2;
  4558. pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s2;
  4559. }
  4560. }
  4561. }
  4562. }
  4563. void CalcPoseSingle( Vector pos[], Quaternion q[], int sequence, float frame )
  4564. {
  4565. s_sequence_t *pseqdesc = &g_sequence[sequence];
  4566. s_animation_t *panim = pseqdesc->panim[0][0];
  4567. // FIXME: is this modulo correct?
  4568. int iframe = ((int)frame) % panim->numframes;
  4569. for (int k = 0; k < g_numbones; k++)
  4570. {
  4571. // FIXME: this isn't doing a fractional frame
  4572. AngleQuaternion( panim->sanim[iframe][k].rot, q[k] );
  4573. pos[k] = panim->sanim[iframe][k].pos;
  4574. }
  4575. }
  4576. void AccumulateSeqLayers( Vector pos[], Quaternion q[], int sequence, float frame, float flWeight );
  4577. void AccumulatePose( Vector pos[], Quaternion q[], int sequence, float frame, float flWeight )
  4578. {
  4579. Vector pos2[MAXSTUDIOBONES];
  4580. Quaternion q2[MAXSTUDIOBONES];
  4581. // printf("accumulate %s : %.1f\n", g_sequence[sequence].name, frame );
  4582. CalcPoseSingle( pos2, q2, sequence, frame );
  4583. SlerpBones( q, pos, sequence, q2, pos2, flWeight );
  4584. AccumulateSeqLayers( pos, q, sequence, frame, flWeight );
  4585. }
  4586. void AccumulateSeqLayers( Vector pos[], Quaternion q[], int sequence, float frame, float flWeight )
  4587. {
  4588. s_sequence_t *pseqdesc = &g_sequence[sequence];
  4589. for (int i = 0; i < pseqdesc->numautolayers; i++)
  4590. {
  4591. s_autolayer_t *pLayer = &pseqdesc->autolayer[i];
  4592. float layerFrame = frame;
  4593. float layerWeight = flWeight;
  4594. if (pLayer->start != pLayer->end)
  4595. {
  4596. float s = 1.0;
  4597. float index;
  4598. if (!(pLayer->flags & STUDIO_AL_POSE))
  4599. {
  4600. index = frame;
  4601. }
  4602. else
  4603. {
  4604. int iPose = pLayer->pose;
  4605. if (iPose != -1)
  4606. {
  4607. index = 0; // undefined?
  4608. }
  4609. else
  4610. {
  4611. index = 0;
  4612. }
  4613. }
  4614. if (index < pLayer->start)
  4615. continue;
  4616. if (index >= pLayer->end)
  4617. continue;
  4618. if (index < pLayer->peak && pLayer->start != pLayer->peak)
  4619. {
  4620. s = (index - pLayer->start) / (pLayer->peak - pLayer->start);
  4621. }
  4622. else if (index > pLayer->tail && pLayer->end != pLayer->tail)
  4623. {
  4624. s = (pLayer->end - index) / (pLayer->end - pLayer->tail);
  4625. }
  4626. if (pLayer->flags & STUDIO_AL_SPLINE)
  4627. {
  4628. s = 3 * s * s - 2 * s * s * s;
  4629. }
  4630. if ((pLayer->flags & STUDIO_AL_XFADE) && (frame > pLayer->tail))
  4631. {
  4632. layerWeight = ( s * flWeight ) / ( 1 - flWeight + s * flWeight );
  4633. }
  4634. else if (pLayer->flags & STUDIO_AL_NOBLEND)
  4635. {
  4636. layerWeight = s;
  4637. }
  4638. else
  4639. {
  4640. layerWeight = flWeight * s;
  4641. }
  4642. if (!(pLayer->flags & STUDIO_AL_POSE))
  4643. {
  4644. layerFrame = ((frame - pLayer->start) / (pLayer->end - pLayer->start)) * (g_sequence[pLayer->sequence].panim[0][0]->numframes - 1);
  4645. }
  4646. else
  4647. {
  4648. layerFrame = (frame / g_sequence[sequence].panim[0][0]->numframes - 1) * (g_sequence[pLayer->sequence].panim[0][0]->numframes - 1);
  4649. }
  4650. }
  4651. AccumulatePose( pos, q, pLayer->sequence, layerFrame, layerWeight );
  4652. }
  4653. }
  4654. void CalcSeqTransforms( int sequence, int frame, matrix3x4_t* pBoneToWorld )
  4655. {
  4656. int k;
  4657. Vector pos[MAXSTUDIOBONES];
  4658. Quaternion q[MAXSTUDIOBONES];
  4659. // CalcPoseSingle( pos, q, 0, 0 );
  4660. /*
  4661. for (k = 0; k < g_numbones; k++)
  4662. {
  4663. //AngleQuaternion( g_bonetable[k].rot, q[k] );
  4664. //pos[k] = g_bonetable[k].pos;
  4665. AngleQuaternion( g_bonetable[k].rot, q[k] );
  4666. pos[k] = g_bonetable[k].pos;
  4667. }
  4668. */
  4669. for (k = 0; k < g_numbones; k++)
  4670. {
  4671. //AngleQuaternion( g_bonetable[k].rot, q[k] );
  4672. //pos[k] = g_bonetable[k].pos;
  4673. AngleQuaternion( g_bonetable[k].rot, q[k] );
  4674. pos[k] = g_bonetable[k].pos;
  4675. }
  4676. AccumulatePose( pos, q, sequence, frame, 1.0 );
  4677. for (k = 0; k < g_numbones; k++)
  4678. {
  4679. matrix3x4_t bonematrix;
  4680. QuaternionMatrix( q[k], pos[k], bonematrix );
  4681. if (g_bonetable[k].parent == -1)
  4682. {
  4683. MatrixCopy( bonematrix, pBoneToWorld[k] );
  4684. }
  4685. else
  4686. {
  4687. ConcatTransforms (pBoneToWorld[g_bonetable[k].parent], bonematrix, pBoneToWorld[k]);
  4688. }
  4689. }
  4690. }
  4691. //-----------------------------------------------------------------------------
  4692. // Purpose:
  4693. //-----------------------------------------------------------------------------
  4694. void CalcBonePos( s_animation_t *panimation, int frame, int bone, Vector &pos )
  4695. {
  4696. matrix3x4_t boneToWorld[MAXSTUDIOSRCBONES]; // bone transformation matrix
  4697. CalcBoneTransforms( panimation, frame, boneToWorld );
  4698. pos.x = boneToWorld[bone][0][3];
  4699. pos.y = boneToWorld[bone][1][3];
  4700. pos.z = boneToWorld[bone][2][3];
  4701. }
  4702. #define SMALL_FLOAT 1e-12
  4703. // NOTE: This routine was taken (and modified) from NVidia's BlinnReflection demo
  4704. // Creates basis vectors, based on a vertex and index list.
  4705. // See the NVidia white paper 'GDC2K PerPixel Lighting' for a description
  4706. // of how this computation works
  4707. static void CalcTriangleTangentSpace( s_source_t *pSrc, int v1, int v2, int v3,
  4708. Vector &sVect, Vector &tVect )
  4709. {
  4710. /*
  4711. static bool firstTime = true;
  4712. static FILE *fp = NULL;
  4713. if( firstTime )
  4714. {
  4715. firstTime = false;
  4716. fp = fopen( "crap.out", "w" );
  4717. }
  4718. */
  4719. Vector2D t0( pSrc->vertex[v1].texcoord[0], pSrc->vertex[v1].texcoord[1] );
  4720. Vector2D t1( pSrc->vertex[v2].texcoord[0], pSrc->vertex[v2].texcoord[1] );
  4721. Vector2D t2( pSrc->vertex[v3].texcoord[0], pSrc->vertex[v3].texcoord[1] );
  4722. Vector p0( pSrc->vertex[v1].position[0], pSrc->vertex[v1].position[1], pSrc->vertex[v1].position[2] );
  4723. Vector p1( pSrc->vertex[v2].position[0], pSrc->vertex[v2].position[1], pSrc->vertex[v2].position[2] );
  4724. Vector p2( pSrc->vertex[v3].position[0], pSrc->vertex[v3].position[1], pSrc->vertex[v3].position[2] );
  4725. CalcTriangleTangentSpace( p0, p1, p2, t0, t1, t2, sVect, tVect );
  4726. /*
  4727. // Calculate flat normal
  4728. Vector flatNormal;
  4729. edge01 = p1 - p0;
  4730. edge02 = p2 - p0;
  4731. CrossProduct( edge02, edge01, flatNormal );
  4732. VectorNormalize( flatNormal );
  4733. // Get the average position
  4734. Vector avgPos = ( p0 + p1 + p2 ) / 3.0f;
  4735. // Draw the svect
  4736. Vector endS = avgPos + sVect * .2f;
  4737. fprintf( fp, "2\n" );
  4738. fprintf( fp, "%f %f %f 1.0 0.0 0.0\n", endS[0], endS[1], endS[2] );
  4739. fprintf( fp, "%f %f %f 1.0 0.0 0.0\n", avgPos[0], avgPos[1], avgPos[2] );
  4740. // Draw the tvect
  4741. Vector endT = avgPos + tVect * .2f;
  4742. fprintf( fp, "2\n" );
  4743. fprintf( fp, "%f %f %f 0.0 1.0 0.0\n", endT[0], endT[1], endT[2] );
  4744. fprintf( fp, "%f %f %f 0.0 1.0 0.0\n", avgPos[0], avgPos[1], avgPos[2] );
  4745. // Draw the normal
  4746. Vector endN = avgPos + flatNormal * .2f;
  4747. fprintf( fp, "2\n" );
  4748. fprintf( fp, "%f %f %f 0.0 0.0 1.0\n", endN[0], endN[1], endN[2] );
  4749. fprintf( fp, "%f %f %f 0.0 0.0 1.0\n", avgPos[0], avgPos[1], avgPos[2] );
  4750. // Draw the wireframe of the triangle in white.
  4751. fprintf( fp, "2\n" );
  4752. fprintf( fp, "%f %f %f 1.0 1.0 1.0\n", p0[0], p0[1], p0[2] );
  4753. fprintf( fp, "%f %f %f 1.0 1.0 1.0\n", p1[0], p1[1], p1[2] );
  4754. fprintf( fp, "2\n" );
  4755. fprintf( fp, "%f %f %f 1.0 1.0 1.0\n", p1[0], p1[1], p1[2] );
  4756. fprintf( fp, "%f %f %f 1.0 1.0 1.0\n", p2[0], p2[1], p2[2] );
  4757. fprintf( fp, "2\n" );
  4758. fprintf( fp, "%f %f %f 1.0 1.0 1.0\n", p2[0], p2[1], p2[2] );
  4759. fprintf( fp, "%f %f %f 1.0 1.0 1.0\n", p0[0], p0[1], p0[2] );
  4760. // Draw a slightly shrunken version of the geometry to hide surfaces
  4761. Vector tmp0 = p0 - flatNormal * .1f;
  4762. Vector tmp1 = p1 - flatNormal * .1f;
  4763. Vector tmp2 = p2 - flatNormal * .1f;
  4764. fprintf( fp, "3\n" );
  4765. fprintf( fp, "%f %f %f 0.1 0.1 0.1\n", tmp0[0], tmp0[1], tmp0[2] );
  4766. fprintf( fp, "%f %f %f 0.1 0.1 0.1\n", tmp1[0], tmp1[1], tmp1[2] );
  4767. fprintf( fp, "%f %f %f 0.1 0.1 0.1\n", tmp2[0], tmp2[1], tmp2[2] );
  4768. fflush( fp );
  4769. */
  4770. }
  4771. typedef CUtlVector<int> CIntVector;
  4772. void CalcModelTangentSpaces( s_source_t *pSrc )
  4773. {
  4774. // Build a map from vertex to a list of triangles that share the vert.
  4775. int meshID;
  4776. for( meshID = 0; meshID < pSrc->nummeshes; meshID++ )
  4777. {
  4778. s_mesh_t *pMesh = &pSrc->mesh[pSrc->meshindex[meshID]];
  4779. CUtlVector<CIntVector> vertToTriMap;
  4780. vertToTriMap.AddMultipleToTail( pMesh->numvertices );
  4781. int triID;
  4782. for( triID = 0; triID < pMesh->numfaces; triID++ )
  4783. {
  4784. s_face_t *pFace = &pSrc->face[triID + pMesh->faceoffset];
  4785. vertToTriMap[pFace->a].AddToTail( triID );
  4786. vertToTriMap[pFace->b].AddToTail( triID );
  4787. vertToTriMap[pFace->c].AddToTail( triID );
  4788. }
  4789. // Calculate the tangent space for each triangle.
  4790. CUtlVector<Vector> triSVect;
  4791. CUtlVector<Vector> triTVect;
  4792. triSVect.AddMultipleToTail( pMesh->numfaces );
  4793. triTVect.AddMultipleToTail( pMesh->numfaces );
  4794. for( triID = 0; triID < pMesh->numfaces; triID++ )
  4795. {
  4796. s_face_t *pFace = &pSrc->face[triID + pMesh->faceoffset];
  4797. CalcTriangleTangentSpace( pSrc,
  4798. pMesh->vertexoffset + pFace->a,
  4799. pMesh->vertexoffset + pFace->b,
  4800. pMesh->vertexoffset + pFace->c,
  4801. triSVect[triID], triTVect[triID] );
  4802. }
  4803. // calculate an average tangent space for each vertex.
  4804. int vertID;
  4805. for( vertID = 0; vertID < pMesh->numvertices; vertID++ )
  4806. {
  4807. const Vector &normal = pSrc->vertex[vertID+pMesh->vertexoffset].normal;
  4808. Vector4D &finalSVect = pSrc->vertex[vertID+pMesh->vertexoffset].tangentS;
  4809. Vector sVect, tVect;
  4810. sVect.Init( 0.0f, 0.0f, 0.0f );
  4811. tVect.Init( 0.0f, 0.0f, 0.0f );
  4812. for( triID = 0; triID < vertToTriMap[vertID].Size(); triID++ )
  4813. {
  4814. sVect += triSVect[vertToTriMap[vertID][triID]];
  4815. tVect += triTVect[vertToTriMap[vertID][triID]];
  4816. }
  4817. // In the case of zbrush, everything needs to be treated as smooth.
  4818. if( g_bZBrush )
  4819. {
  4820. int vertID2;
  4821. Vector vertPos1( pSrc->vertex[vertID].position[0], pSrc->vertex[vertID].position[1], pSrc->vertex[vertID].position[2] );
  4822. for( vertID2 = 0; vertID2 < pMesh->numvertices; vertID2++ )
  4823. {
  4824. if( vertID2 == vertID )
  4825. {
  4826. continue;
  4827. }
  4828. Vector vertPos2( pSrc->vertex[vertID2].position[0], pSrc->vertex[vertID2].position[1], pSrc->vertex[vertID2].position[2] );
  4829. if( vertPos1 == vertPos2 )
  4830. {
  4831. int triID2;
  4832. for( triID2 = 0; triID2 < vertToTriMap[vertID2].Size(); triID2++ )
  4833. {
  4834. sVect += triSVect[vertToTriMap[vertID2][triID2]];
  4835. tVect += triTVect[vertToTriMap[vertID2][triID2]];
  4836. }
  4837. }
  4838. }
  4839. }
  4840. // make an orthonormal system.
  4841. // need to check if we are left or right handed.
  4842. Vector tmpVect;
  4843. CrossProduct( sVect, tVect, tmpVect );
  4844. bool leftHanded = DotProduct( tmpVect, normal ) < 0.0f;
  4845. if( !leftHanded )
  4846. {
  4847. CrossProduct( normal, sVect, tVect );
  4848. CrossProduct( tVect, normal, sVect );
  4849. VectorNormalize( sVect );
  4850. VectorNormalize( tVect );
  4851. finalSVect[0] = sVect[0];
  4852. finalSVect[1] = sVect[1];
  4853. finalSVect[2] = sVect[2];
  4854. finalSVect[3] = 1.0f;
  4855. }
  4856. else
  4857. {
  4858. CrossProduct( sVect, normal, tVect );
  4859. CrossProduct( normal, tVect, sVect );
  4860. VectorNormalize( sVect );
  4861. VectorNormalize( tVect );
  4862. finalSVect[0] = sVect[0];
  4863. finalSVect[1] = sVect[1];
  4864. finalSVect[2] = sVect[2];
  4865. finalSVect[3] = -1.0f;
  4866. }
  4867. }
  4868. }
  4869. }
  4870. //-----------------------------------------------------------------------------
  4871. // Generate a model vertex from a source vertex
  4872. //-----------------------------------------------------------------------------
  4873. static void InitRemappedVertex( s_source_t *pSource, matrix3x4_t *pDestBoneToWorld, const s_vertexinfo_t &srcVertex, s_vertexinfo_t &dstVertex )
  4874. {
  4875. Vector tmp1, tmp2, vdest, ndest;
  4876. memcpy( &dstVertex, &srcVertex, sizeof(s_vertexinfo_t) );
  4877. dstVertex.boneweight.numbones = 0;
  4878. vdest.Init();
  4879. ndest.Init();
  4880. int n;
  4881. for ( n = 0; n < srcVertex.boneweight.numbones; n++ )
  4882. {
  4883. // src bone
  4884. int q = srcVertex.boneweight.bone[n];
  4885. // mapping to global bone
  4886. int k = pSource->boneLocalToGlobal[q];
  4887. if ( k == -1 )
  4888. {
  4889. VectorCopy( srcVertex.position, vdest );
  4890. VectorCopy( srcVertex.normal, ndest );
  4891. break;
  4892. // printf("%s:%s (%d) missing global\n", psource->filename, psource->localBone[q].name, q );
  4893. }
  4894. // If the global bone is already in the list, then this vertex
  4895. // contains influences from multiple local bones which have been collapsed
  4896. // into a single global bone
  4897. int m;
  4898. for ( m = 0; m < dstVertex.boneweight.numbones; m++ )
  4899. {
  4900. if ( k == dstVertex.boneweight.bone[m] )
  4901. {
  4902. // bone got collapsed out
  4903. dstVertex.boneweight.weight[m] += srcVertex.boneweight.weight[n];
  4904. break;
  4905. }
  4906. }
  4907. if ( m == dstVertex.boneweight.numbones )
  4908. {
  4909. // add new bone
  4910. dstVertex.boneweight.bone[m] = k;
  4911. dstVertex.boneweight.weight[m] = srcVertex.boneweight.weight[n];
  4912. dstVertex.boneweight.numbones++;
  4913. }
  4914. // convert vertex into original models' bone local space
  4915. VectorITransform( srcVertex.position, pDestBoneToWorld[k], tmp1 );
  4916. // convert that into global world space using stardard pose
  4917. VectorTransform( tmp1, g_bonetable[k].boneToPose, tmp2 );
  4918. // accumulate
  4919. VectorMA( vdest, srcVertex.boneweight.weight[n], tmp2, vdest );
  4920. // convert normal into original models' bone local space
  4921. VectorIRotate( srcVertex.normal, pDestBoneToWorld[k], tmp1 );
  4922. // convert that into global world space using stardard pose
  4923. VectorRotate( tmp1, g_bonetable[k].boneToPose, tmp2 );
  4924. // accumulate
  4925. VectorMA( ndest, srcVertex.boneweight.weight[n], tmp2, ndest );
  4926. }
  4927. // printf("%d %.2f %.2f %.2f\n", j, vdest.x, vdest.y, vdest.z );
  4928. // save, normalize
  4929. VectorCopy( vdest, dstVertex.position );
  4930. VectorNormalize( ndest );
  4931. VectorCopy( ndest, dstVertex.normal );
  4932. // FIXME: Remapping will whack tangentS. Need to recompute tangents after remapping
  4933. }
  4934. //-----------------------------------------------------------------------------
  4935. // When read off disk, s_source_t contains bone indices local to the source
  4936. // we need to make the bone indices use the global bone list
  4937. //-----------------------------------------------------------------------------
  4938. void RemapVerticesToGlobalBones( )
  4939. {
  4940. matrix3x4_t srcBoneToWorld[MAXSTUDIOSRCBONES];
  4941. matrix3x4_t destBoneToWorld[MAXSTUDIOSRCBONES];
  4942. for (int i = 0; i < g_numsources; i++)
  4943. {
  4944. s_source_t *pSource = g_source[i];
  4945. if ( !pSource->vertex )
  4946. continue;
  4947. s_sourceanim_t *pSourceAnim = FindSourceAnim( pSource, "BindPose" );
  4948. if ( !pSourceAnim )
  4949. {
  4950. pSourceAnim = &pSource->m_Animations[0];
  4951. }
  4952. BuildRawTransforms( pSource, pSourceAnim->animationname, 0, srcBoneToWorld );
  4953. TranslateAnimations( pSource, srcBoneToWorld, destBoneToWorld );
  4954. pSource->m_GlobalVertices.AddMultipleToTail( pSource->numvertices );
  4955. for ( int j = 0; j < pSource->numvertices; j++ )
  4956. {
  4957. InitRemappedVertex( pSource, destBoneToWorld, pSource->vertex[j], pSource->m_GlobalVertices[j] );
  4958. }
  4959. }
  4960. }
  4961. //-----------------------------------------------------------------------------
  4962. // Links bone controllers
  4963. //-----------------------------------------------------------------------------
  4964. static void FindAutolayers()
  4965. {
  4966. int i;
  4967. for (i = 0; i < g_sequence.Count(); i++)
  4968. {
  4969. int k;
  4970. for (k = 0; k < g_sequence[i].numautolayers; k++)
  4971. {
  4972. int j;
  4973. for ( j = 0; j < g_sequence.Count(); j++)
  4974. {
  4975. if (stricmp( g_sequence[i].autolayer[k].name, g_sequence[j].name) == 0)
  4976. {
  4977. g_sequence[i].autolayer[k].sequence = j;
  4978. break;
  4979. }
  4980. }
  4981. if (j == g_sequence.Count())
  4982. {
  4983. MdlError( "sequence \"%s\" cannot find autolayer sequence \"%s\"\n",
  4984. g_sequence[i].name, g_sequence[i].autolayer[k].name );
  4985. }
  4986. }
  4987. }
  4988. }
  4989. //-----------------------------------------------------------------------------
  4990. // Links bone controllers
  4991. //-----------------------------------------------------------------------------
  4992. static void LinkBoneControllers()
  4993. {
  4994. for (int i = 0; i < g_numbonecontrollers; i++)
  4995. {
  4996. int j = findGlobalBone( g_bonecontroller[i].name );
  4997. if (j == -1)
  4998. {
  4999. MdlError("unknown g_bonecontroller link '%s'\n", g_bonecontroller[i].name );
  5000. }
  5001. g_bonecontroller[i].bone = j;
  5002. }
  5003. }
  5004. //-----------------------------------------------------------------------------
  5005. // Links screen aligned bones
  5006. //-----------------------------------------------------------------------------
  5007. static void TagScreenAlignedBones()
  5008. {
  5009. for (int i = 0; i < g_numscreenalignedbones; i++)
  5010. {
  5011. int j = findGlobalBone( g_screenalignedbone[i].name );
  5012. if (j == -1)
  5013. {
  5014. MdlError("unknown g_screenalignedbone link '%s'\n", g_screenalignedbone[i].name );
  5015. }
  5016. g_bonetable[j].flags |= g_screenalignedbone[i].flags;
  5017. printf("tagging bone: %s as screen aligned (index %i, flags:%x)\n", g_bonetable[j].name, j, g_bonetable[j].flags );
  5018. }
  5019. }
  5020. //-----------------------------------------------------------------------------
  5021. // Links attachments
  5022. //-----------------------------------------------------------------------------
  5023. static void LinkAttachments()
  5024. {
  5025. int i, j, k;
  5026. // attachments may be connected to bones that can be optimized out
  5027. // so search through all the sources and move to a valid location
  5028. matrix3x4_t boneToPose;
  5029. matrix3x4_t world;
  5030. matrix3x4_t poseToBone;
  5031. for (i = 0; i < g_numattachments; i++)
  5032. {
  5033. bool found = false;
  5034. // search through known bones
  5035. for (k = 0; k < g_numbones; k++)
  5036. {
  5037. if ( !stricmp( g_attachment[i].bonename, g_bonetable[k].name ))
  5038. {
  5039. g_attachment[i].bone = k;
  5040. MatrixCopy( g_bonetable[k].boneToPose, boneToPose );
  5041. MatrixInvert( boneToPose, poseToBone );
  5042. // printf("%s : %d\n", g_bonetable[k].name, k );
  5043. found = true;
  5044. break;
  5045. }
  5046. }
  5047. if (!found)
  5048. {
  5049. // search all the loaded sources for the first occurance of the named bone
  5050. for (j = 0; j < g_numsources && !found; j++)
  5051. {
  5052. for (k = 0; k < g_source[j]->numbones && !found; k++)
  5053. {
  5054. if ( !stricmp( g_attachment[i].bonename, g_source[j]->localBone[k].name ) )
  5055. {
  5056. MatrixCopy( g_source[j]->boneToPose[k], boneToPose );
  5057. // check to make sure that this bone is actually referenced in the output model
  5058. // if not, try parent bone until we find a referenced bone in this chain
  5059. while (k != -1 && g_source[j]->boneGlobalToLocal[g_source[j]->boneLocalToGlobal[k]] != k)
  5060. {
  5061. k = g_source[j]->localBone[k].parent;
  5062. }
  5063. if (k == -1)
  5064. {
  5065. MdlError( "unable to find valid bone for attachment %s:%s\n",
  5066. g_attachment[i].name,
  5067. g_attachment[i].bonename );
  5068. }
  5069. MatrixInvert( g_source[j]->boneToPose[k], poseToBone );
  5070. g_attachment[i].bone = g_source[j]->boneLocalToGlobal[k];
  5071. found = true;
  5072. }
  5073. }
  5074. }
  5075. }
  5076. if (!found)
  5077. {
  5078. MdlError("unknown attachment link '%s'\n", g_attachment[i].bonename );
  5079. }
  5080. // printf("%s: %s / %s\n", g_attachment[i].name, g_attachment[i].bonename, g_bonetable[g_attachment[i].bone].name );
  5081. if (g_attachment[i].type & IS_ABSOLUTE)
  5082. {
  5083. MatrixCopy( g_attachment[i].local, world );
  5084. }
  5085. else
  5086. {
  5087. ConcatTransforms( boneToPose, g_attachment[i].local, world );
  5088. }
  5089. ConcatTransforms( poseToBone, world, g_attachment[i].local );
  5090. }
  5091. // flag all bones used by attachments
  5092. for (i = 0; i < g_numattachments; i++)
  5093. {
  5094. j = g_attachment[i].bone;
  5095. while (j != -1)
  5096. {
  5097. g_bonetable[j].flags |= BONE_USED_BY_ATTACHMENT;
  5098. j = g_bonetable[j].parent;
  5099. }
  5100. }
  5101. }
  5102. //-----------------------------------------------------------------------------
  5103. // Links mouths
  5104. //-----------------------------------------------------------------------------
  5105. static void LinkMouths()
  5106. {
  5107. for (int i = 0; i < g_nummouths; i++)
  5108. {
  5109. int j;
  5110. for ( j = 0; j < g_numbones; j++)
  5111. {
  5112. if (g_mouth[i].bonename[0] && stricmp( g_mouth[i].bonename, g_bonetable[j].name) == 0)
  5113. break;
  5114. }
  5115. if (j >= g_numbones)
  5116. {
  5117. MdlError("unknown mouth link '%s'\n", g_mouth[i].bonename );
  5118. }
  5119. g_mouth[i].bone = j;
  5120. }
  5121. }
  5122. //-----------------------------------------------------------------------------
  5123. //
  5124. //-----------------------------------------------------------------------------
  5125. static float CalcPoseParameterValue( int control, RadianEuler &angle, Vector &pos )
  5126. {
  5127. switch( control )
  5128. {
  5129. case STUDIO_X:
  5130. return pos.x;
  5131. case STUDIO_Y:
  5132. return pos.y;
  5133. case STUDIO_Z:
  5134. return pos.z;
  5135. case STUDIO_XR:
  5136. return RAD2DEG( angle.x );
  5137. case STUDIO_YR:
  5138. return RAD2DEG( angle.y );
  5139. case STUDIO_ZR:
  5140. return RAD2DEG( angle.z );
  5141. }
  5142. return 0.0;
  5143. }
  5144. static void CalcPoseParameters( void )
  5145. {
  5146. int i;
  5147. matrix3x4_t boneToWorld[MAXSTUDIOBONES];
  5148. RadianEuler angles;
  5149. Vector pos;
  5150. for (i = 0; i < g_sequence.Count(); i++)
  5151. {
  5152. s_sequence_t *pseq = &g_sequence[i];
  5153. for (int iPose = 0; iPose < 2; iPose++)
  5154. {
  5155. if (pseq->groupsize[iPose] > 1)
  5156. {
  5157. if (pseq->paramattachment[iPose] != -1)
  5158. {
  5159. int j0 = pseq->paramindex[iPose];
  5160. int n0 = pseq->paramattachment[iPose];
  5161. int k0 = g_attachment[n0].bone;
  5162. matrix3x4_t boneToWorldRel;
  5163. matrix3x4_t boneToWorldMid;
  5164. matrix3x4_t worldToBoneMid;
  5165. matrix3x4_t boneRel;
  5166. // printf("%s\n", pseq->name );
  5167. if (pseq->paramanim == NULL)
  5168. {
  5169. pseq->paramanim = g_panimation[0];
  5170. }
  5171. if (pseq->paramcompanim == NULL)
  5172. {
  5173. pseq->paramcompanim = pseq->paramanim;
  5174. }
  5175. // calculate what "zero" looks like to the attachment
  5176. CalcBoneTransforms( pseq->paramanim, 0, boneToWorld );
  5177. ConcatTransforms( boneToWorld[k0], g_attachment[n0].local, boneToWorldMid );
  5178. MatrixAngles( boneToWorldMid, angles, pos );
  5179. // printf("%s : %s : %6.2f %6.2f %6.2f : %6.2f %6.2f %6.2f\n", pseq->name, g_pose[j0].name, RAD2DEG( angles.x ), RAD2DEG( angles.y ), RAD2DEG( angles.z ), pos.x, pos.y, pos.z );
  5180. MatrixInvert( boneToWorldMid, worldToBoneMid );
  5181. if ( g_verbose )
  5182. {
  5183. printf("%s : %s", pseq->name, g_pose[j0].name );
  5184. }
  5185. // for 2D animation, figure out what opposite row/column to use
  5186. // FIXME: make these 2D instead of 2 1D!
  5187. int m[2];
  5188. bool found = false;
  5189. if (pseq->paramcenter != NULL)
  5190. {
  5191. for (int i0 = 0; !found && i0 < pseq->groupsize[0]; i0++)
  5192. {
  5193. for (int i1 = 0; !found && i1 < pseq->groupsize[1]; i1++)
  5194. {
  5195. if (pseq->panim[i0][i1] == pseq->paramcenter)
  5196. {
  5197. m[0] = i0;
  5198. m[1] = i1;
  5199. found = true;
  5200. }
  5201. }
  5202. }
  5203. }
  5204. if (!found)
  5205. {
  5206. m[1-iPose] = (pseq->groupsize[1-iPose]) / 2;
  5207. }
  5208. // find changes to attachment
  5209. for (m[iPose] = 0; m[iPose] < pseq->groupsize[iPose]; m[iPose]++)
  5210. {
  5211. CalcBoneTransforms( pseq->panim[m[0]][m[1]], pseq->paramcompanim, 0, boneToWorld );
  5212. ConcatTransforms( boneToWorld[k0], g_attachment[n0].local, boneToWorldRel );
  5213. ConcatTransforms( worldToBoneMid, boneToWorldRel, boneRel );
  5214. MatrixAngles( boneRel, angles, pos );
  5215. // printf("%6.2f %6.2f %6.2f : %6.2f %6.2f %6.2f\n", RAD2DEG( angles.x ), RAD2DEG( angles.y ), RAD2DEG( angles.z ), pos.x, pos.y, pos.z );
  5216. float v = CalcPoseParameterValue( pseq->paramcontrol[iPose], angles, pos );
  5217. if ( g_verbose )
  5218. {
  5219. printf(" %6.2f", v );
  5220. }
  5221. if (iPose == 0)
  5222. {
  5223. pseq->param0[m[iPose]] = v;
  5224. }
  5225. else
  5226. {
  5227. pseq->param1[m[iPose]] = v;
  5228. }
  5229. // pseq->param1[i0][i1] = CalcPoseParameterValue( pseq->paramcontrol[1], angles, pos );
  5230. if (m[iPose] == 0)
  5231. {
  5232. pseq->paramstart[iPose] = (iPose == 0) ? pseq->param0[m[iPose]] : pseq->param1[m[iPose]];
  5233. }
  5234. if (m[iPose] == pseq->groupsize[iPose] - 1)
  5235. {
  5236. pseq->paramend[iPose] = (iPose == 0) ? pseq->param0[m[iPose]] : pseq->param1[m[iPose]];
  5237. }
  5238. }
  5239. if ( g_verbose )
  5240. {
  5241. printf("\n");
  5242. }
  5243. if (fabs( pseq->paramstart[iPose] - pseq->paramend[iPose]) < 0.01 )
  5244. {
  5245. MdlError( "calcblend failed in %s\n", pseq->name );
  5246. }
  5247. g_pose[j0].min = min( g_pose[j0].min, pseq->paramstart[iPose] );
  5248. g_pose[j0].max = max( g_pose[j0].max, pseq->paramstart[iPose] );
  5249. g_pose[j0].min = min( g_pose[j0].min, pseq->paramend[iPose] );
  5250. g_pose[j0].max = max( g_pose[j0].max, pseq->paramend[iPose] );
  5251. }
  5252. else
  5253. {
  5254. for (int m = 0; m < pseq->groupsize[iPose]; m++)
  5255. {
  5256. float f = (m / (float)(pseq->groupsize[iPose] - 1.0));
  5257. if (iPose == 0)
  5258. {
  5259. pseq->param0[m] = pseq->paramstart[iPose] * (1.0 - f) + pseq->paramend[iPose] * f;
  5260. }
  5261. else
  5262. {
  5263. pseq->param1[m] = pseq->paramstart[iPose] * (1.0 - f) + pseq->paramend[iPose] * f;
  5264. }
  5265. }
  5266. }
  5267. }
  5268. }
  5269. }
  5270. // exit(0);
  5271. }
  5272. //-----------------------------------------------------------------------------
  5273. // Link ikchains
  5274. //-----------------------------------------------------------------------------
  5275. static void LinkIKChains( )
  5276. {
  5277. int i, k;
  5278. // create IK links
  5279. for (i = 0; i < g_numikchains; i++)
  5280. {
  5281. g_ikchain[i].numlinks = 3;
  5282. k = findGlobalBone( g_ikchain[i].bonename );
  5283. if (k == -1)
  5284. {
  5285. MdlError("unknown bone '%s' in ikchain '%s'\n", g_ikchain[i].bonename, g_ikchain[i].name );
  5286. }
  5287. g_ikchain[i].link[2].bone = k;
  5288. g_bonetable[k].flags |= BONE_USED_BY_ATTACHMENT;
  5289. k = g_bonetable[k].parent;
  5290. if (k == -1)
  5291. {
  5292. MdlError("ikchain '%s' too close to root, no parent knee/elbow\n", g_ikchain[i].name );
  5293. }
  5294. g_ikchain[i].link[1].bone = k;
  5295. g_bonetable[k].flags |= BONE_USED_BY_ATTACHMENT;
  5296. k = g_bonetable[k].parent;
  5297. if (k == -1)
  5298. {
  5299. MdlError("ikchain '%s' too close to root, no parent hip/shoulder\n", g_ikchain[i].name );
  5300. }
  5301. g_ikchain[i].link[0].bone = k;
  5302. g_bonetable[k].flags |= BONE_USED_BY_ATTACHMENT;
  5303. // FIXME: search for toes
  5304. }
  5305. }
  5306. //-----------------------------------------------------------------------------
  5307. // Link ikchains
  5308. //-----------------------------------------------------------------------------
  5309. static void LinkIKLocks( )
  5310. {
  5311. int i, j;
  5312. // create IK links
  5313. for (i = 0; i < g_numikautoplaylocks; i++)
  5314. {
  5315. for (j = 0; j < g_numikchains; j++)
  5316. {
  5317. if (stricmp( g_ikchain[j].name, g_ikautoplaylock[i].name) == 0)
  5318. {
  5319. break;
  5320. }
  5321. }
  5322. if (j == g_numikchains)
  5323. {
  5324. MdlError("unknown chain '%s' in ikautoplaylock\n", g_ikautoplaylock[i].name );
  5325. }
  5326. g_ikautoplaylock[i].chain = j;
  5327. }
  5328. int k;
  5329. for (k = 0; k < g_sequence.Count(); k++)
  5330. {
  5331. for (i = 0; i < g_sequence[k].numiklocks; i++)
  5332. {
  5333. for (j = 0; j < g_numikchains; j++)
  5334. {
  5335. if (stricmp( g_ikchain[j].name, g_sequence[k].iklock[i].name) == 0)
  5336. {
  5337. break;
  5338. }
  5339. }
  5340. if (j == g_numikchains)
  5341. {
  5342. MdlError("unknown chain '%s' in sequence iklock\n", g_sequence[k].iklock[i].name );
  5343. }
  5344. g_sequence[k].iklock[i].chain = j;
  5345. }
  5346. }
  5347. }
  5348. //-----------------------------------------------------------------------------
  5349. // Process IK links
  5350. //-----------------------------------------------------------------------------
  5351. s_ikrule_t *FindPrevIKRule( s_animation_t *panim, int iRule )
  5352. {
  5353. int i, j;
  5354. s_ikrule_t *pRule = &panim->ikrule[iRule];
  5355. for (i = 1; i < panim->numikrules; i++)
  5356. {
  5357. j = ( iRule - i + panim->numikrules) % panim->numikrules;
  5358. if (panim->ikrule[j].chain == pRule->chain)
  5359. return &panim->ikrule[j];
  5360. }
  5361. return pRule;
  5362. }
  5363. s_ikrule_t *FindNextIKRule( s_animation_t *panim, int iRule )
  5364. {
  5365. int i, j;
  5366. s_ikrule_t *pRule = &panim->ikrule[iRule];
  5367. for (i = 1; i < panim->numikrules; i++)
  5368. {
  5369. j = (iRule + i ) % panim->numikrules;
  5370. if (panim->ikrule[j].chain == pRule->chain)
  5371. return &panim->ikrule[j];
  5372. }
  5373. return pRule;
  5374. }
  5375. //-----------------------------------------------------------------------------
  5376. // Purpose: don't allow bones to change their length if they're predefined.
  5377. // go through all the animations and reset them, but move anything on an ikchain back to where it was.
  5378. //-----------------------------------------------------------------------------
  5379. static void LockBoneLengths()
  5380. {
  5381. int i, j, k;
  5382. int n;
  5383. if (!g_bLockBoneLengths)
  5384. return;
  5385. Vector origLocalPos[MAXSTUDIOBONES];
  5386. // find original lengths
  5387. for (k = 0; k < g_numbones; k++)
  5388. {
  5389. MatrixPosition( g_bonetable[k].rawLocalOriginal, origLocalPos[k] );
  5390. if ( g_verbose )
  5391. {
  5392. Vector prev, delta;
  5393. MatrixPosition( g_bonetable[k].rawLocal, prev );
  5394. delta = prev - origLocalPos[k];
  5395. printf("%s - %f %f %f\n", g_bonetable[k].name, delta.x, delta.y, delta.z );
  5396. }
  5397. }
  5398. for (i = 0; i < g_numani; i++)
  5399. {
  5400. s_animation_t *panim = g_panimation[i];
  5401. if (panim->flags & STUDIO_DELTA)
  5402. continue;
  5403. for (j = 0; j < panim->numframes; j++)
  5404. {
  5405. matrix3x4_t boneToWorldOriginal[MAXSTUDIOBONES];
  5406. matrix3x4_t boneToWorld[MAXSTUDIOBONES];
  5407. // calc original transformations
  5408. CalcBoneTransforms( panim, j, boneToWorldOriginal );
  5409. // force bones back to original lengths
  5410. for (k = 0; k < g_numbones; k++)
  5411. {
  5412. if (g_bonetable[k].parent != -1)
  5413. {
  5414. //Vector delta = panim->sanim[j][k].pos - origLocalPos[k];
  5415. //printf("%f %f %f\n", delta.x, delta.y, delta.z );
  5416. panim->sanim[j][k].pos = origLocalPos[k];
  5417. }
  5418. }
  5419. // calc new transformations
  5420. CalcBoneTransforms( panim, j, boneToWorld );
  5421. for (n = 0; n < g_numikchains; n++)
  5422. {
  5423. if (panim->weight[g_ikchain[n].link[2].bone] > 0)
  5424. {
  5425. Vector worldPos;
  5426. MatrixPosition( boneToWorldOriginal[g_ikchain[n].link[2].bone], worldPos );
  5427. Studio_SolveIK(
  5428. g_ikchain[n].link[0].bone,
  5429. g_ikchain[n].link[1].bone,
  5430. g_ikchain[n].link[2].bone,
  5431. worldPos,
  5432. boneToWorld );
  5433. solveBone( panim, j, g_ikchain[n].link[0].bone, boneToWorld );
  5434. solveBone( panim, j, g_ikchain[n].link[1].bone, boneToWorld );
  5435. solveBone( panim, j, g_ikchain[n].link[2].bone, boneToWorld );
  5436. }
  5437. }
  5438. }
  5439. }
  5440. }
  5441. //-----------------------------------------------------------------------------
  5442. // Purpose: go through all the IK rules and calculate the animated path the IK'd
  5443. // end point moves relative to its IK target.
  5444. //-----------------------------------------------------------------------------
  5445. static void ProcessIKRules( )
  5446. {
  5447. int i, j, k;
  5448. // copy source animations
  5449. for (i = 0; i < g_numani; i++)
  5450. {
  5451. s_animation_t *panim = g_panimation[i];
  5452. const char *pAnimationName = g_panimation[i]->animationname;
  5453. s_sourceanim_t *pSourceAnim = FindSourceAnim( panim->source, pAnimationName );
  5454. for (j = 0; j < panim->numcmds; j++)
  5455. {
  5456. if ( panim->cmds[j].cmd == CMD_IKFIXUP )
  5457. {
  5458. fixupIKErrors( panim, panim->cmds[j].u.ikfixup.pRule );
  5459. }
  5460. if (panim->cmds[j].cmd != CMD_IKRULE)
  5461. continue;
  5462. if (panim->numikrules >= MAXSTUDIOIKRULES)
  5463. {
  5464. MdlError("Too many IK rules in %s (%s)\n", panim->name, panim->filename );
  5465. }
  5466. s_ikrule_t *pRule = &panim->ikrule[panim->numikrules++];
  5467. // make a copy of the rule;
  5468. *pRule = *panim->cmds[j].u.ikrule.pRule;
  5469. }
  5470. for (j = 0; j < panim->numikrules; j++)
  5471. {
  5472. s_ikrule_t *pRule = &panim->ikrule[j];
  5473. if (pRule->start == 0 && pRule->peak == 0 && pRule->tail == 0 && pRule->end == 0)
  5474. {
  5475. pRule->tail = panim->numframes - 1;
  5476. pRule->end = panim->numframes - 1;
  5477. }
  5478. if (pRule->start != -1 && pRule->peak == -1 && pRule->tail == -1 && pRule->end != -1)
  5479. {
  5480. pRule->peak = (pRule->start + pRule->end) / 2;
  5481. pRule->tail = (pRule->start + pRule->end) / 2;
  5482. }
  5483. if (pRule->start != -1 && pRule->peak == -1 && pRule->tail != -1)
  5484. {
  5485. pRule->peak = (pRule->start + pRule->tail) / 2;
  5486. }
  5487. if (pRule->peak != -1 && pRule->tail == -1 && pRule->end != -1)
  5488. {
  5489. pRule->tail = (pRule->peak + pRule->end) / 2;
  5490. }
  5491. if (pRule->peak == -1)
  5492. {
  5493. pRule->start = 0;
  5494. pRule->peak = 0;
  5495. }
  5496. if (pRule->tail == -1)
  5497. {
  5498. pRule->tail = panim->numframes - 1;
  5499. pRule->end = panim->numframes - 1;
  5500. }
  5501. if (pRule->contact == -1)
  5502. {
  5503. pRule->contact = pRule->peak;
  5504. }
  5505. // huh, make up start and end numbers
  5506. if (pRule->start == -1)
  5507. {
  5508. s_ikrule_t *pPrev = FindPrevIKRule( panim, j );
  5509. if (pPrev->slot == pRule->slot)
  5510. {
  5511. if (pRule->peak < pPrev->tail)
  5512. {
  5513. pRule->start = pRule->peak + (pPrev->tail - pRule->peak) / 2;
  5514. }
  5515. else
  5516. {
  5517. pRule->start = pRule->peak + (pPrev->tail - pRule->peak + panim->numframes - 1) / 2;
  5518. }
  5519. pRule->start = (pRule->start + panim->numframes / 2) % (panim->numframes - 1);
  5520. pPrev->end = (pRule->start + panim->numframes - 1) % (panim->numframes - 1);
  5521. }
  5522. else
  5523. {
  5524. pRule->start = pPrev->tail;
  5525. pPrev->end = pRule->peak;
  5526. }
  5527. // printf("%s : %d (%d) : %d %d %d %d\n", panim->name, pRule->chain, panim->numframes - 1, pRule->start, pRule->peak, pRule->tail, pRule->end );
  5528. }
  5529. // huh, make up start and end numbers
  5530. if (pRule->end == -1)
  5531. {
  5532. s_ikrule_t *pNext = FindNextIKRule( panim, j );
  5533. if (pNext->slot == pRule->slot)
  5534. {
  5535. if (pNext->peak < pRule->tail)
  5536. {
  5537. pNext->start = pNext->peak + (pRule->tail - pNext->peak) / 2;
  5538. }
  5539. else
  5540. {
  5541. pNext->start = pNext->peak + (pRule->tail - pNext->peak + panim->numframes - 1) / 2;
  5542. }
  5543. pNext->start = (pNext->start + panim->numframes / 2) % (panim->numframes - 1);
  5544. pRule->end = (pNext->start + panim->numframes - 1) % (panim->numframes - 1);
  5545. }
  5546. else
  5547. {
  5548. pNext->start = pRule->tail;
  5549. pRule->end = pNext->peak;
  5550. }
  5551. // printf("%s : %d (%d) : %d %d %d %d\n", panim->name, pRule->chain, panim->numframes - 1, pRule->start, pRule->peak, pRule->tail, pRule->end );
  5552. }
  5553. // check for wrapping
  5554. if (pRule->peak < pRule->start)
  5555. {
  5556. pRule->peak += panim->numframes - 1;
  5557. }
  5558. if (pRule->tail < pRule->peak)
  5559. {
  5560. pRule->tail += panim->numframes - 1;
  5561. }
  5562. if (pRule->end < pRule->tail)
  5563. {
  5564. pRule->end += panim->numframes - 1;
  5565. }
  5566. if (pRule->contact < pRule->start)
  5567. {
  5568. pRule->contact += panim->numframes - 1;
  5569. }
  5570. /*
  5571. printf("%s : %d (%d) : %d %d %d %d : %s\n", panim->name, pRule->chain, panim->numframes - 1, pRule->start, pRule->peak, pRule->tail, pRule->end,
  5572. pRule->usesequence ? "usesequence" : pRule->usesource ? "source" : "" );
  5573. */
  5574. pRule->errorData.numerror = pRule->end - pRule->start + 1;
  5575. if (pRule->end >= panim->numframes)
  5576. pRule->errorData.numerror = pRule->errorData.numerror + 2;
  5577. pRule->errorData.pError = (s_streamdata_t *)kalloc( pRule->errorData.numerror, sizeof( s_streamdata_t ));
  5578. int n = 0;
  5579. if (pRule->usesequence)
  5580. {
  5581. // FIXME: bah, this is horrendously hacky, add a damn back pointer
  5582. for (n = 0; n < g_sequence.Count(); n++)
  5583. {
  5584. if (g_sequence[n].panim[0][0] == panim)
  5585. break;
  5586. }
  5587. }
  5588. switch( pRule->type )
  5589. {
  5590. case IK_SELF:
  5591. {
  5592. matrix3x4_t boneToWorld[MAXSTUDIOBONES];
  5593. matrix3x4_t worldToBone;
  5594. matrix3x4_t local;
  5595. if (strlen(pRule->bonename) == 0)
  5596. {
  5597. pRule->bone = -1;
  5598. }
  5599. else
  5600. {
  5601. pRule->bone = findGlobalBone( pRule->bonename );
  5602. if (pRule->bone == -1)
  5603. {
  5604. MdlError("unknown bone '%s' in ikrule\n", pRule->bonename );
  5605. }
  5606. }
  5607. for (k = 0; k < pRule->errorData.numerror; k++)
  5608. {
  5609. if (pRule->usesequence)
  5610. {
  5611. CalcSeqTransforms( n, k + pRule->start, boneToWorld );
  5612. }
  5613. else if (pRule->usesource)
  5614. {
  5615. matrix3x4_t srcBoneToWorld[MAXSTUDIOSRCBONES];
  5616. BuildRawTransforms( panim->source, pAnimationName, k + pRule->start + panim->startframe - pSourceAnim->startframe, panim->scale, panim->adjust, panim->rotation, panim->flags, srcBoneToWorld );
  5617. TranslateAnimations( panim->source, srcBoneToWorld, boneToWorld );
  5618. }
  5619. else
  5620. {
  5621. CalcBoneTransforms( panim, k + pRule->start, boneToWorld );
  5622. }
  5623. if (pRule->bone != -1)
  5624. {
  5625. MatrixInvert( boneToWorld[pRule->bone], worldToBone );
  5626. ConcatTransforms( worldToBone, boneToWorld[g_ikchain[pRule->chain].link[2].bone], local );
  5627. }
  5628. else
  5629. {
  5630. MatrixCopy( boneToWorld[g_ikchain[pRule->chain].link[2].bone], local );
  5631. }
  5632. MatrixAngles( local, pRule->errorData.pError[k].q, pRule->errorData.pError[k].pos );
  5633. /*
  5634. QAngle ang;
  5635. QuaternionAngles( pRule->errorData.pError[k].q, ang );
  5636. printf("%d %.1f %.1f %.1f : %.1f %.1f %.1f\n",
  5637. k,
  5638. pRule->errorData.pError[k].pos.x, pRule->errorData.pError[k].pos.y, pRule->errorData.pError[k].pos.z,
  5639. ang.x, ang.y, ang.z );
  5640. */
  5641. }
  5642. }
  5643. break;
  5644. case IK_WORLD:
  5645. break;
  5646. case IK_ATTACHMENT:
  5647. {
  5648. matrix3x4_t boneToWorld[MAXSTUDIOBONES];
  5649. matrix3x4_t worldToBone;
  5650. matrix3x4_t local;
  5651. int bone = g_ikchain[pRule->chain].link[2].bone;
  5652. CalcBoneTransforms( panim, pRule->contact, boneToWorld );
  5653. // FIXME: add in motion
  5654. // pRule->pos = footfall;
  5655. // pRule->q = RadianEuler( 0, 0, 0 );
  5656. if (strlen(pRule->bonename) == 0)
  5657. {
  5658. if (pRule->bone != -1)
  5659. {
  5660. pRule->bone = bone;
  5661. }
  5662. }
  5663. else
  5664. {
  5665. pRule->bone = findGlobalBone( pRule->bonename );
  5666. if (pRule->bone == -1)
  5667. {
  5668. MdlError("unknown bone '%s' in ikrule\n", pRule->bonename );
  5669. }
  5670. }
  5671. if (pRule->bone != -1)
  5672. {
  5673. // FIXME: look for local bones...
  5674. CalcBoneTransforms( panim, pRule->contact, boneToWorld );
  5675. MatrixAngles( boneToWorld[pRule->bone], pRule->q, pRule->pos );
  5676. }
  5677. #if 0
  5678. printf("%d %.1f %.1f %.1f\n",
  5679. pRule->peak,
  5680. pRule->pos.x, pRule->pos.y, pRule->pos.z );
  5681. #endif
  5682. for (k = 0; k < pRule->errorData.numerror; k++)
  5683. {
  5684. int t = k + pRule->start;
  5685. if (pRule->usesequence)
  5686. {
  5687. CalcSeqTransforms( n, t, boneToWorld );
  5688. }
  5689. else if (pRule->usesource)
  5690. {
  5691. matrix3x4_t srcBoneToWorld[MAXSTUDIOSRCBONES];
  5692. BuildRawTransforms( panim->source, pAnimationName, t + panim->startframe - pSourceAnim->startframe, srcBoneToWorld );
  5693. TranslateAnimations( panim->source, srcBoneToWorld, boneToWorld );
  5694. }
  5695. else
  5696. {
  5697. CalcBoneTransforms( panim, t, boneToWorld );
  5698. }
  5699. Vector pos = pRule->pos + calcMovement( panim, t, pRule->contact );
  5700. // printf("%2d : %2d : %4.2f %6.1f %6.1f %6.1f\n", k, t, s, pos.x, pos.y, pos.z );
  5701. AngleMatrix( pRule->q, pos, local );
  5702. MatrixInvert( local, worldToBone );
  5703. // calc position error
  5704. ConcatTransforms( worldToBone, boneToWorld[bone], local );
  5705. MatrixAngles( local, pRule->errorData.pError[k].q, pRule->errorData.pError[k].pos );
  5706. #if 0
  5707. QAngle ang;
  5708. QuaternionAngles( pRule->errorData.pError[k].q, ang );
  5709. printf("%d %.1f %.1f %.1f : %.1f %.1f %.1f\n",
  5710. k + pRule->start,
  5711. pRule->errorData.pError[k].pos.x, pRule->errorData.pError[k].pos.y, pRule->errorData.pError[k].pos.z,
  5712. ang.x, ang.y, ang.z );
  5713. #endif
  5714. }
  5715. }
  5716. break;
  5717. case IK_GROUND:
  5718. {
  5719. matrix3x4_t boneToWorld[MAXSTUDIOBONES];
  5720. matrix3x4_t worldToBone;
  5721. matrix3x4_t local;
  5722. int bone = g_ikchain[pRule->chain].link[2].bone;
  5723. if (pRule->usesequence)
  5724. {
  5725. CalcSeqTransforms( n, pRule->contact, boneToWorld );
  5726. }
  5727. else if (pRule->usesource)
  5728. {
  5729. matrix3x4_t srcBoneToWorld[MAXSTUDIOSRCBONES];
  5730. BuildRawTransforms( panim->source, pAnimationName, pRule->contact + panim->startframe - pSourceAnim->startframe, panim->scale, panim->adjust, panim->rotation, panim->flags, srcBoneToWorld );
  5731. TranslateAnimations( panim->source, srcBoneToWorld, boneToWorld );
  5732. }
  5733. else
  5734. {
  5735. CalcBoneTransforms( panim, pRule->contact, boneToWorld );
  5736. }
  5737. // FIXME: add in motion
  5738. Vector footfall;
  5739. VectorTransform( g_ikchain[pRule->chain].center, boneToWorld[bone], footfall );
  5740. footfall.z = pRule->floor;
  5741. AngleMatrix( RadianEuler( 0, 0, 0 ), footfall, local );
  5742. MatrixInvert( local, worldToBone );
  5743. pRule->pos = footfall;
  5744. pRule->q = RadianEuler( 0, 0, 0 );
  5745. #if 0
  5746. printf("%d %.1f %.1f %.1f\n",
  5747. pRule->peak,
  5748. pRule->pos.x, pRule->pos.y, pRule->pos.z );
  5749. #endif
  5750. float s;
  5751. for (k = 0; k < pRule->errorData.numerror; k++)
  5752. {
  5753. int t = k + pRule->start;
  5754. /*
  5755. if (t > pRule->end)
  5756. {
  5757. t = t - (panim->numframes - 1);
  5758. }
  5759. */
  5760. if (pRule->usesequence)
  5761. {
  5762. CalcSeqTransforms( n, t, boneToWorld );
  5763. }
  5764. else if (pRule->usesource)
  5765. {
  5766. matrix3x4_t srcBoneToWorld[MAXSTUDIOSRCBONES];
  5767. BuildRawTransforms( panim->source, pAnimationName, pRule->contact + panim->startframe - pSourceAnim->startframe, panim->scale, panim->adjust, panim->rotation, panim->flags, srcBoneToWorld );
  5768. TranslateAnimations( panim->source, srcBoneToWorld, boneToWorld );
  5769. }
  5770. else
  5771. {
  5772. CalcBoneTransforms( panim, t, boneToWorld );
  5773. }
  5774. Vector pos = pRule->pos + calcMovement( panim, t, pRule->contact );
  5775. s = 0.0;
  5776. Vector cur;
  5777. VectorTransform( g_ikchain[pRule->chain].center, boneToWorld[bone], cur );
  5778. cur.z = pos.z;
  5779. if (t < pRule->start || t >= pRule->end)
  5780. {
  5781. // s = (float)(t - pRule->start) / (pRule->peak - pRule->start);
  5782. // pos = startPos * (1 - s) + pos * s;
  5783. pos = cur;
  5784. }
  5785. else if (t < pRule->peak)
  5786. {
  5787. s = (float)(pRule->peak - t) / (pRule->peak - pRule->start);
  5788. s = 3 * s * s - 2 * s * s * s;
  5789. pos = pos * (1 - s) + cur * s;
  5790. }
  5791. else if (t > pRule->tail)
  5792. {
  5793. s = (float)(t - pRule->tail) / (pRule->end - pRule->tail);
  5794. s = 3 * s * s - 2 * s * s * s;
  5795. pos = pos * (1 - s) + cur * s;
  5796. //pos = endPos - calcMovement( panim, t, pRule->tail );
  5797. }
  5798. //MatrixPosition( boneToWorld[bone], pos );
  5799. //pos.z = pRule->floor;
  5800. // printf("%2d : %2d : %4.2f %6.1f %6.1f %6.1f\n", k, t, s, pos.x, pos.y, pos.z );
  5801. AngleMatrix( pRule->q, pos, local );
  5802. MatrixInvert( local, worldToBone );
  5803. // calc position error
  5804. ConcatTransforms( worldToBone, boneToWorld[bone], local );
  5805. MatrixAngles( local, pRule->errorData.pError[k].q, pRule->errorData.pError[k].pos );
  5806. #if 0
  5807. QAngle ang;
  5808. QuaternionAngles( pRule->errorData.pError[k].q, ang );
  5809. printf("%d %.1f %.1f %.1f : %.1f %.1f %.1f\n",
  5810. k + pRule->start,
  5811. pRule->errorData.pError[k].pos.x, pRule->errorData.pError[k].pos.y, pRule->errorData.pError[k].pos.z,
  5812. ang.x, ang.y, ang.z );
  5813. #endif
  5814. }
  5815. }
  5816. break;
  5817. case IK_RELEASE:
  5818. case IK_UNLATCH:
  5819. break;
  5820. }
  5821. }
  5822. if ((panim->flags & STUDIO_DELTA) || panim->noAutoIK)
  5823. continue;
  5824. // auto release ik chains that are moved but not referenced and have no explicit rules
  5825. int count[16];
  5826. for (j = 0; j < g_numikchains; j++)
  5827. {
  5828. count[j] = 0;
  5829. }
  5830. for (j = 0; j < panim->numikrules; j++)
  5831. {
  5832. count[panim->ikrule[j].chain]++;
  5833. }
  5834. for (j = 0; j < g_numikchains; j++)
  5835. {
  5836. if (count[j] == 0 && panim->weight[g_ikchain[j].link[2].bone] > 0.0)
  5837. {
  5838. // printf("%s - %s\n", panim->name, g_ikchain[j].name );
  5839. k = panim->numikrules++;
  5840. panim->ikrule[k].chain = j;
  5841. panim->ikrule[k].slot = j;
  5842. panim->ikrule[k].type = IK_RELEASE;
  5843. panim->ikrule[k].start = 0;
  5844. panim->ikrule[k].peak = 0;
  5845. panim->ikrule[k].tail = panim->numframes - 1;
  5846. panim->ikrule[k].end = panim->numframes - 1;
  5847. }
  5848. }
  5849. }
  5850. // exit(0);
  5851. // realign IK across multiple animations
  5852. for (i = 0; i < g_sequence.Count(); i++)
  5853. {
  5854. for (j = 0; j < g_sequence[i].groupsize[0]; j++)
  5855. {
  5856. for (k = 0; k < g_sequence[i].groupsize[1]; k++)
  5857. {
  5858. g_sequence[i].numikrules = max( g_sequence[i].numikrules, g_sequence[i].panim[j][k]->numikrules );
  5859. }
  5860. }
  5861. // check for mismatched ik rules
  5862. s_animation_t *panim1 = g_sequence[i].panim[0][0];
  5863. for (j = 0; j < g_sequence[i].groupsize[0]; j++)
  5864. {
  5865. for (k = 0; k < g_sequence[i].groupsize[1]; k++)
  5866. {
  5867. s_animation_t *panim2 = g_sequence[i].panim[j][k];
  5868. if (panim1->numikrules != panim2->numikrules)
  5869. {
  5870. MdlError( "%s - mismatched number of IK rules: \"%s\" \"%s\"\n",
  5871. g_sequence[i].name, panim1->name, panim2->name );
  5872. }
  5873. for (int n = 0; n < panim1->numikrules; n++)
  5874. {
  5875. if ((panim1->ikrule[n].type != panim2->ikrule[n].type) ||
  5876. (panim1->ikrule[n].chain != panim2->ikrule[n].chain) ||
  5877. (panim1->ikrule[n].slot != panim2->ikrule[n].slot))
  5878. {
  5879. MdlError( "%s - mismatched IK rule %d: \n\"%s\" : %d %d %d\n\"%s\" : %d %d %d\n",
  5880. g_sequence[i].name, n,
  5881. panim1->name, panim1->ikrule[n].type, panim1->ikrule[n].chain, panim1->ikrule[n].slot,
  5882. panim2->name, panim2->ikrule[n].type, panim2->ikrule[n].chain, panim2->ikrule[n].slot );
  5883. }
  5884. }
  5885. }
  5886. }
  5887. // FIXME: this doesn't check alignment!!!
  5888. for (j = 0; j < g_sequence[i].groupsize[0]; j++)
  5889. {
  5890. for (k = 0; k < g_sequence[i].groupsize[1]; k++)
  5891. {
  5892. for (int n = 0; n < g_sequence[i].panim[j][k]->numikrules; n++)
  5893. {
  5894. g_sequence[i].panim[j][k]->ikrule[n].index = n;
  5895. }
  5896. }
  5897. }
  5898. }
  5899. }
  5900. //-----------------------------------------------------------------------------
  5901. // CompressAnimations
  5902. //-----------------------------------------------------------------------------
  5903. static void CompressAnimations( )
  5904. {
  5905. int i, j, k, n, m;
  5906. // find scales for all bones
  5907. for (j = 0; j < g_numbones; j++)
  5908. {
  5909. // printf("%s : ", g_bonetable[j].name );
  5910. for (k = 0; k < 6; k++)
  5911. {
  5912. float minv, maxv, scale;
  5913. float total_minv, total_maxv;
  5914. if (k < 3)
  5915. {
  5916. minv = -128.0;
  5917. maxv = 128.0;
  5918. total_maxv = total_minv = g_bonetable[j].pos[k];
  5919. }
  5920. else
  5921. {
  5922. minv = -M_PI / 8.0;
  5923. maxv = M_PI / 8.0;
  5924. total_maxv = total_minv = g_bonetable[j].rot[k-3];
  5925. }
  5926. for (i = 0; i < g_numani; i++)
  5927. {
  5928. for (n = 0; n < g_panimation[i]->numframes; n++)
  5929. {
  5930. float v = 0.0f;
  5931. switch(k)
  5932. {
  5933. case 0:
  5934. case 1:
  5935. case 2:
  5936. if (g_panimation[i]->flags & STUDIO_DELTA)
  5937. {
  5938. v = g_panimation[i]->sanim[n][j].pos[k];
  5939. }
  5940. else
  5941. {
  5942. v = ( g_panimation[i]->sanim[n][j].pos[k] - g_bonetable[j].pos[k] );
  5943. if (g_panimation[i]->sanim[n][j].pos[k] < total_minv)
  5944. total_minv = g_panimation[i]->sanim[n][j].pos[k];
  5945. if (g_panimation[i]->sanim[n][j].pos[k] > total_maxv)
  5946. total_maxv = g_panimation[i]->sanim[n][j].pos[k];
  5947. }
  5948. break;
  5949. case 3:
  5950. case 4:
  5951. case 5:
  5952. if (g_panimation[i]->flags & STUDIO_DELTA)
  5953. {
  5954. v = g_panimation[i]->sanim[n][j].rot[k-3];
  5955. }
  5956. else
  5957. {
  5958. v = ( g_panimation[i]->sanim[n][j].rot[k-3] - g_bonetable[j].rot[k-3] );
  5959. }
  5960. while (v >= M_PI)
  5961. v -= M_PI * 2;
  5962. while (v < -M_PI)
  5963. v += M_PI * 2;
  5964. break;
  5965. }
  5966. if (v < minv)
  5967. minv = v;
  5968. if (v > maxv)
  5969. maxv = v;
  5970. }
  5971. }
  5972. if (minv < maxv)
  5973. {
  5974. if (-minv> maxv)
  5975. {
  5976. scale = minv / -32768.0;
  5977. }
  5978. else
  5979. {
  5980. scale = maxv / 32767;
  5981. }
  5982. }
  5983. else
  5984. {
  5985. scale = 1.0 / 32.0;
  5986. }
  5987. switch(k)
  5988. {
  5989. case 0:
  5990. case 1:
  5991. case 2:
  5992. g_bonetable[j].posscale[k] = scale;
  5993. g_bonetable[j].posrange[k] = total_maxv - total_minv;
  5994. break;
  5995. case 3:
  5996. case 4:
  5997. case 5:
  5998. // printf("(%.1f %.1f)", RAD2DEG(minv), RAD2DEG(maxv) );
  5999. // printf("(%.1f)", RAD2DEG(maxv-minv) );
  6000. g_bonetable[j].rotscale[k-3] = scale;
  6001. break;
  6002. }
  6003. // printf("%.0f ", 1.0 / scale );
  6004. }
  6005. // printf("\n" );
  6006. }
  6007. // reduce animations
  6008. for (i = 0; i < g_numani; i++)
  6009. {
  6010. s_animation_t *panim = g_panimation[i];
  6011. s_source_t *psource = panim->source;
  6012. if (g_bCheckLengths)
  6013. {
  6014. printf("%s\n", panim->name );
  6015. }
  6016. // setup animation interior sections
  6017. int iSectionFrames = panim->numframes;
  6018. if ( panim->numframes >= g_minSectionFrameLimit )
  6019. {
  6020. iSectionFrames = g_sectionFrames;
  6021. panim->sectionframes = g_sectionFrames;
  6022. panim->numsections = (int)(panim->numframes / panim->sectionframes) + 2;
  6023. }
  6024. else
  6025. {
  6026. panim->sectionframes = 0;
  6027. panim->numsections = 1;
  6028. }
  6029. for (int w = 0; w < panim->numsections; w++)
  6030. {
  6031. int iStartFrame = w * iSectionFrames;
  6032. int iEndFrame = (w + 1) * iSectionFrames;
  6033. iStartFrame = min( iStartFrame, panim->numframes - 1 );
  6034. iEndFrame = min( iEndFrame, panim->numframes - 1 );
  6035. // printf("%s : %d %d\n", panim->name, iStartFrame, iEndFrame );
  6036. for (j = 0; j < g_numbones; j++)
  6037. {
  6038. for (k = 0; k < 6; k++)
  6039. {
  6040. panim->anim[w][j].num[k] = 0;
  6041. panim->anim[w][j].data[k] = NULL;
  6042. }
  6043. // skip bones that are always procedural
  6044. if (g_bonetable[j].flags & BONE_ALWAYS_PROCEDURAL)
  6045. {
  6046. // panim->weight[j] = 0.0;
  6047. continue;
  6048. }
  6049. // skip bones that have no influence
  6050. if (panim->weight[j] < 0.001)
  6051. continue;
  6052. float checkmin[6], checkmax[6];
  6053. for (k = 0; k < 6; k++)
  6054. {
  6055. checkmin[k] = 9999;
  6056. checkmax[k] = -9999;
  6057. }
  6058. for (k = 0; k < 6; k++)
  6059. {
  6060. mstudioanimvalue_t *pcount, *pvalue;
  6061. float v;
  6062. short value[MAXSTUDIOANIMFRAMES];
  6063. mstudioanimvalue_t data[MAXSTUDIOANIMFRAMES];
  6064. // find deltas from default pose
  6065. for (n = 0; n <= iEndFrame - iStartFrame; n++)
  6066. {
  6067. s_bone_t *psrcdata = &panim->sanim[n+iStartFrame][j];
  6068. switch(k)
  6069. {
  6070. case 0: /* X Position */
  6071. case 1: /* Y Position */
  6072. case 2: /* Z Position */
  6073. if (panim->flags & STUDIO_DELTA)
  6074. {
  6075. value[n] = psrcdata->pos[k] / g_bonetable[j].posscale[k];
  6076. // pre-scale pos delta since format only has room for "overall" weight
  6077. float r = panim->posweight[j] / panim->weight[j];
  6078. value[n] *= r;
  6079. }
  6080. else
  6081. {
  6082. value[n] = ( psrcdata->pos[k] - g_bonetable[j].pos[k] ) / g_bonetable[j].posscale[k];
  6083. }
  6084. checkmin[k] = min( value[n] * g_bonetable[j].posscale[k], checkmin[k] );
  6085. checkmax[k] = max( value[n] * g_bonetable[j].posscale[k], checkmax[k] );
  6086. break;
  6087. case 3: /* X Rotation */
  6088. case 4: /* Y Rotation */
  6089. case 5: /* Z Rotation */
  6090. if (panim->flags & STUDIO_DELTA)
  6091. {
  6092. v = psrcdata->rot[k-3];
  6093. }
  6094. else
  6095. {
  6096. v = ( psrcdata->rot[k-3] - g_bonetable[j].rot[k-3] );
  6097. }
  6098. while (v >= M_PI)
  6099. v -= M_PI * 2;
  6100. while (v < -M_PI)
  6101. v += M_PI * 2;
  6102. checkmin[k] = min( v, checkmin[k] );
  6103. checkmax[k] = max( v, checkmax[k] );
  6104. value[n] = v / g_bonetable[j].rotscale[k-3];
  6105. break;
  6106. }
  6107. }
  6108. if (n == 0)
  6109. MdlError("no animation frames: \"%s\"\n", psource->filename );
  6110. // FIXME: this compression algorithm needs work
  6111. // initialize animation RLE block
  6112. memset( data, 0, sizeof( data ) );
  6113. pcount = data;
  6114. pvalue = pcount + 1;
  6115. pcount->num.valid = 1;
  6116. pcount->num.total = 1;
  6117. pvalue->value = value[0];
  6118. pvalue++;
  6119. // build a RLE of deltas from the default pose
  6120. for (m = 1; m < n; m++)
  6121. {
  6122. if (pcount->num.total == 255)
  6123. {
  6124. // chain too long, force a new entry
  6125. pcount = pvalue;
  6126. pvalue = pcount + 1;
  6127. pcount->num.valid++;
  6128. pvalue->value = value[m];
  6129. pvalue++;
  6130. }
  6131. // insert value if they're not equal,
  6132. // or if we're not on a run and the run is less than 3 units
  6133. else if ((value[m] != value[m-1])
  6134. || ((pcount->num.total == pcount->num.valid) && ((m < n - 1) && value[m] != value[m+1])))
  6135. {
  6136. if (pcount->num.total != pcount->num.valid)
  6137. {
  6138. //if (j == 0) printf("%d:%d ", pcount->num.valid, pcount->num.total );
  6139. pcount = pvalue;
  6140. pvalue = pcount + 1;
  6141. }
  6142. pcount->num.valid++;
  6143. pvalue->value = value[m];
  6144. pvalue++;
  6145. }
  6146. pcount->num.total++;
  6147. }
  6148. //if (j == 0) printf("%d:%d\n", pcount->num.valid, pcount->num.total );
  6149. panim->anim[w][j].num[k] = pvalue - data;
  6150. if (panim->anim[w][j].num[k] == 2 && value[0] == 0)
  6151. {
  6152. panim->anim[w][j].num[k] = 0;
  6153. }
  6154. else
  6155. {
  6156. panim->anim[w][j].data[k] = (mstudioanimvalue_t *)kalloc( pvalue - data, sizeof( mstudioanimvalue_t ) );
  6157. memmove( panim->anim[w][j].data[k], data, (pvalue - data) * sizeof( mstudioanimvalue_t ) );
  6158. }
  6159. // printf("%d(%d) ", g_source[i]->panim[q]->numanim[j][k], n );
  6160. }
  6161. if (g_bCheckLengths)
  6162. {
  6163. char *tmp[6] = { "X", "Y", "Z", "XR", "YR", "ZR" };
  6164. n = 0;
  6165. for (k = 0; k < 3; k++)
  6166. {
  6167. if (checkmin[k] != 0)
  6168. {
  6169. if (n == 0)
  6170. printf("%s :", g_bonetable[j].name );
  6171. printf("%s(%.1f: %.1f %.1f) ", tmp[k], g_bonetable[j].pos[k], checkmin[k], checkmax[k] );
  6172. n = 1;
  6173. }
  6174. }
  6175. if (n)
  6176. printf("\n");
  6177. }
  6178. }
  6179. }
  6180. if (panim->numsections == 1)
  6181. {
  6182. panim->sectionframes = 0;
  6183. }
  6184. }
  6185. }
  6186. //-----------------------------------------------------------------------------
  6187. // Compress a single animation stream
  6188. //-----------------------------------------------------------------------------
  6189. static void CompressSingle( s_animationstream_t *pStream )
  6190. {
  6191. int k, n, m;
  6192. if (pStream->numerror == 0)
  6193. return;
  6194. // printf("%s : ", g_bonetable[j].name );
  6195. for (k = 0; k < 6; k++)
  6196. {
  6197. float minv, maxv, scale;
  6198. RadianEuler ang;
  6199. if (k < 3)
  6200. {
  6201. minv = -128.0;
  6202. maxv = 128.0;
  6203. }
  6204. else
  6205. {
  6206. minv = -M_PI / 8.0;
  6207. maxv = M_PI / 8.0;
  6208. }
  6209. for (n = 0; n < pStream->numerror; n++)
  6210. {
  6211. float v = 0.0f;
  6212. switch(k)
  6213. {
  6214. case 0:
  6215. case 1:
  6216. case 2:
  6217. v = pStream->pError[n].pos[k];
  6218. break;
  6219. case 3:
  6220. case 4:
  6221. case 5:
  6222. QuaternionAngles( pStream->pError[n].q, ang );
  6223. v = ang[k-3];
  6224. while (v >= M_PI)
  6225. v -= M_PI * 2;
  6226. while (v < -M_PI)
  6227. v += M_PI * 2;
  6228. break;
  6229. }
  6230. if (v < minv)
  6231. minv = v;
  6232. if (v > maxv)
  6233. maxv = v;
  6234. }
  6235. // printf("%f %f\n", minv, maxv );
  6236. if (minv < maxv)
  6237. {
  6238. if (-minv> maxv)
  6239. {
  6240. scale = minv / -32768.0;
  6241. }
  6242. else
  6243. {
  6244. scale = maxv / 32767;
  6245. }
  6246. }
  6247. else
  6248. {
  6249. scale = 1.0 / 32.0;
  6250. }
  6251. pStream->scale[k] = scale;
  6252. mstudioanimvalue_t *pcount, *pvalue;
  6253. float v;
  6254. short value[MAXSTUDIOANIMFRAMES];
  6255. mstudioanimvalue_t data[MAXSTUDIOANIMFRAMES];
  6256. // find deltas from default pose
  6257. for (n = 0; n < pStream->numerror; n++)
  6258. {
  6259. switch(k)
  6260. {
  6261. case 0: /* X Position */
  6262. case 1: /* Y Position */
  6263. case 2: /* Z Position */
  6264. value[n] = pStream->pError[n].pos[k] / pStream->scale[k];
  6265. break;
  6266. case 3: /* X Rotation */
  6267. case 4: /* Y Rotation */
  6268. case 5: /* Z Rotation */
  6269. QuaternionAngles( pStream->pError[n].q, ang );
  6270. v = ang[k-3];
  6271. while (v >= M_PI)
  6272. v -= M_PI * 2;
  6273. while (v < -M_PI)
  6274. v += M_PI * 2;
  6275. value[n] = v / pStream->scale[k];
  6276. break;
  6277. }
  6278. }
  6279. // initialize animation RLE block
  6280. pStream->numanim[k] = 0;
  6281. memset( data, 0, sizeof( data ) );
  6282. pcount = data;
  6283. pvalue = pcount + 1;
  6284. pcount->num.valid = 1;
  6285. pcount->num.total = 1;
  6286. pvalue->value = value[0];
  6287. pvalue++;
  6288. // build a RLE of deltas from the default pose
  6289. for (m = 1; m < n; m++)
  6290. {
  6291. if (pcount->num.total == 255)
  6292. {
  6293. // chain too long, force a new entry
  6294. pcount = pvalue;
  6295. pvalue = pcount + 1;
  6296. pcount->num.valid++;
  6297. pvalue->value = value[m];
  6298. pvalue++;
  6299. }
  6300. // insert value if they're not equal,
  6301. // or if we're not on a run and the run is less than 3 units
  6302. else if ((value[m] != value[m-1])
  6303. || ((pcount->num.total == pcount->num.valid) && ((m < n - 1) && value[m] != value[m+1])))
  6304. {
  6305. if (pcount->num.total != pcount->num.valid)
  6306. {
  6307. //if (j == 0) printf("%d:%d ", pcount->num.valid, pcount->num.total );
  6308. pcount = pvalue;
  6309. pvalue = pcount + 1;
  6310. }
  6311. pcount->num.valid++;
  6312. pvalue->value = value[m];
  6313. pvalue++;
  6314. }
  6315. pcount->num.total++;
  6316. }
  6317. //if (j == 0) printf("%d:%d\n", pcount->num.valid, pcount->num.total );
  6318. pStream->numanim[k] = pvalue - data;
  6319. pStream->anim[k] = (mstudioanimvalue_t *)kalloc( pvalue - data, sizeof( mstudioanimvalue_t ) );
  6320. memmove( pStream->anim[k], data, (pvalue - data) * sizeof( mstudioanimvalue_t ) );
  6321. // printf("%d (%d) : %d\n", pRule->numanim[k], n, pRule->errorData.numerror );
  6322. }
  6323. }
  6324. //-----------------------------------------------------------------------------
  6325. // Compress all the IK data
  6326. //-----------------------------------------------------------------------------
  6327. static void CompressIKErrors( )
  6328. {
  6329. int i, j;
  6330. // find scales for all bones
  6331. for (i = 0; i < g_numani; i++)
  6332. {
  6333. for (j = 0; j < g_panimation[i]->numikrules; j++)
  6334. {
  6335. s_ikrule_t *pRule = &g_panimation[i]->ikrule[j];
  6336. if (pRule->errorData.numerror == 0)
  6337. continue;
  6338. CompressSingle( &pRule->errorData );
  6339. }
  6340. }
  6341. }
  6342. //-----------------------------------------------------------------------------
  6343. // Compress all the Local Hierarchy data
  6344. //-----------------------------------------------------------------------------
  6345. static void CompressLocalHierarchy( )
  6346. {
  6347. int i, j;
  6348. // find scales for all bones
  6349. for (i = 0; i < g_numani; i++)
  6350. {
  6351. for (j = 0; j < g_panimation[i]->numlocalhierarchy; j++)
  6352. {
  6353. s_localhierarchy_t *pRule = &g_panimation[i]->localhierarchy[j];
  6354. if (pRule->localData.numerror == 0)
  6355. continue;
  6356. CompressSingle( &pRule->localData );
  6357. }
  6358. }
  6359. }
  6360. //-----------------------------------------------------------------------------
  6361. //
  6362. //-----------------------------------------------------------------------------
  6363. struct BonePriority_s
  6364. {
  6365. int m_nGlobalBoneId;
  6366. float m_nGlobalBoneWeight;
  6367. };
  6368. //-----------------------------------------------------------------------------
  6369. // Sort by bone weight
  6370. //-----------------------------------------------------------------------------
  6371. int compareBonePriority( const void *a, const void *b )
  6372. {
  6373. return
  6374. reinterpret_cast< const BonePriority_s * >( a )->m_nGlobalBoneWeight < reinterpret_cast< const BonePriority_s * >( b )->m_nGlobalBoneWeight ? -1 :
  6375. reinterpret_cast< const BonePriority_s * >( a )->m_nGlobalBoneWeight > reinterpret_cast< const BonePriority_s * >( b )->m_nGlobalBoneWeight ? 1 : 0;
  6376. };
  6377. //-----------------------------------------------------------------------------
  6378. // Dump A $definebone line, ensuring any parents are already dumped
  6379. //-----------------------------------------------------------------------------
  6380. void DumpDefineBone( int nBoneId, bool *pBoneDumpedList )
  6381. {
  6382. Assert( nBoneId < g_numbones );
  6383. if ( pBoneDumpedList[ nBoneId ] )
  6384. return;
  6385. const s_bonetable_t &bone = g_bonetable[ nBoneId ];
  6386. // Ensure the parent bone is dumped before the child
  6387. if ( bone.parent >= 0 )
  6388. {
  6389. DumpDefineBone( bone.parent, pBoneDumpedList );
  6390. }
  6391. printf( "$definebone " );
  6392. printf( "\"%s\" ", bone.name );
  6393. if ( bone.parent != -1 )
  6394. {
  6395. printf( "\"%s\" ", g_bonetable[ bone.parent ].name );
  6396. }
  6397. else
  6398. {
  6399. printf( "\"\" " );
  6400. }
  6401. Vector pos;
  6402. QAngle angles;
  6403. pos = bone.pos;
  6404. angles.Init( RAD2DEG( bone.rot.y ), RAD2DEG( bone.rot.z ), RAD2DEG( bone.rot.x ) );
  6405. printf( "%f %f %f %f %f %f", pos.x, pos.y, pos.z, angles.x, angles.y, angles.z );
  6406. MatrixAngles( bone.srcRealign, angles, pos );
  6407. printf( " %f %f %f %f %f %f", pos.x, pos.y, pos.z, angles.x, angles.y, angles.z );
  6408. printf( "\n" );
  6409. pBoneDumpedList[ nBoneId ] = true;
  6410. }
  6411. //-----------------------------------------------------------------------------
  6412. // Dump a $definebones .qci file with the bones in an optimal order
  6413. // i.e. Bones that are removed or replaced in LODs are later in the list
  6414. // bones that are used all of the time are at the top of the list
  6415. //-----------------------------------------------------------------------------
  6416. void DumpDefineBones()
  6417. {
  6418. BonePriority_s *pBonePriorityList = reinterpret_cast< BonePriority_s * >( stackalloc( g_numbones * sizeof( BonePriority_s ) ) );
  6419. for ( int i = 0; i < g_numbones; ++i )
  6420. {
  6421. BonePriority_s &bonePriority = pBonePriorityList[ i ];
  6422. bonePriority.m_nGlobalBoneId = i;
  6423. bonePriority.m_nGlobalBoneWeight = 0.0f;
  6424. }
  6425. for ( int i = 0; i < g_ScriptLODs.Count(); ++i )
  6426. {
  6427. const LodScriptData_t &scriptLOD = g_ScriptLODs[ i ];
  6428. for ( int j = 0; j < scriptLOD.boneReplacements.Count(); ++j )
  6429. {
  6430. // Ignore Shadow LOD
  6431. if ( scriptLOD.switchValue <= 0.0f )
  6432. continue;
  6433. const int nBoneId = findGlobalBone( scriptLOD.boneReplacements[ j ].GetSrcName() );
  6434. if ( nBoneId < 0 )
  6435. {
  6436. Warning( "Can't Find BoneReplacement Bone %s\n", scriptLOD.boneReplacements[ j ].GetSrcName() );
  6437. continue;
  6438. }
  6439. pBonePriorityList[ nBoneId ].m_nGlobalBoneWeight += scriptLOD.switchValue;
  6440. }
  6441. }
  6442. // bones used by hitboxes and attachments should always go first since they're used by the server
  6443. for ( int i = 0; i < g_numbones; ++i )
  6444. {
  6445. if ( g_bonetable[i].flags & (BONE_USED_BY_HITBOX | BONE_USED_BY_ATTACHMENT | BONE_USED_BY_BONE_MERGE ))
  6446. {
  6447. pBonePriorityList[ i ].m_nGlobalBoneWeight = -1.0f;
  6448. }
  6449. }
  6450. qsort( pBonePriorityList, g_numbones, sizeof( BonePriority_s ), compareBonePriority );
  6451. bool *pBoneDumpedList = reinterpret_cast< bool * >( stackalloc( g_numbones * sizeof( bool ) ) );
  6452. memset( pBoneDumpedList, 0, g_numbones * sizeof( bool ) );
  6453. for (int i = 0; i < g_numbones; i++)
  6454. {
  6455. const BonePriority_s &bonePriority = pBonePriorityList[ i ];
  6456. const int nBoneId = bonePriority.m_nGlobalBoneId;
  6457. if (g_bonetable[ nBoneId ].flags & BONE_ALWAYS_PROCEDURAL)
  6458. {
  6459. pBoneDumpedList[ nBoneId ] = true;
  6460. continue;
  6461. }
  6462. DumpDefineBone( nBoneId, pBoneDumpedList );
  6463. }
  6464. }
  6465. void ReLinkAttachments()
  6466. {
  6467. int i;
  6468. int j;
  6469. int k;
  6470. // relink per-model attachments, eyeballs
  6471. for (i = 0; i < g_nummodelsbeforeLOD; i++)
  6472. {
  6473. s_source_t *psource = g_model[i]->source;
  6474. for (j = 0; j < g_model[i]->numattachments; j++)
  6475. {
  6476. k = findGlobalBone( g_model[i]->attachment[j].bonename );
  6477. if (k == -1)
  6478. {
  6479. MdlError("unknown model attachment link '%s'\n", g_model[i]->attachment[j].bonename );
  6480. }
  6481. g_model[i]->attachment[j].bone = j;
  6482. }
  6483. for (j = 0; j < g_model[i]->numeyeballs; j++)
  6484. {
  6485. g_model[i]->eyeball[j].bone = psource->boneLocalToGlobal[g_model[i]->eyeball[j].bone];
  6486. }
  6487. }
  6488. }
  6489. void CheckEyeballSetup()
  6490. {
  6491. for (int i = 0; i < g_nummodelsbeforeLOD; i++)
  6492. {
  6493. for (int j = 0; j < g_model[i]->numeyeballs; j++)
  6494. {
  6495. s_eyeball_t *peyeball = &g_model[i]->eyeball[j];
  6496. if (peyeball->upperlidflexdesc == -1)
  6497. {
  6498. // MdlWarning( "eyeball %s missing upperlid data\n", peyeball->name );
  6499. int dummy = Add_Flexdesc( "dummy_eyelid" );
  6500. peyeball->upperlidflexdesc = dummy;
  6501. peyeball->upperflexdesc[0] = dummy;
  6502. peyeball->uppertarget[0] = -1;
  6503. peyeball->upperflexdesc[1] = dummy;
  6504. peyeball->uppertarget[1] = 0;
  6505. peyeball->upperflexdesc[2] = dummy;
  6506. peyeball->uppertarget[2] = 1;
  6507. }
  6508. if (peyeball->lowerlidflexdesc == -1)
  6509. {
  6510. // MdlWarning( "eyeball %s missing lower data\n", peyeball->name );
  6511. int dummy = Add_Flexdesc( "dummy_eyelid" );
  6512. peyeball->lowerlidflexdesc = dummy;
  6513. peyeball->lowerflexdesc[0] = dummy;
  6514. peyeball->lowertarget[0] = -1;
  6515. peyeball->lowerflexdesc[1] = dummy;
  6516. peyeball->lowertarget[1] = 0;
  6517. peyeball->lowerflexdesc[2] = dummy;
  6518. peyeball->lowertarget[2] = 1;
  6519. }
  6520. }
  6521. }
  6522. }
  6523. void SetupHitBoxes()
  6524. {
  6525. int i;
  6526. int j;
  6527. int k;
  6528. int n;
  6529. // set hitgroups
  6530. for (k = 0; k < g_numbones; k++)
  6531. {
  6532. g_bonetable[k].group = -9999;
  6533. }
  6534. for (j = 0; j < g_numhitgroups; j++)
  6535. {
  6536. k = findGlobalBone( g_hitgroup[j].name );
  6537. if (k != -1)
  6538. {
  6539. g_bonetable[k].group = g_hitgroup[j].group;
  6540. }
  6541. else
  6542. {
  6543. MdlError( "cannot find bone %s for hitgroup %d\n", g_hitgroup[j].name, g_hitgroup[j].group );
  6544. }
  6545. }
  6546. for (k = 0; k < g_numbones; k++)
  6547. {
  6548. if (g_bonetable[k].group == -9999)
  6549. {
  6550. if (g_bonetable[k].parent != -1)
  6551. g_bonetable[k].group = g_bonetable[g_bonetable[k].parent].group;
  6552. else
  6553. g_bonetable[k].group = 0;
  6554. }
  6555. }
  6556. if ( g_hitboxsets.Size() == 0 )
  6557. {
  6558. int index = g_hitboxsets.AddToTail();
  6559. s_hitboxset *set = &g_hitboxsets[ index ];
  6560. memset( set, 0, sizeof( *set) );
  6561. strcpy( set->hitboxsetname, "default" );
  6562. gflags |= STUDIOHDR_FLAGS_AUTOGENERATED_HITBOX;
  6563. // find intersection box volume for each bone
  6564. for (k = 0; k < g_numbones; k++)
  6565. {
  6566. for (j = 0; j < 3; j++)
  6567. {
  6568. if (g_bUseBoneInBBox)
  6569. {
  6570. g_bonetable[k].bmin[j] = 0.0;
  6571. g_bonetable[k].bmax[j] = 0.0;
  6572. }
  6573. else
  6574. {
  6575. g_bonetable[k].bmin[j] = 9999.0;
  6576. g_bonetable[k].bmax[j] = -9999.0;
  6577. }
  6578. }
  6579. }
  6580. // try all the connect vertices
  6581. for (i = 0; i < g_nummodelsbeforeLOD; i++)
  6582. {
  6583. s_loddata_t *pLodData = g_model[i]->m_pLodData;
  6584. if ( !pLodData )
  6585. continue;
  6586. Vector p;
  6587. for (j = 0; j < pLodData->numvertices; j++)
  6588. {
  6589. for (n = 0; n < pLodData->vertex[j].boneweight.numbones; n++)
  6590. {
  6591. k = pLodData->vertex[j].boneweight.bone[n];
  6592. VectorITransform( pLodData->vertex[j].position, g_bonetable[k].boneToPose, p );
  6593. if (p[0] < g_bonetable[k].bmin[0]) g_bonetable[k].bmin[0] = p[0];
  6594. if (p[1] < g_bonetable[k].bmin[1]) g_bonetable[k].bmin[1] = p[1];
  6595. if (p[2] < g_bonetable[k].bmin[2]) g_bonetable[k].bmin[2] = p[2];
  6596. if (p[0] > g_bonetable[k].bmax[0]) g_bonetable[k].bmax[0] = p[0];
  6597. if (p[1] > g_bonetable[k].bmax[1]) g_bonetable[k].bmax[1] = p[1];
  6598. if (p[2] > g_bonetable[k].bmax[2]) g_bonetable[k].bmax[2] = p[2];
  6599. }
  6600. }
  6601. }
  6602. // add in all your children as well
  6603. for (k = 0; k < g_numbones; k++)
  6604. {
  6605. if ((j = g_bonetable[k].parent) != -1)
  6606. {
  6607. if (g_bonetable[k].pos[0] < g_bonetable[j].bmin[0]) g_bonetable[j].bmin[0] = g_bonetable[k].pos[0];
  6608. if (g_bonetable[k].pos[1] < g_bonetable[j].bmin[1]) g_bonetable[j].bmin[1] = g_bonetable[k].pos[1];
  6609. if (g_bonetable[k].pos[2] < g_bonetable[j].bmin[2]) g_bonetable[j].bmin[2] = g_bonetable[k].pos[2];
  6610. if (g_bonetable[k].pos[0] > g_bonetable[j].bmax[0]) g_bonetable[j].bmax[0] = g_bonetable[k].pos[0];
  6611. if (g_bonetable[k].pos[1] > g_bonetable[j].bmax[1]) g_bonetable[j].bmax[1] = g_bonetable[k].pos[1];
  6612. if (g_bonetable[k].pos[2] > g_bonetable[j].bmax[2]) g_bonetable[j].bmax[2] = g_bonetable[k].pos[2];
  6613. }
  6614. }
  6615. for (k = 0; k < g_numbones; k++)
  6616. {
  6617. if (g_bonetable[k].bmin[0] < g_bonetable[k].bmax[0] - 1
  6618. && g_bonetable[k].bmin[1] < g_bonetable[k].bmax[1] - 1
  6619. && g_bonetable[k].bmin[2] < g_bonetable[k].bmax[2] - 1)
  6620. {
  6621. set->hitbox[set->numhitboxes].bone = k;
  6622. set->hitbox[set->numhitboxes].group = g_bonetable[k].group;
  6623. VectorCopy( g_bonetable[k].bmin, set->hitbox[set->numhitboxes].bmin );
  6624. VectorCopy( g_bonetable[k].bmax, set->hitbox[set->numhitboxes].bmax );
  6625. if (dump_hboxes)
  6626. {
  6627. printf("$hbox %d \"%s\" %.2f %.2f %.2f %.2f %.2f %.2f\n",
  6628. set->hitbox[set->numhitboxes].group,
  6629. g_bonetable[set->hitbox[set->numhitboxes].bone].name,
  6630. set->hitbox[set->numhitboxes].bmin[0], set->hitbox[set->numhitboxes].bmin[1], set->hitbox[set->numhitboxes].bmin[2],
  6631. set->hitbox[set->numhitboxes].bmax[0], set->hitbox[set->numhitboxes].bmax[1], set->hitbox[set->numhitboxes].bmax[2] );
  6632. }
  6633. set->numhitboxes++;
  6634. }
  6635. }
  6636. }
  6637. else
  6638. {
  6639. gflags &= ~STUDIOHDR_FLAGS_AUTOGENERATED_HITBOX;
  6640. for (int s = 0; s < g_hitboxsets.Size(); s++ )
  6641. {
  6642. s_hitboxset *set = &g_hitboxsets[ s ];
  6643. for (j = 0; j < set->numhitboxes; j++)
  6644. {
  6645. k = findGlobalBone( set->hitbox[j].name );
  6646. if (k != -1)
  6647. {
  6648. set->hitbox[j].bone = k;
  6649. }
  6650. else
  6651. {
  6652. MdlError( "cannot find bone %s for bbox\n", set->hitbox[j].name );
  6653. }
  6654. }
  6655. }
  6656. }
  6657. for (int s = 0; s < g_hitboxsets.Size(); s++ )
  6658. {
  6659. s_hitboxset *set = &g_hitboxsets[ s ];
  6660. // flag all bones used by hitboxes
  6661. for (j = 0; j < set->numhitboxes; j++)
  6662. {
  6663. k = set->hitbox[j].bone;
  6664. while (k != -1)
  6665. {
  6666. g_bonetable[k].flags |= BONE_USED_BY_HITBOX;
  6667. k = g_bonetable[k].parent;
  6668. }
  6669. }
  6670. }
  6671. }
  6672. void SetupFullBoneRenderBounds( CUtlVector<CBoneRenderBounds> &boneRenderBounds )
  6673. {
  6674. boneRenderBounds.SetSize( g_numbones );
  6675. // First, add the ones already calculated from vertices.
  6676. for ( int i=0; i < g_numbones; i++ )
  6677. {
  6678. CBoneRenderBounds *pOut = &boneRenderBounds[i];
  6679. pOut->m_Mins = g_bonetable[i].bmin;
  6680. pOut->m_Maxs = g_bonetable[i].bmax;
  6681. }
  6682. // Note: shared animation files will need to include the hitboxes or else their sequence
  6683. // boxes won't use this stuff.
  6684. // Now add hitboxes.
  6685. for ( int i=0; i < g_hitboxsets.Count(); i++ )
  6686. {
  6687. const s_hitboxset *pSet = &g_hitboxsets[i];
  6688. for ( int k=0; k < pSet->numhitboxes; k++ )
  6689. {
  6690. const s_bbox_t *pIn = &pSet->hitbox[k];
  6691. if ( pIn->bone >= 0 )
  6692. {
  6693. CBoneRenderBounds *pOut = &boneRenderBounds[pIn->bone];
  6694. VectorMin( pIn->bmin, pOut->m_Mins, pOut->m_Mins );
  6695. VectorMax( pIn->bmax, pOut->m_Maxs, pOut->m_Maxs );
  6696. }
  6697. }
  6698. }
  6699. }
  6700. void CalcSequenceBoundingBoxes()
  6701. {
  6702. int i;
  6703. int j;
  6704. int k;
  6705. int n;
  6706. int m;
  6707. CUtlVector<CBoneRenderBounds> boneRenderBounds;
  6708. SetupFullBoneRenderBounds( boneRenderBounds );
  6709. // find bounding box for each g_sequence
  6710. for (i = 0; i < g_numani; i++)
  6711. {
  6712. Vector bmin, bmax;
  6713. // find intersection box volume for each bone
  6714. for (j = 0; j < 3; j++)
  6715. {
  6716. bmin[j] = 9999.0;
  6717. bmax[j] = -9999.0;
  6718. }
  6719. for (j = 0; j < g_panimation[i]->numframes; j++)
  6720. {
  6721. matrix3x4_t bonetransform[MAXSTUDIOBONES]; // bone transformation matrix
  6722. matrix3x4_t posetransform[MAXSTUDIOBONES]; // bone transformation matrix
  6723. matrix3x4_t bonematrix; // local transformation matrix
  6724. Vector pos;
  6725. CalcBoneTransforms( g_panimation[i], j, bonetransform );
  6726. for (k = 0; k < g_numbones; k++)
  6727. {
  6728. MatrixInvert( g_bonetable[k].boneToPose, bonematrix );
  6729. ConcatTransforms (bonetransform[k], bonematrix, posetransform[k]);
  6730. }
  6731. // include hitboxes as well.
  6732. for (k = 0; k < g_numbones; k++)
  6733. {
  6734. Vector tmpMin, tmpMax;
  6735. TransformAABB( bonetransform[k], boneRenderBounds[k].m_Mins, boneRenderBounds[k].m_Maxs, tmpMin, tmpMax );
  6736. VectorMin( tmpMin, bmin, bmin );
  6737. VectorMax( tmpMax, bmax, bmax );
  6738. }
  6739. // include vertices
  6740. for (k = 0; k < g_nummodelsbeforeLOD; k++)
  6741. {
  6742. s_loddata_t *pLodData = g_model[k]->m_pLodData;
  6743. // skip blank empty model
  6744. if ( !pLodData )
  6745. continue;
  6746. for (n = 0; n < pLodData->numvertices; n++)
  6747. {
  6748. Vector tmp;
  6749. pos = Vector( 0, 0, 0 );
  6750. for (m = 0; m < pLodData->vertex[n].boneweight.numbones; m++)
  6751. {
  6752. VectorTransform( pLodData->vertex[n].position, posetransform[pLodData->vertex[n].boneweight.bone[m]], tmp ); // bug: should use all bones!
  6753. VectorMA( pos, pLodData->vertex[n].boneweight.weight[m], tmp, pos );
  6754. }
  6755. VectorMin( pos, bmin, bmin );
  6756. VectorMax( pos, bmax, bmax );
  6757. }
  6758. }
  6759. }
  6760. if (bmin.x < g_vecMinWorldspace.x || bmin.y < g_vecMinWorldspace.y || bmin.z < g_vecMinWorldspace.z || bmax.x > g_vecMaxWorldspace.x || bmax.y > g_vecMaxWorldspace.y || bmax.z > g_vecMaxWorldspace.z)
  6761. {
  6762. MdlWarning("%s : bounding box out of range : %.0f %.0f %.0f : %.0f %.0f %.0f\n",
  6763. g_panimation[i]->name,
  6764. bmin.x, bmin.y, bmin.z, bmax.z, bmax.y, bmax.z );
  6765. VectorMax( bmin, g_vecMinWorldspace, bmin );
  6766. VectorMin( bmax, g_vecMaxWorldspace, bmax );
  6767. }
  6768. VectorCopy( bmin, g_panimation[i]->bmin );
  6769. VectorCopy( bmax, g_panimation[i]->bmax );
  6770. /*
  6771. printf("%s : %.0f %.0f %.0f %.0f %.0f %.0f\n",
  6772. g_panimation[i]->name, bmin[0], bmax[0], bmin[1], bmax[1], bmin[2], bmax[2] );
  6773. */
  6774. // printf("%s %.2f\n", g_sequence[i].name, g_sequence[i].panim[0]->pos[9][0][0] / g_bonetable[9].pos[0] );
  6775. }
  6776. for (i = 0; i < g_sequence.Count(); i++)
  6777. {
  6778. Vector bmin, bmax;
  6779. // find intersection box volume for each bone
  6780. for (j = 0; j < 3; j++)
  6781. {
  6782. bmin[j] = 9999.0;
  6783. bmax[j] = -9999.0;
  6784. }
  6785. for (j = 0; j < g_sequence[i].groupsize[0]; j++)
  6786. {
  6787. for (k = 0; k < g_sequence[i].groupsize[1]; k++)
  6788. {
  6789. s_animation_t *panim = g_sequence[i].panim[j][k];
  6790. if (panim->bmin[0] < bmin[0]) bmin[0] = panim->bmin[0];
  6791. if (panim->bmin[1] < bmin[1]) bmin[1] = panim->bmin[1];
  6792. if (panim->bmin[2] < bmin[2]) bmin[2] = panim->bmin[2];
  6793. if (panim->bmax[0] > bmax[0]) bmax[0] = panim->bmax[0];
  6794. if (panim->bmax[1] > bmax[1]) bmax[1] = panim->bmax[1];
  6795. if (panim->bmax[2] > bmax[2]) bmax[2] = panim->bmax[2];
  6796. }
  6797. }
  6798. VectorCopy( bmin, g_sequence[i].bmin );
  6799. VectorCopy( bmax, g_sequence[i].bmax );
  6800. }
  6801. }
  6802. void SetIlluminationPosition()
  6803. {
  6804. // find center of domain
  6805. if (!illumpositionset)
  6806. {
  6807. // Only use the 0th sequence; that should be the idle sequence
  6808. VectorFill( illumposition, 0 );
  6809. if (g_sequence.Count() != 0)
  6810. {
  6811. VectorAdd( g_sequence[0].bmin, g_sequence[0].bmax, illumposition );
  6812. illumposition *= 0.5f;
  6813. }
  6814. illumpositionset = true;
  6815. }
  6816. }
  6817. void SimplifyModel()
  6818. {
  6819. if (g_sequence.Count() == 0 && g_numincludemodels == 0)
  6820. {
  6821. MdlError( "model has no sequences\n");
  6822. }
  6823. // have to load the lod sources before remapping bones so that the remap
  6824. // happens for all LODs.
  6825. LoadLODSources();
  6826. RemapBones();
  6827. LinkIKChains();
  6828. LinkIKLocks();
  6829. RealignBones();
  6830. ConvertBoneTreeCollapsesToReplaceBones();
  6831. // export bones
  6832. if (g_definebones)
  6833. {
  6834. DumpDefineBones();
  6835. exit( 0 );
  6836. }
  6837. // translate:
  6838. // replacebone "bone0" "bone1"
  6839. // replacebone "bone1" "bone2"
  6840. // replacebone "bone2" "bone3"
  6841. // to:
  6842. // replacebone "bone0" "bone3"
  6843. // replacebone "bone1" "bone3"
  6844. // replacebone "bone2" "bone3"
  6845. FixupReplacedBones();
  6846. RemapVerticesToGlobalBones();
  6847. if (g_bCenterBonesOnVerts)
  6848. {
  6849. CenterBonesOnVerts();
  6850. }
  6851. // remap lods to root, building aggregate final pools
  6852. // mark bones used by an lod
  6853. UnifyLODs();
  6854. if ( g_bPrintBones )
  6855. {
  6856. printf( "Hardware bone usage:\n" );
  6857. }
  6858. SpewBoneUsageStats();
  6859. MarkParentBoneLODs();
  6860. if ( g_bPrintBones )
  6861. {
  6862. printf( "CPU bone usage:\n" );
  6863. }
  6864. SpewBoneUsageStats();
  6865. RemapAnimations();
  6866. processAnimations();
  6867. limitBoneRotations();
  6868. limitIKChainLength();
  6869. RemapProceduralBones();
  6870. MakeTransitions();
  6871. RemapVertexAnimations();
  6872. RemapVertexAnimationsNewVersion();
  6873. FindAutolayers();
  6874. // link bonecontrollers
  6875. LinkBoneControllers();
  6876. // link screen aligned bones
  6877. TagScreenAlignedBones();
  6878. // link attachments
  6879. LinkAttachments();
  6880. // link mouths
  6881. LinkMouths();
  6882. // procedural bone needs to propogate its bone usage up its chain
  6883. // ensures runtime sets up dependent bone hierarchy
  6884. MarkProceduralBoneChain();
  6885. LockBoneLengths();
  6886. ProcessIKRules();
  6887. CompressIKErrors( );
  6888. CompressLocalHierarchy( );
  6889. CalcPoseParameters();
  6890. ReLinkAttachments();
  6891. CheckEyeballSetup();
  6892. SetupHitBoxes();
  6893. CompressAnimations( );
  6894. CalcSequenceBoundingBoxes();
  6895. SetIlluminationPosition();
  6896. if ( g_bBuildPreview )
  6897. {
  6898. gflags |= STUDIOHDR_FLAGS_BUILT_IN_PREVIEW_MODE;
  6899. }
  6900. }