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.

3272 lines
85 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <sys/stat.h>
  5. #include <math.h>
  6. #include "filesystem_tools.h"
  7. #include "cmdlib.h"
  8. #include "scriplib.h"
  9. #include "mathlib/mathlib.h"
  10. #define EXTERN
  11. #include "studio.h"
  12. #include "motionmapper.h"
  13. #include "tier1/strtools.h"
  14. #include "tier0/icommandline.h"
  15. #include "utldict.h"
  16. #include <windows.h>
  17. #include "UtlBuffer.h"
  18. #include "utlsymbol.h"
  19. bool g_quiet = false;
  20. bool g_verbose = false;
  21. char g_outfile[1024];
  22. bool uselogfile = false;
  23. char g_szFilename[1024];
  24. FILE *g_fpInput;
  25. char g_szLine[4096];
  26. int g_iLinecount;
  27. bool g_bZBrush = false;
  28. bool g_bGaveMissingBoneWarning = false;
  29. //-----------------------------------------------------------------------------
  30. // Purpose:
  31. // Input : depth -
  32. // *fmt -
  33. // ... -
  34. //-----------------------------------------------------------------------------
  35. void vprint( int depth, const char *fmt, ... )
  36. {
  37. char string[ 8192 ];
  38. va_list va;
  39. va_start( va, fmt );
  40. V_vsprintf_safe( string, fmt, va );
  41. va_end( va );
  42. FILE *fp = NULL;
  43. if ( uselogfile )
  44. {
  45. fp = fopen( "log.txt", "ab" );
  46. }
  47. while ( depth-- > 0 )
  48. {
  49. vprint( 0, " " );
  50. OutputDebugString( " " );
  51. if ( fp )
  52. {
  53. fprintf( fp, " " );
  54. }
  55. }
  56. ::printf( "%s", string );
  57. OutputDebugString( string );
  58. if ( fp )
  59. {
  60. char *p = string;
  61. while ( *p )
  62. {
  63. if ( *p == '\n' )
  64. {
  65. fputc( '\r', fp );
  66. }
  67. fputc( *p, fp );
  68. p++;
  69. }
  70. fclose( fp );
  71. }
  72. }
  73. int k_memtotal;
  74. void *kalloc( int num, int size )
  75. {
  76. // vprint( 0, "calloc( %d, %d )\n", num, size );
  77. // vprint( 0, "%d ", num * size );
  78. k_memtotal += num * size;
  79. return calloc( num, size );
  80. }
  81. void kmemset( void *ptr, int value, int size )
  82. {
  83. // vprint( 0, "kmemset( %x, %d, %d )\n", ptr, value, size );
  84. memset( ptr, value, size );
  85. return;
  86. }
  87. static bool g_bFirstWarning = true;
  88. void MdlWarning( const char *fmt, ... )
  89. {
  90. va_list args;
  91. static char output[1024];
  92. if (g_quiet)
  93. {
  94. if (g_bFirstWarning)
  95. {
  96. vprint( 0, "%s :\n", fullpath );
  97. g_bFirstWarning = false;
  98. }
  99. vprint( 0, "\t");
  100. }
  101. vprint( 0, "WARNING: ");
  102. va_start( args, fmt );
  103. vprint( 0, fmt, args );
  104. }
  105. void MdlError( char const *fmt, ... )
  106. {
  107. va_list args;
  108. if (g_quiet)
  109. {
  110. if (g_bFirstWarning)
  111. {
  112. vprint( 0, "%s :\n", fullpath );
  113. g_bFirstWarning = false;
  114. }
  115. vprint( 0, "\t");
  116. }
  117. vprint( 0, "ERROR: ");
  118. va_start( args, fmt );
  119. vprint( 0, fmt, args );
  120. exit( -1 );
  121. }
  122. int OpenGlobalFile( char *src )
  123. {
  124. int time1;
  125. char filename[1024];
  126. // local copy of string
  127. strcpy( filename, ExpandPath( src ) );
  128. // Ummm, path sanity checking
  129. int pathLength;
  130. int numBasePaths = CmdLib_GetNumBasePaths();
  131. // This is kinda gross. . . doing the same work in cmdlib on SafeOpenRead.
  132. if( CmdLib_HasBasePath( filename, pathLength ) )
  133. {
  134. char tmp[1024];
  135. int i;
  136. for( i = 0; i < numBasePaths; i++ )
  137. {
  138. strcpy( tmp, CmdLib_GetBasePath( i ) );
  139. strcat( tmp, filename + pathLength );
  140. time1 = FileTime( tmp );
  141. if( time1 != -1 )
  142. {
  143. if ((g_fpInput = fopen(tmp, "r")) == 0)
  144. {
  145. MdlWarning( "reader: could not open file '%s'\n", src );
  146. return 0;
  147. }
  148. else
  149. {
  150. return 1;
  151. }
  152. }
  153. }
  154. return 0;
  155. }
  156. else
  157. {
  158. time1 = FileTime (filename);
  159. if (time1 == -1)
  160. return 0;
  161. // Whoohooo, FOPEN!
  162. if ((g_fpInput = fopen(filename, "r")) == 0)
  163. {
  164. MdlWarning( "reader: could not open file '%s'\n", src );
  165. return 0;
  166. }
  167. return 1;
  168. }
  169. }
  170. bool IsEnd( char const* pLine )
  171. {
  172. if (strncmp( "end", pLine, 3 ) != 0)
  173. return false;
  174. return (pLine[3] == '\0') || (pLine[3] == '\n');
  175. }
  176. //Wrong name for the use of it.
  177. void scale_vertex( Vector &org )
  178. {
  179. org[0] = org[0] * g_currentscale;
  180. org[1] = org[1] * g_currentscale;
  181. org[2] = org[2] * g_currentscale;
  182. }
  183. void clip_rotations( RadianEuler& rot )
  184. {
  185. int j;
  186. // clip everything to : -M_PI <= x < M_PI
  187. for (j = 0; j < 3; j++) {
  188. while (rot[j] >= M_PI)
  189. rot[j] -= M_PI*2;
  190. while (rot[j] < -M_PI)
  191. rot[j] += M_PI*2;
  192. }
  193. }
  194. void clip_rotations( Vector& rot )
  195. {
  196. int j;
  197. // clip everything to : -180 <= x < 180
  198. for (j = 0; j < 3; j++) {
  199. while (rot[j] >= 180)
  200. rot[j] -= 180*2;
  201. while (rot[j] < -180)
  202. rot[j] += 180*2;
  203. }
  204. }
  205. void Build_Reference( s_source_t *psource)
  206. {
  207. int i, parent;
  208. Vector angle;
  209. for (i = 0; i < psource->numbones; i++)
  210. {
  211. matrix3x4_t m;
  212. AngleMatrix( psource->rawanim[0][i].rot, m );
  213. m[0][3] = psource->rawanim[0][i].pos[0];
  214. m[1][3] = psource->rawanim[0][i].pos[1];
  215. m[2][3] = psource->rawanim[0][i].pos[2];
  216. parent = psource->localBone[i].parent;
  217. if (parent == -1)
  218. {
  219. // scale the done pos.
  220. // calc rotational matrices
  221. MatrixCopy( m, psource->boneToPose[i] );
  222. }
  223. else
  224. {
  225. // calc compound rotational matrices
  226. // FIXME : Hey, it's orthogical so inv(A) == transpose(A)
  227. ConcatTransforms( psource->boneToPose[parent], m, psource->boneToPose[i] );
  228. }
  229. // vprint( 0, "%3d %f %f %f\n", i, psource->bonefixup[i].worldorg[0], psource->bonefixup[i].worldorg[1], psource->bonefixup[i].worldorg[2] );
  230. /*
  231. AngleMatrix( angle, m );
  232. vprint( 0, "%8.4f %8.4f %8.4f\n", m[0][0], m[1][0], m[2][0] );
  233. vprint( 0, "%8.4f %8.4f %8.4f\n", m[0][1], m[1][1], m[2][1] );
  234. vprint( 0, "%8.4f %8.4f %8.4f\n", m[0][2], m[1][2], m[2][2] );
  235. */
  236. }
  237. }
  238. int Grab_Nodes( s_node_t *pnodes )
  239. {
  240. //
  241. // s_node_t structure: index is index!!
  242. //
  243. int index;
  244. char name[1024];
  245. int parent;
  246. int numbones = 0;
  247. // Init parent to none
  248. for (index = 0; index < MAXSTUDIOSRCBONES; index++)
  249. {
  250. pnodes[index].parent = -1;
  251. }
  252. // March through nodes lines
  253. while (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
  254. {
  255. g_iLinecount++;
  256. // get tokens
  257. if (sscanf( g_szLine, "%d \"%[^\"]\" %d", &index, name, &parent ) == 3)
  258. {
  259. // check for duplicated bones
  260. /*
  261. if (strlen(pnodes[index].name) != 0)
  262. {
  263. MdlError( "bone \"%s\" exists more than once\n", name );
  264. }
  265. */
  266. // copy name to struct array
  267. V_strcpy_safe( pnodes[index].name, name );
  268. // set parent into struct array
  269. pnodes[index].parent = parent;
  270. // increment numbones
  271. if (index > numbones)
  272. {
  273. numbones = index;
  274. }
  275. }
  276. else
  277. {
  278. return numbones + 1;
  279. }
  280. }
  281. MdlError( "Unexpected EOF at line %d\n", g_iLinecount );
  282. return 0;
  283. }
  284. void Grab_Vertexanimation( s_source_t *psource )
  285. {
  286. char cmd[1024];
  287. int index;
  288. Vector pos;
  289. Vector normal;
  290. int t = -1;
  291. int count = 0;
  292. static s_vertanim_t tmpvanim[MAXSTUDIOVERTS*4];
  293. while (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
  294. {
  295. g_iLinecount++;
  296. if (sscanf( g_szLine, "%d %f %f %f %f %f %f", &index, &pos[0], &pos[1], &pos[2], &normal[0], &normal[1], &normal[2] ) == 7)
  297. {
  298. if (psource->startframe < 0)
  299. {
  300. MdlError( "Missing frame start(%d) : %s", g_iLinecount, g_szLine );
  301. }
  302. if (t < 0)
  303. {
  304. MdlError( "VTA Frame Sync (%d) : %s", g_iLinecount, g_szLine );
  305. }
  306. tmpvanim[count].vertex = index;
  307. VectorCopy( pos, tmpvanim[count].pos );
  308. VectorCopy( normal, tmpvanim[count].normal );
  309. count++;
  310. if (index >= psource->numvertices)
  311. psource->numvertices = index + 1;
  312. }
  313. else
  314. {
  315. // flush data
  316. if (count)
  317. {
  318. psource->numvanims[t] = count;
  319. psource->vanim[t] = (s_vertanim_t *)kalloc( count, sizeof( s_vertanim_t ) );
  320. memcpy( psource->vanim[t], tmpvanim, count * sizeof( s_vertanim_t ) );
  321. }
  322. else if (t > 0)
  323. {
  324. psource->numvanims[t] = 0;
  325. }
  326. // next command
  327. if (sscanf( g_szLine, "%1023s %d", cmd, &index ))
  328. {
  329. if (strcmp( cmd, "time" ) == 0)
  330. {
  331. t = index;
  332. count = 0;
  333. if (t < psource->startframe)
  334. {
  335. MdlError( "Frame MdlError(%d) : %s", g_iLinecount, g_szLine );
  336. }
  337. if (t > psource->endframe)
  338. {
  339. MdlError( "Frame MdlError(%d) : %s", g_iLinecount, g_szLine );
  340. }
  341. t -= psource->startframe;
  342. }
  343. else if (strcmp( cmd, "end") == 0)
  344. {
  345. psource->numframes = psource->endframe - psource->startframe + 1;
  346. return;
  347. }
  348. else
  349. {
  350. MdlError( "MdlError(%d) : %s", g_iLinecount, g_szLine );
  351. }
  352. }
  353. else
  354. {
  355. MdlError( "MdlError(%d) : %s", g_iLinecount, g_szLine );
  356. }
  357. }
  358. }
  359. MdlError( "unexpected EOF: %s\n", psource->filename );
  360. }
  361. void Grab_Animation( s_source_t *psource )
  362. {
  363. Vector pos;
  364. RadianEuler rot;
  365. char cmd[1024];
  366. int index;
  367. int t = -99999999;
  368. int size;
  369. // Init startframe
  370. psource->startframe = -1;
  371. // size per frame
  372. size = psource->numbones * sizeof( s_bone_t );
  373. // march through animation
  374. while (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
  375. {
  376. // linecount
  377. g_iLinecount++;
  378. // split if big enoough
  379. if (sscanf( g_szLine, "%d %f %f %f %f %f %f", &index, &pos[0], &pos[1], &pos[2], &rot[0], &rot[1], &rot[2] ) == 7)
  380. {
  381. // startframe is sanity check for having determined time
  382. if (psource->startframe < 0)
  383. {
  384. MdlError( "Missing frame start(%d) : %s", g_iLinecount, g_szLine );
  385. }
  386. // scale if pertinent
  387. scale_vertex( pos );
  388. VectorCopy( pos, psource->rawanim[t][index].pos );
  389. VectorCopy( rot, psource->rawanim[t][index].rot );
  390. clip_rotations( rot ); // !!!
  391. }
  392. else if (sscanf( g_szLine, "%1023s %d", cmd, &index ))
  393. {
  394. // get time
  395. if (strcmp( cmd, "time" ) == 0)
  396. {
  397. // again time IS an index
  398. t = index;
  399. if (psource->startframe == -1)
  400. {
  401. psource->startframe = t;
  402. }
  403. // sanity check time (little funny logic here, see previous IF)
  404. if (t < psource->startframe)
  405. {
  406. MdlError( "Frame MdlError(%d) : %s", g_iLinecount, g_szLine );
  407. }
  408. // bump up endframe?
  409. if (t > psource->endframe)
  410. {
  411. psource->endframe = t;
  412. }
  413. // make t into pure index
  414. t -= psource->startframe;
  415. // check for memory allocation
  416. if (psource->rawanim[t] == NULL)
  417. {
  418. // Allocate 1 frame of full bonecount
  419. psource->rawanim[t] = (s_bone_t *)kalloc( 1, size );
  420. // duplicate previous frames keys?? preventative sanity?
  421. if (t > 0 && psource->rawanim[t-1])
  422. {
  423. for (int j = 0; j < psource->numbones; j++)
  424. {
  425. VectorCopy( psource->rawanim[t-1][j].pos, psource->rawanim[t][j].pos );
  426. VectorCopy( psource->rawanim[t-1][j].rot, psource->rawanim[t][j].rot );
  427. }
  428. }
  429. }
  430. else
  431. {
  432. // MdlError( "%s has duplicated frame %d\n", psource->filename, t );
  433. }
  434. }
  435. else if (strcmp( cmd, "end") == 0)
  436. {
  437. psource->numframes = psource->endframe - psource->startframe + 1;
  438. for (t = 0; t < psource->numframes; t++)
  439. {
  440. if (psource->rawanim[t] == NULL)
  441. {
  442. MdlError( "%s is missing frame %d\n", psource->filename, t + psource->startframe );
  443. }
  444. }
  445. Build_Reference( psource );
  446. return;
  447. }
  448. else
  449. {
  450. MdlError( "MdlError(%d) : %s", g_iLinecount, g_szLine );
  451. }
  452. }
  453. else
  454. {
  455. MdlError( "MdlError(%d) : %s", g_iLinecount, g_szLine );
  456. }
  457. }
  458. MdlError( "unexpected EOF: %s\n", psource->filename );
  459. }
  460. int lookup_index( s_source_t *psource, int material, Vector& vertex, Vector& normal, Vector2D texcoord )
  461. {
  462. int i;
  463. for (i = 0; i < numvlist; i++)
  464. {
  465. if (v_listdata[i].m == material
  466. && DotProduct( g_normal[i], normal ) > normal_blend
  467. && VectorCompare( g_vertex[i], vertex )
  468. && g_texcoord[i][0] == texcoord[0]
  469. && g_texcoord[i][1] == texcoord[1])
  470. {
  471. v_listdata[i].lastref = numvlist;
  472. return i;
  473. }
  474. }
  475. if (i >= MAXSTUDIOVERTS) {
  476. MdlError( "too many indices in source: \"%s\"\n", psource->filename);
  477. }
  478. VectorCopy( vertex, g_vertex[i] );
  479. VectorCopy( normal, g_normal[i] );
  480. Vector2Copy( texcoord, g_texcoord[i] );
  481. v_listdata[i].v = i;
  482. v_listdata[i].m = material;
  483. v_listdata[i].n = i;
  484. v_listdata[i].t = i;
  485. v_listdata[i].firstref = numvlist;
  486. v_listdata[i].lastref = numvlist;
  487. numvlist = i + 1;
  488. return i;
  489. }
  490. void ParseFaceData( s_source_t *psource, int material, s_face_t *pFace )
  491. {
  492. int index[3];
  493. int i, j;
  494. Vector p;
  495. Vector normal;
  496. Vector2D t;
  497. int iCount, bones[MAXSTUDIOSRCBONES];
  498. float weights[MAXSTUDIOSRCBONES];
  499. int bone;
  500. for (j = 0; j < 3; j++)
  501. {
  502. memset( g_szLine, 0, sizeof( g_szLine ) );
  503. if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) == NULL)
  504. {
  505. MdlError("%s: error on g_szLine %d: %s", g_szFilename, g_iLinecount, g_szLine );
  506. }
  507. iCount = 0;
  508. g_iLinecount++;
  509. i = sscanf( g_szLine, "%d %f %f %f %f %f %f %f %f %d %d %f %d %f %d %f %d %f",
  510. &bone,
  511. &p[0], &p[1], &p[2],
  512. &normal[0], &normal[1], &normal[2],
  513. &t[0], &t[1],
  514. &iCount,
  515. &bones[0], &weights[0], &bones[1], &weights[1], &bones[2], &weights[2], &bones[3], &weights[3] );
  516. if (i < 9)
  517. continue;
  518. if (bone < 0 || bone >= psource->numbones)
  519. {
  520. MdlError("bogus bone index\n%d %s :\n%s", g_iLinecount, g_szFilename, g_szLine );
  521. }
  522. //Scale face pos
  523. scale_vertex( p );
  524. // continue parsing more bones.
  525. // FIXME: don't we have a built in parser that'll do this?
  526. if (iCount > 4)
  527. {
  528. int k;
  529. int ctr = 0;
  530. char *token;
  531. for (k = 0; k < 18; k++)
  532. {
  533. while (g_szLine[ctr] == ' ')
  534. {
  535. ctr++;
  536. }
  537. token = strtok( &g_szLine[ctr], " " );
  538. ctr += strlen( token ) + 1;
  539. }
  540. for (k = 4; k < iCount && k < MAXSTUDIOSRCBONES; k++)
  541. {
  542. while (g_szLine[ctr] == ' ')
  543. {
  544. ctr++;
  545. }
  546. token = strtok( &g_szLine[ctr], " " );
  547. ctr += strlen( token ) + 1;
  548. bones[k] = atoi(token);
  549. token = strtok( &g_szLine[ctr], " " );
  550. ctr += strlen( token ) + 1;
  551. weights[k] = atof(token);
  552. }
  553. // vprint( 0, "%d ", iCount );
  554. //vprint( 0, "\n");
  555. //exit(1);
  556. }
  557. // adjust_vertex( p );
  558. // scale_vertex( p );
  559. // move vertex position to object space.
  560. // VectorSubtract( p, psource->bonefixup[bone].worldorg, tmp );
  561. // VectorTransform(tmp, psource->bonefixup[bone].im, p );
  562. // move normal to object space.
  563. // VectorCopy( normal, tmp );
  564. // VectorTransform(tmp, psource->bonefixup[bone].im, normal );
  565. // VectorNormalize( normal );
  566. // invert v
  567. t[1] = 1.0 - t[1];
  568. index[j] = lookup_index( psource, material, p, normal, t );
  569. if (i == 9 || iCount == 0)
  570. {
  571. g_bone[index[j]].numbones = 1;
  572. g_bone[index[j]].bone[0] = bone;
  573. g_bone[index[j]].weight[0] = 1.0;
  574. }
  575. else
  576. {
  577. iCount = SortAndBalanceBones( iCount, MAXSTUDIOBONEWEIGHTS, bones, weights );
  578. g_bone[index[j]].numbones = iCount;
  579. for (i = 0; i < iCount; i++)
  580. {
  581. g_bone[index[j]].bone[i] = bones[i];
  582. g_bone[index[j]].weight[i] = weights[i];
  583. }
  584. }
  585. }
  586. // pFace->material = material; // BUG
  587. pFace->a = index[0];
  588. pFace->b = index[1];
  589. pFace->c = index[2];
  590. Assert( ((pFace->a & 0xF0000000) == 0) && ((pFace->b & 0xF0000000) == 0) &&
  591. ((pFace->c & 0xF0000000) == 0) );
  592. if (flip_triangles)
  593. {
  594. j = pFace->b; pFace->b = pFace->c; pFace->c = j;
  595. }
  596. }
  597. int use_texture_as_material( int textureindex )
  598. {
  599. if (g_texture[textureindex].material == -1)
  600. {
  601. // vprint( 0, "%d %d %s\n", textureindex, g_nummaterials, g_texture[textureindex].name );
  602. g_material[g_nummaterials] = textureindex;
  603. g_texture[textureindex].material = g_nummaterials++;
  604. }
  605. return g_texture[textureindex].material;
  606. }
  607. int material_to_texture( int material )
  608. {
  609. int i;
  610. for (i = 0; i < g_numtextures; i++)
  611. {
  612. if (g_texture[i].material == material)
  613. {
  614. return i;
  615. }
  616. }
  617. return -1;
  618. }
  619. int lookup_texture( char *texturename, int maxlen )
  620. {
  621. int i;
  622. Q_StripExtension( texturename, texturename, maxlen );
  623. for (i = 0; i < g_numtextures; i++)
  624. {
  625. if (stricmp( g_texture[i].name, texturename ) == 0)
  626. {
  627. return i;
  628. }
  629. }
  630. if (i >= MAXSTUDIOSKINS)
  631. MdlError("Too many materials used, max %d\n", ( int )MAXSTUDIOSKINS );
  632. // vprint( 0, "texture %d = %s\n", i, texturename );
  633. V_strcpy_safe( g_texture[i].name, texturename );
  634. g_texture[i].material = -1;
  635. /*
  636. if (stristr( texturename, "chrome" ) != NULL) {
  637. texture[i].flags = STUDIO_NF_FLATSHADE | STUDIO_NF_CHROME;
  638. }
  639. else {
  640. texture[i].flags = 0;
  641. }
  642. */
  643. g_numtextures++;
  644. return i;
  645. }
  646. int SortAndBalanceBones( int iCount, int iMaxCount, int bones[], float weights[] )
  647. {
  648. int i;
  649. // collapse duplicate bone weights
  650. for (i = 0; i < iCount-1; i++)
  651. {
  652. int j;
  653. for (j = i + 1; j < iCount; j++)
  654. {
  655. if (bones[i] == bones[j])
  656. {
  657. weights[i] += weights[j];
  658. weights[j] = 0.0;
  659. }
  660. }
  661. }
  662. // do sleazy bubble sort
  663. int bShouldSort;
  664. do {
  665. bShouldSort = false;
  666. for (i = 0; i < iCount-1; i++)
  667. {
  668. if (weights[i+1] > weights[i])
  669. {
  670. int j = bones[i+1]; bones[i+1] = bones[i]; bones[i] = j;
  671. float w = weights[i+1]; weights[i+1] = weights[i]; weights[i] = w;
  672. bShouldSort = true;
  673. }
  674. }
  675. } while (bShouldSort);
  676. // throw away all weights less than 1/20th
  677. while (iCount > 1 && weights[iCount-1] < 0.05)
  678. {
  679. iCount--;
  680. }
  681. // clip to the top iMaxCount bones
  682. if (iCount > iMaxCount)
  683. {
  684. iCount = iMaxCount;
  685. }
  686. float t = 0;
  687. for (i = 0; i < iCount; i++)
  688. {
  689. t += weights[i];
  690. }
  691. if (t <= 0.0)
  692. {
  693. // missing weights?, go ahead and evenly share?
  694. // FIXME: shouldn't this error out?
  695. t = 1.0 / iCount;
  696. for (i = 0; i < iCount; i++)
  697. {
  698. weights[i] = t;
  699. }
  700. }
  701. else
  702. {
  703. // scale to sum to 1.0
  704. t = 1.0 / t;
  705. for (i = 0; i < iCount; i++)
  706. {
  707. weights[i] = weights[i] * t;
  708. }
  709. }
  710. return iCount;
  711. }
  712. int vlistCompare( const void *elem1, const void *elem2 )
  713. {
  714. v_unify_t *u1 = &v_listdata[*(int *)elem1];
  715. v_unify_t *u2 = &v_listdata[*(int *)elem2];
  716. // sort by material
  717. if (u1->m < u2->m)
  718. return -1;
  719. if (u1->m > u2->m)
  720. return 1;
  721. // sort by last used
  722. if (u1->lastref < u2->lastref)
  723. return -1;
  724. if (u1->lastref > u2->lastref)
  725. return 1;
  726. return 0;
  727. }
  728. int faceCompare( const void *elem1, const void *elem2 )
  729. {
  730. int i1 = *(int *)elem1;
  731. int i2 = *(int *)elem2;
  732. // sort by material
  733. if (g_face[i1].material < g_face[i2].material)
  734. return -1;
  735. if (g_face[i1].material > g_face[i2].material)
  736. return 1;
  737. // sort by original usage
  738. if (i1 < i2)
  739. return -1;
  740. if (i1 > i2)
  741. return 1;
  742. return 0;
  743. }
  744. #define SMALL_FLOAT 1e-12
  745. // NOTE: This routine was taken (and modified) from NVidia's BlinnReflection demo
  746. // Creates basis vectors, based on a vertex and index list.
  747. // See the NVidia white paper 'GDC2K PerPixel Lighting' for a description
  748. // of how this computation works
  749. static void CalcTriangleTangentSpace( s_source_t *pSrc, int v1, int v2, int v3,
  750. Vector &sVect, Vector &tVect )
  751. {
  752. /*
  753. static bool firstTime = true;
  754. static FILE *fp = NULL;
  755. if( firstTime )
  756. {
  757. firstTime = false;
  758. fp = fopen( "crap.out", "w" );
  759. }
  760. */
  761. /* Compute the partial derivatives of X, Y, and Z with respect to S and T. */
  762. Vector2D t0( pSrc->texcoord[v1][0], pSrc->texcoord[v1][1] );
  763. Vector2D t1( pSrc->texcoord[v2][0], pSrc->texcoord[v2][1] );
  764. Vector2D t2( pSrc->texcoord[v3][0], pSrc->texcoord[v3][1] );
  765. Vector p0( pSrc->vertex[v1][0], pSrc->vertex[v1][1], pSrc->vertex[v1][2] );
  766. Vector p1( pSrc->vertex[v2][0], pSrc->vertex[v2][1], pSrc->vertex[v2][2] );
  767. Vector p2( pSrc->vertex[v3][0], pSrc->vertex[v3][1], pSrc->vertex[v3][2] );
  768. sVect.Init( 0.0f, 0.0f, 0.0f );
  769. tVect.Init( 0.0f, 0.0f, 0.0f );
  770. // x, s, t
  771. Vector edge01 = Vector( p1.x - p0.x, t1.x - t0.x, t1.y - t0.y );
  772. Vector edge02 = Vector( p2.x - p0.x, t2.x - t0.x, t2.y - t0.y );
  773. Vector cross;
  774. CrossProduct( edge01, edge02, cross );
  775. if( fabs( cross.x ) > SMALL_FLOAT )
  776. {
  777. sVect.x += -cross.y / cross.x;
  778. tVect.x += -cross.z / cross.x;
  779. }
  780. // y, s, t
  781. edge01 = Vector( p1.y - p0.y, t1.x - t0.x, t1.y - t0.y );
  782. edge02 = Vector( p2.y - p0.y, t2.x - t0.x, t2.y - t0.y );
  783. CrossProduct( edge01, edge02, cross );
  784. if( fabs( cross.x ) > SMALL_FLOAT )
  785. {
  786. sVect.y += -cross.y / cross.x;
  787. tVect.y += -cross.z / cross.x;
  788. }
  789. // z, s, t
  790. edge01 = Vector( p1.z - p0.z, t1.x - t0.x, t1.y - t0.y );
  791. edge02 = Vector( p2.z - p0.z, t2.x - t0.x, t2.y - t0.y );
  792. CrossProduct( edge01, edge02, cross );
  793. if( fabs( cross.x ) > SMALL_FLOAT )
  794. {
  795. sVect.z += -cross.y / cross.x;
  796. tVect.z += -cross.z / cross.x;
  797. }
  798. // Normalize sVect and tVect
  799. VectorNormalize( sVect );
  800. VectorNormalize( tVect );
  801. /*
  802. // Calculate flat normal
  803. Vector flatNormal;
  804. edge01 = p1 - p0;
  805. edge02 = p2 - p0;
  806. CrossProduct( edge02, edge01, flatNormal );
  807. VectorNormalize( flatNormal );
  808. // Get the average position
  809. Vector avgPos = ( p0 + p1 + p2 ) / 3.0f;
  810. // Draw the svect
  811. Vector endS = avgPos + sVect * .2f;
  812. fvprint( 0, fp, "2\n" );
  813. fvprint( 0, fp, "%f %f %f 1.0 0.0 0.0\n", endS[0], endS[1], endS[2] );
  814. fvprint( 0, fp, "%f %f %f 1.0 0.0 0.0\n", avgPos[0], avgPos[1], avgPos[2] );
  815. // Draw the tvect
  816. Vector endT = avgPos + tVect * .2f;
  817. fvprint( 0, fp, "2\n" );
  818. fvprint( 0, fp, "%f %f %f 0.0 1.0 0.0\n", endT[0], endT[1], endT[2] );
  819. fvprint( 0, fp, "%f %f %f 0.0 1.0 0.0\n", avgPos[0], avgPos[1], avgPos[2] );
  820. // Draw the normal
  821. Vector endN = avgPos + flatNormal * .2f;
  822. fvprint( 0, fp, "2\n" );
  823. fvprint( 0, fp, "%f %f %f 0.0 0.0 1.0\n", endN[0], endN[1], endN[2] );
  824. fvprint( 0, fp, "%f %f %f 0.0 0.0 1.0\n", avgPos[0], avgPos[1], avgPos[2] );
  825. // Draw the wireframe of the triangle in white.
  826. fvprint( 0, fp, "2\n" );
  827. fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p0[0], p0[1], p0[2] );
  828. fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p1[0], p1[1], p1[2] );
  829. fvprint( 0, fp, "2\n" );
  830. fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p1[0], p1[1], p1[2] );
  831. fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p2[0], p2[1], p2[2] );
  832. fvprint( 0, fp, "2\n" );
  833. fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p2[0], p2[1], p2[2] );
  834. fvprint( 0, fp, "%f %f %f 1.0 1.0 1.0\n", p0[0], p0[1], p0[2] );
  835. // Draw a slightly shrunken version of the geometry to hide surfaces
  836. Vector tmp0 = p0 - flatNormal * .1f;
  837. Vector tmp1 = p1 - flatNormal * .1f;
  838. Vector tmp2 = p2 - flatNormal * .1f;
  839. fvprint( 0, fp, "3\n" );
  840. fvprint( 0, fp, "%f %f %f 0.1 0.1 0.1\n", tmp0[0], tmp0[1], tmp0[2] );
  841. fvprint( 0, fp, "%f %f %f 0.1 0.1 0.1\n", tmp1[0], tmp1[1], tmp1[2] );
  842. fvprint( 0, fp, "%f %f %f 0.1 0.1 0.1\n", tmp2[0], tmp2[1], tmp2[2] );
  843. fflush( fp );
  844. */
  845. }
  846. typedef CUtlVector<int> CIntVector;
  847. void CalcModelTangentSpaces( s_source_t *pSrc )
  848. {
  849. // Build a map from vertex to a list of triangles that share the vert.
  850. int meshID;
  851. for( meshID = 0; meshID < pSrc->nummeshes; meshID++ )
  852. {
  853. s_mesh_t *pMesh = &pSrc->mesh[pSrc->meshindex[meshID]];
  854. CUtlVector<CIntVector> vertToTriMap;
  855. vertToTriMap.AddMultipleToTail( pMesh->numvertices );
  856. int triID;
  857. for( triID = 0; triID < pMesh->numfaces; triID++ )
  858. {
  859. s_face_t *pFace = &pSrc->face[triID + pMesh->faceoffset];
  860. vertToTriMap[pFace->a].AddToTail( triID );
  861. vertToTriMap[pFace->b].AddToTail( triID );
  862. vertToTriMap[pFace->c].AddToTail( triID );
  863. }
  864. // Calculate the tangent space for each triangle.
  865. CUtlVector<Vector> triSVect;
  866. CUtlVector<Vector> triTVect;
  867. triSVect.AddMultipleToTail( pMesh->numfaces );
  868. triTVect.AddMultipleToTail( pMesh->numfaces );
  869. for( triID = 0; triID < pMesh->numfaces; triID++ )
  870. {
  871. s_face_t *pFace = &pSrc->face[triID + pMesh->faceoffset];
  872. CalcTriangleTangentSpace( pSrc,
  873. pMesh->vertexoffset + pFace->a,
  874. pMesh->vertexoffset + pFace->b,
  875. pMesh->vertexoffset + pFace->c,
  876. triSVect[triID], triTVect[triID] );
  877. }
  878. // calculate an average tangent space for each vertex.
  879. int vertID;
  880. for( vertID = 0; vertID < pMesh->numvertices; vertID++ )
  881. {
  882. const Vector &normal = pSrc->normal[vertID+pMesh->vertexoffset];
  883. Vector4D &finalSVect = pSrc->tangentS[vertID+pMesh->vertexoffset];
  884. Vector sVect, tVect;
  885. sVect.Init( 0.0f, 0.0f, 0.0f );
  886. tVect.Init( 0.0f, 0.0f, 0.0f );
  887. for( triID = 0; triID < vertToTriMap[vertID].Size(); triID++ )
  888. {
  889. sVect += triSVect[vertToTriMap[vertID][triID]];
  890. tVect += triTVect[vertToTriMap[vertID][triID]];
  891. }
  892. // In the case of zbrush, everything needs to be treated as smooth.
  893. if( g_bZBrush )
  894. {
  895. int vertID2;
  896. Vector vertPos1( pSrc->vertex[vertID][0], pSrc->vertex[vertID][1], pSrc->vertex[vertID][2] );
  897. for( vertID2 = 0; vertID2 < pMesh->numvertices; vertID2++ )
  898. {
  899. if( vertID2 == vertID )
  900. {
  901. continue;
  902. }
  903. Vector vertPos2( pSrc->vertex[vertID2][0], pSrc->vertex[vertID2][1], pSrc->vertex[vertID2][2] );
  904. if( vertPos1 == vertPos2 )
  905. {
  906. int triID2;
  907. for( triID2 = 0; triID2 < vertToTriMap[vertID2].Size(); triID2++ )
  908. {
  909. sVect += triSVect[vertToTriMap[vertID2][triID2]];
  910. tVect += triTVect[vertToTriMap[vertID2][triID2]];
  911. }
  912. }
  913. }
  914. }
  915. // make an orthonormal system.
  916. // need to check if we are left or right handed.
  917. Vector tmpVect;
  918. CrossProduct( sVect, tVect, tmpVect );
  919. bool leftHanded = DotProduct( tmpVect, normal ) < 0.0f;
  920. if( !leftHanded )
  921. {
  922. CrossProduct( normal, sVect, tVect );
  923. CrossProduct( tVect, normal, sVect );
  924. VectorNormalize( sVect );
  925. VectorNormalize( tVect );
  926. finalSVect[0] = sVect[0];
  927. finalSVect[1] = sVect[1];
  928. finalSVect[2] = sVect[2];
  929. finalSVect[3] = 1.0f;
  930. }
  931. else
  932. {
  933. CrossProduct( sVect, normal, tVect );
  934. CrossProduct( normal, tVect, sVect );
  935. VectorNormalize( sVect );
  936. VectorNormalize( tVect );
  937. finalSVect[0] = sVect[0];
  938. finalSVect[1] = sVect[1];
  939. finalSVect[2] = sVect[2];
  940. finalSVect[3] = -1.0f;
  941. }
  942. }
  943. }
  944. }
  945. void BuildIndividualMeshes( s_source_t *psource )
  946. {
  947. int i, j, k;
  948. // sort new vertices by materials, last used
  949. static int v_listsort[MAXSTUDIOVERTS]; // map desired order to vlist entry
  950. static int v_ilistsort[MAXSTUDIOVERTS]; // map vlist entry to desired order
  951. for (i = 0; i < numvlist; i++)
  952. {
  953. v_listsort[i] = i;
  954. }
  955. qsort( v_listsort, numvlist, sizeof( int ), vlistCompare );
  956. for (i = 0; i < numvlist; i++)
  957. {
  958. v_ilistsort[v_listsort[i]] = i;
  959. }
  960. // allocate memory
  961. psource->numvertices = numvlist;
  962. psource->localBoneweight = (s_boneweight_t *)kalloc( psource->numvertices, sizeof( s_boneweight_t ) );
  963. psource->globalBoneweight = NULL;
  964. psource->vertexInfo = (s_vertexinfo_t *)kalloc( psource->numvertices, sizeof( s_vertexinfo_t ) );
  965. psource->vertex = new Vector[psource->numvertices];
  966. psource->normal = new Vector[psource->numvertices];
  967. psource->tangentS = new Vector4D[psource->numvertices];
  968. psource->texcoord = (Vector2D *)kalloc( psource->numvertices, sizeof( Vector2D ) );
  969. // create arrays of unique vertexes, normals, texcoords.
  970. for (i = 0; i < psource->numvertices; i++)
  971. {
  972. j = v_listsort[i];
  973. VectorCopy( g_vertex[v_listdata[j].v], psource->vertex[i] );
  974. VectorCopy( g_normal[v_listdata[j].n], psource->normal[i] );
  975. Vector2Copy( g_texcoord[v_listdata[j].t], psource->texcoord[i] );
  976. psource->localBoneweight[i].numbones = g_bone[v_listdata[j].v].numbones;
  977. int k;
  978. for( k = 0; k < MAXSTUDIOBONEWEIGHTS; k++ )
  979. {
  980. psource->localBoneweight[i].bone[k] = g_bone[v_listdata[j].v].bone[k];
  981. psource->localBoneweight[i].weight[k] = g_bone[v_listdata[j].v].weight[k];
  982. }
  983. // store a bunch of other info
  984. psource->vertexInfo[i].material = v_listdata[j].m;
  985. psource->vertexInfo[i].firstref = v_listdata[j].firstref;
  986. psource->vertexInfo[i].lastref = v_listdata[j].lastref;
  987. // vprint( 0, "%4d : %2d : %6.2f %6.2f %6.2f\n", i, psource->boneweight[i].bone[0], psource->vertex[i][0], psource->vertex[i][1], psource->vertex[i][2] );
  988. }
  989. // sort faces by materials, last used.
  990. static int facesort[MAXSTUDIOTRIANGLES]; // map desired order to src_face entry
  991. static int ifacesort[MAXSTUDIOTRIANGLES]; // map src_face entry to desired order
  992. for (i = 0; i < g_numfaces; i++)
  993. {
  994. facesort[i] = i;
  995. }
  996. qsort( facesort, g_numfaces, sizeof( int ), faceCompare );
  997. for (i = 0; i < g_numfaces; i++)
  998. {
  999. ifacesort[facesort[i]] = i;
  1000. }
  1001. psource->numfaces = g_numfaces;
  1002. // find first occurance for each material
  1003. for (k = 0; k < MAXSTUDIOSKINS; k++)
  1004. {
  1005. psource->mesh[k].numvertices = 0;
  1006. psource->mesh[k].vertexoffset = psource->numvertices;
  1007. psource->mesh[k].numfaces = 0;
  1008. psource->mesh[k].faceoffset = g_numfaces;
  1009. }
  1010. // find first and count of indices per material
  1011. for (i = 0; i < psource->numvertices; i++)
  1012. {
  1013. k = psource->vertexInfo[i].material;
  1014. psource->mesh[k].numvertices++;
  1015. if (psource->mesh[k].vertexoffset > i)
  1016. psource->mesh[k].vertexoffset = i;
  1017. }
  1018. // find first and count of faces per material
  1019. for (i = 0; i < psource->numfaces; i++)
  1020. {
  1021. k = g_face[facesort[i]].material;
  1022. psource->mesh[k].numfaces++;
  1023. if (psource->mesh[k].faceoffset > i)
  1024. psource->mesh[k].faceoffset = i;
  1025. }
  1026. /*
  1027. for (k = 0; k < MAXSTUDIOSKINS; k++)
  1028. {
  1029. vprint( 0, "%d : %d:%d %d:%d\n", k, psource->mesh[k].numvertices, psource->mesh[k].vertexoffset, psource->mesh[k].numfaces, psource->mesh[k].faceoffset );
  1030. }
  1031. */
  1032. // create remapped faces
  1033. psource->face = (s_face_t *)kalloc( psource->numfaces, sizeof( s_face_t ));
  1034. for (k = 0; k < MAXSTUDIOSKINS; k++)
  1035. {
  1036. if (psource->mesh[k].numfaces)
  1037. {
  1038. psource->meshindex[psource->nummeshes] = k;
  1039. for (i = psource->mesh[k].faceoffset; i < psource->mesh[k].numfaces + psource->mesh[k].faceoffset; i++)
  1040. {
  1041. j = facesort[i];
  1042. psource->face[i].a = v_ilistsort[g_src_uface[j].a] - psource->mesh[k].vertexoffset;
  1043. psource->face[i].b = v_ilistsort[g_src_uface[j].b] - psource->mesh[k].vertexoffset;
  1044. psource->face[i].c = v_ilistsort[g_src_uface[j].c] - psource->mesh[k].vertexoffset;
  1045. Assert( ((psource->face[i].a & 0xF0000000) == 0) && ((psource->face[i].b & 0xF0000000) == 0) &&
  1046. ((psource->face[i].c & 0xF0000000) == 0) );
  1047. // vprint( 0, "%3d : %4d %4d %4d\n", i, psource->face[i].a, psource->face[i].b, psource->face[i].c );
  1048. }
  1049. psource->nummeshes++;
  1050. }
  1051. }
  1052. CalcModelTangentSpaces( psource );
  1053. }
  1054. void Grab_Triangles( s_source_t *psource )
  1055. {
  1056. int i;
  1057. Vector vmin, vmax;
  1058. vmin[0] = vmin[1] = vmin[2] = 99999;
  1059. vmax[0] = vmax[1] = vmax[2] = -99999;
  1060. g_numfaces = 0;
  1061. numvlist = 0;
  1062. //
  1063. // load the base triangles
  1064. //
  1065. int texture;
  1066. int material;
  1067. char texturename[64];
  1068. while (1)
  1069. {
  1070. if (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) == NULL)
  1071. break;
  1072. g_iLinecount++;
  1073. // check for end
  1074. if (IsEnd( g_szLine ))
  1075. break;
  1076. // Look for extra junk that we may want to avoid...
  1077. int nLineLength = strlen( g_szLine );
  1078. if (nLineLength >= 64)
  1079. {
  1080. MdlWarning("Unexpected data at line %d, (need a texture name) ignoring...\n", g_iLinecount );
  1081. continue;
  1082. }
  1083. // strip off trailing smag
  1084. V_strcpy_safe( texturename, g_szLine );
  1085. for (i = strlen( texturename ) - 1; i >= 0 && ! isgraph( texturename[i] ); i--)
  1086. {
  1087. }
  1088. texturename[i + 1] = '\0';
  1089. // funky texture overrides
  1090. for (i = 0; i < numrep; i++)
  1091. {
  1092. if (sourcetexture[i][0] == '\0')
  1093. {
  1094. strcpy( texturename, defaulttexture[i] );
  1095. break;
  1096. }
  1097. if (stricmp( texturename, sourcetexture[i]) == 0)
  1098. {
  1099. strcpy( texturename, defaulttexture[i] );
  1100. break;
  1101. }
  1102. }
  1103. if (texturename[0] == '\0')
  1104. {
  1105. // weird source problem, skip them
  1106. fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
  1107. fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
  1108. fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
  1109. g_iLinecount += 3;
  1110. continue;
  1111. }
  1112. if (stricmp( texturename, "null.bmp") == 0 || stricmp( texturename, "null.tga") == 0)
  1113. {
  1114. // skip all faces with the null texture on them.
  1115. fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
  1116. fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
  1117. fgets( g_szLine, sizeof( g_szLine ), g_fpInput );
  1118. g_iLinecount += 3;
  1119. continue;
  1120. }
  1121. texture = lookup_texture( texturename, sizeof( texturename ) );
  1122. psource->texmap[texture] = texture; // hack, make it 1:1
  1123. material = use_texture_as_material( texture );
  1124. s_face_t f;
  1125. ParseFaceData( psource, material, &f );
  1126. g_src_uface[g_numfaces] = f;
  1127. g_face[g_numfaces].material = material;
  1128. g_numfaces++;
  1129. }
  1130. BuildIndividualMeshes( psource );
  1131. }
  1132. //--------------------------------------------------------------------
  1133. // Load a SMD file
  1134. //--------------------------------------------------------------------
  1135. int Load_SMD ( s_source_t *psource )
  1136. {
  1137. char cmd[1024];
  1138. int option;
  1139. // Open file
  1140. if (!OpenGlobalFile( psource->filename ))
  1141. return 0;
  1142. // verbose
  1143. if( !g_quiet )
  1144. {
  1145. printf ("SMD MODEL %s\n", psource->filename);
  1146. }
  1147. //March through lines
  1148. g_iLinecount = 0;
  1149. while (fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
  1150. {
  1151. g_iLinecount++;
  1152. int numRead = sscanf( g_szLine, "%s %d", cmd, &option );
  1153. // Blank line
  1154. if ((numRead == EOF) || (numRead == 0))
  1155. continue;
  1156. if (strcmp( cmd, "version" ) == 0)
  1157. {
  1158. if (option != 1)
  1159. {
  1160. MdlError("bad version\n");
  1161. }
  1162. }
  1163. // Get hierarchy?
  1164. else if (strcmp( cmd, "nodes" ) == 0)
  1165. {
  1166. psource->numbones = Grab_Nodes( psource->localBone );
  1167. }
  1168. // Get animation??
  1169. else if (strcmp( cmd, "skeleton" ) == 0)
  1170. {
  1171. Grab_Animation( psource );
  1172. }
  1173. // Geo?
  1174. else if (strcmp( cmd, "triangles" ) == 0)
  1175. {
  1176. Grab_Triangles( psource );
  1177. }
  1178. // Geo animation
  1179. else if (strcmp( cmd, "vertexanimation" ) == 0)
  1180. {
  1181. Grab_Vertexanimation( psource );
  1182. }
  1183. else
  1184. {
  1185. MdlWarning("unknown studio command\n" );
  1186. }
  1187. }
  1188. fclose( g_fpInput );
  1189. is_v1support = true;
  1190. return 1;
  1191. }
  1192. //-----------------------------------------------------------------------------
  1193. // Checks to see if the model source was already loaded
  1194. //-----------------------------------------------------------------------------
  1195. static s_source_t *FindCachedSource( char const* name, char const* xext )
  1196. {
  1197. int i;
  1198. if( xext[0] )
  1199. {
  1200. // we know what extension is necessary. . look for it.
  1201. sprintf (g_szFilename, "%s%s.%s", cddir[numdirs], name, xext );
  1202. for (i = 0; i < g_numsources; i++)
  1203. {
  1204. if (stricmp( g_szFilename, g_source[i]->filename ) == 0)
  1205. return g_source[i];
  1206. }
  1207. }
  1208. else
  1209. {
  1210. // we don't know what extension to use, so look for all of 'em.
  1211. sprintf (g_szFilename, "%s%s.vrm", cddir[numdirs], name );
  1212. for (i = 0; i < g_numsources; i++)
  1213. {
  1214. if (stricmp( g_szFilename, g_source[i]->filename ) == 0)
  1215. return g_source[i];
  1216. }
  1217. sprintf (g_szFilename, "%s%s.smd", cddir[numdirs], name );
  1218. for (i = 0; i < g_numsources; i++)
  1219. {
  1220. if (stricmp( g_szFilename, g_source[i]->filename ) == 0)
  1221. return g_source[i];
  1222. }
  1223. /*
  1224. sprintf (g_szFilename, "%s%s.vta", cddir[numdirs], name );
  1225. for (i = 0; i < g_numsources; i++)
  1226. {
  1227. if (stricmp( g_szFilename, g_source[i]->filename ) == 0)
  1228. return g_source[i];
  1229. }
  1230. */
  1231. }
  1232. // Not found
  1233. return 0;
  1234. }
  1235. static void FlipFacing( s_source_t *pSrc )
  1236. {
  1237. unsigned short tmp;
  1238. int i, j;
  1239. for( i = 0; i < pSrc->nummeshes; i++ )
  1240. {
  1241. s_mesh_t *pMesh = &pSrc->mesh[i];
  1242. for( j = 0; j < pMesh->numfaces; j++ )
  1243. {
  1244. s_face_t &f = pSrc->face[pMesh->faceoffset + j];
  1245. tmp = f.b; f.b = f.c; f.c = tmp;
  1246. }
  1247. }
  1248. }
  1249. //-----------------------------------------------------------------------------
  1250. // Loads an animation source
  1251. //-----------------------------------------------------------------------------
  1252. s_source_t *Load_Source( char const *name, const char *ext, bool reverse, bool isActiveModel )
  1253. {
  1254. // Sanity check number of source files
  1255. if ( g_numsources >= MAXSTUDIOSEQUENCES )
  1256. MdlError( "Load_Source( %s ) - overflowed g_numsources.", name );
  1257. // Sanity check file and init
  1258. Assert(name);
  1259. int namelen = strlen(name) + 1;
  1260. char* pTempName = (char*)_alloca( namelen );
  1261. char xext[32];
  1262. int result = false;
  1263. // Local copy of filename
  1264. strcpy( pTempName, name );
  1265. // Sanity check file extension?
  1266. Q_ExtractFileExtension( pTempName, xext, sizeof( xext ) );
  1267. if (xext[0] == '\0')
  1268. {
  1269. V_strcpy_safe( xext, ext );
  1270. }
  1271. else
  1272. {
  1273. Q_StripExtension( pTempName, pTempName, namelen );
  1274. }
  1275. // Cached source, ie: already loaded model, legacy
  1276. // s_source_t* pSource = FindCachedSource( pTempName, xext );
  1277. // if (pSource)
  1278. // {
  1279. // if (isActiveModel)
  1280. // pSource->isActiveModel = true;
  1281. // return pSource;
  1282. // }
  1283. // allocate space and whatnot
  1284. g_source[g_numsources] = (s_source_t *)kalloc( 1, sizeof( s_source_t ) );
  1285. V_strcpy_safe( g_source[g_numsources]->filename, g_szFilename );
  1286. // legacy stuff
  1287. if (isActiveModel)
  1288. {
  1289. g_source[g_numsources]->isActiveModel = true;
  1290. }
  1291. // more ext sanity check
  1292. if ( ( !result && xext[0] == '\0' ) || stricmp( xext, "smd" ) == 0)
  1293. {
  1294. Q_snprintf( g_szFilename, sizeof(g_szFilename), "%s%s.smd", cddir[numdirs], pTempName );
  1295. V_strcpy_safe( g_source[g_numsources]->filename, g_szFilename );
  1296. // Import part, load smd file
  1297. result = Load_SMD( g_source[g_numsources] );
  1298. }
  1299. /*
  1300. if ( ( !result && xext[0] == '\0' ) || stricmp( xext, "dmx" ) == 0)
  1301. {
  1302. Q_snprintf( g_szFilename, sizeof(g_szFilename), "%s%s.dmx", cddir[numdirs], pTempName );
  1303. V_strcpy_safe( g_source[g_numsources]->filename, g_szFilename );
  1304. // Import part, load smd file
  1305. result = Load_DMX( g_source[g_numsources] );
  1306. }
  1307. */
  1308. // Oops
  1309. if ( !result)
  1310. {
  1311. MdlError( "could not load file '%s'\n", g_source[g_numsources]->filename );
  1312. }
  1313. // bump up number of sources
  1314. g_numsources++;
  1315. if( reverse )
  1316. {
  1317. FlipFacing( g_source[g_numsources-1] );
  1318. }
  1319. return g_source[g_numsources-1];
  1320. }
  1321. void SaveNodes( s_source_t *source, CUtlBuffer& buf )
  1322. {
  1323. if ( source->numbones <= 0 )
  1324. return;
  1325. buf.Printf( "nodes\n" );
  1326. for ( int i = 0; i < source->numbones; ++i )
  1327. {
  1328. s_node_t *bone = &source->localBone[ i ];
  1329. buf.Printf( "%d \"%s\" %d\n", i, bone->name, bone->parent );
  1330. }
  1331. buf.Printf( "end\n" );
  1332. }
  1333. // FIXME: since we don't us a .qc, we could have problems with scaling, etc.???
  1334. void descale_vertex( Vector &org )
  1335. {
  1336. float invscale = 1.0f / g_currentscale;
  1337. org[0] = org[0] * invscale;
  1338. org[1] = org[1] * invscale;
  1339. org[2] = org[2] * invscale;
  1340. }
  1341. void SaveAnimation( s_source_t *source, CUtlBuffer& buf )
  1342. {
  1343. if ( source->numbones <= 0 )
  1344. return;
  1345. buf.Printf( "skeleton\n" );
  1346. for ( int frame = 0; frame < source->numframes; ++frame )
  1347. {
  1348. buf.Printf( "time %i\n", frame + source->startframe );
  1349. for ( int i = 0; i < source->numbones; ++i )
  1350. {
  1351. s_bone_t *prev = NULL;
  1352. if ( frame > 0 )
  1353. {
  1354. if ( source->rawanim[ frame - 1 ] )
  1355. {
  1356. prev = &source->rawanim[ frame - 1 ][ i ];
  1357. }
  1358. }
  1359. Vector pos = source->rawanim[ frame ][ i ].pos;
  1360. descale_vertex( pos );
  1361. RadianEuler rot = source->rawanim[ frame ][ i ].rot;
  1362. // If this is enabled, then we delta this pos vs the prev frame and don't write out a sample if it's the same value...
  1363. #if 0
  1364. if ( prev )
  1365. {
  1366. Vector ppos = source->rawanim[ frame -1 ][ i ].pos;
  1367. descale_vertex( pos );
  1368. RadianEuler prot = source->rawanim[ frame -1 ][ i ].rot;
  1369. // Only output it if there's a delta
  1370. if ( ( ppos != pos ) ||
  1371. Q_memcmp( &prot, &rot, sizeof( prot ) ) )
  1372. {
  1373. buf.Printf
  1374. ( "%d %f %f %f %f %f %f\n",
  1375. i, // bone index
  1376. pos[ 0 ],
  1377. pos[ 1 ],
  1378. pos[ 2 ],
  1379. rot[ 0 ],
  1380. rot[ 1 ],
  1381. rot[ 2 ]
  1382. );
  1383. }
  1384. }
  1385. else
  1386. #endif
  1387. {
  1388. buf.Printf
  1389. ( "%d %f %f %f %f %f %f\n",
  1390. i, // bone index
  1391. pos[ 0 ],
  1392. pos[ 1 ],
  1393. pos[ 2 ],
  1394. rot[ 0 ],
  1395. rot[ 1 ],
  1396. rot[ 2 ]
  1397. );
  1398. }
  1399. }
  1400. }
  1401. buf.Printf( "end\n" );
  1402. }
  1403. void Save_SMD( char const *filename, s_source_t *source )
  1404. {
  1405. // Text buffer
  1406. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  1407. buf.Printf( "version 1\n" );
  1408. SaveNodes( source, buf );
  1409. SaveAnimation( source, buf );
  1410. FileHandle_t fh = g_pFileSystem->Open( filename, "wb" );
  1411. if ( FILESYSTEM_INVALID_HANDLE != fh )
  1412. {
  1413. g_pFileSystem->Write( buf.Base(), buf.TellPut(), fh );
  1414. g_pFileSystem->Close( fh );
  1415. }
  1416. }
  1417. //--------------------------------------------------------------------
  1418. // mikes right handed row based linear algebra
  1419. //--------------------------------------------------------------------
  1420. struct M_matrix4x4_t
  1421. {
  1422. M_matrix4x4_t() {
  1423. m_flMatVal[0][0] = 1.0; m_flMatVal[0][1] = 0.0; m_flMatVal[0][2] = 0.0; m_flMatVal[0][3] = 0.0;
  1424. m_flMatVal[1][0] = 0.0; m_flMatVal[1][1] = 1.0; m_flMatVal[1][2] = 0.0; m_flMatVal[1][3] = 0.0;
  1425. m_flMatVal[2][0] = 0.0; m_flMatVal[2][1] = 0.0; m_flMatVal[2][2] = 1.0; m_flMatVal[2][3] = 0.0;
  1426. m_flMatVal[3][0] = 0.0; m_flMatVal[3][1] = 0.0; m_flMatVal[3][2] = 0.0; m_flMatVal[3][3] = 1.0;
  1427. }
  1428. // M_matrix3x4_t(
  1429. // float m00, float m01, float m02,
  1430. // float m10, float m11, float m12,
  1431. // float m20, float m21, float m22,
  1432. // float m30, float m31, float m32)
  1433. // {
  1434. // m_flMatVal[0][0] = m00; m_flMatVal[0][1] = m01; m_flMatVal[0][2] = m02;
  1435. // m_flMatVal[1][0] = m10; m_flMatVal[1][1] = m11; m_flMatVal[1][2] = m12;
  1436. // m_flMatVal[2][0] = m20; m_flMatVal[2][1] = m21; m_flMatVal[2][2] = m22;
  1437. // m_flMatVal[3][0] = m30; m_flMatVal[3][1] = m31; m_flMatVal[3][2] = m32;
  1438. // }
  1439. float *operator[]( int i ) { Assert(( i >= 0 ) && ( i < 4 )); return m_flMatVal[i]; }
  1440. const float *operator[]( int i ) const { Assert(( i >= 0 ) && ( i < 4 )); return m_flMatVal[i]; }
  1441. float *Base() { return &m_flMatVal[0][0]; }
  1442. const float *Base() const { return &m_flMatVal[0][0]; }
  1443. float m_flMatVal[4][4];
  1444. };
  1445. void M_MatrixAngles( const M_matrix4x4_t& matrix, RadianEuler &angles, Vector &position)
  1446. {
  1447. float cX, sX, cY, sY, cZ, sZ;
  1448. sY = -matrix[0][2];
  1449. cY = sqrtf(1.0-(sY*sY));
  1450. if (cY != 0.0)
  1451. {
  1452. sX = matrix[1][2];
  1453. cX = matrix[2][2];
  1454. sZ = matrix[0][1];
  1455. cZ = matrix[0][0];
  1456. }
  1457. else
  1458. {
  1459. sX = -matrix[2][1];
  1460. cX = matrix[1][1];
  1461. sZ = 0.0;
  1462. cZ = 1.0;
  1463. }
  1464. angles[0] = atan2f( sX, cX );
  1465. angles[2] = atan2f( sZ, cZ );
  1466. sX = sinf(angles[0]);
  1467. cX = cosf(angles[0]);
  1468. if (sX > cX)
  1469. cY = matrix[1][2] / sX;
  1470. else
  1471. cY = matrix[2][2] / cX;
  1472. angles[1] = atan2f( sY, cY );
  1473. position.x = matrix[3][0];
  1474. position.y = matrix[3][1];
  1475. position.z = matrix[3][2];
  1476. }
  1477. // void M_MatrixAngles( const M_matrix4x4_t& matrix, RadianEuler &angles, Vector &position)
  1478. // {
  1479. // float cX, sX, cY, sY, cZ, sZ;
  1480. // sY = matrix[2][0];
  1481. // cY = sqrtf(1.0-(sY*sY));
  1482. // if (cY != 0.0)
  1483. // {
  1484. // sX = -matrix[2][1];
  1485. // cX = matrix[2][2];
  1486. // sZ = -matrix[1][0];
  1487. // cZ = matrix[0][0];
  1488. // }
  1489. // else
  1490. // {
  1491. // sX = matrix[0][1];
  1492. // cX = matrix[1][1];
  1493. // sZ = 0.0;
  1494. // cZ = 1.0;
  1495. // }
  1496. // angles[0] = atan2f( sX, cX );
  1497. // angles[2] = atan2f( sZ, cZ );
  1498. // sX = sinf(angles[0]);
  1499. // cX = cosf(angles[0]);
  1500. // if (sX > cX)
  1501. // cY = -matrix[2][1] / sX;
  1502. // else
  1503. // cY = matrix[2][2] / cX;
  1504. // angles[1] = atan2f( sY, cY );
  1505. // angles[0] = angles[0];
  1506. // angles[1] = angles[1];
  1507. // angles[2] = angles[2];
  1508. // position.x = matrix[3][0];
  1509. // position.y = matrix[3][1];
  1510. // position.z = matrix[3][2];
  1511. // }
  1512. void M_MatrixCopy( const M_matrix4x4_t& in, M_matrix4x4_t& out )
  1513. {
  1514. // Assert( s_bMathlibInitialized );
  1515. memcpy( out.Base(), in.Base(), sizeof( float ) * 4 * 4 );
  1516. }
  1517. void M_RotateZMatrix(float radian, M_matrix4x4_t &resultMatrix)
  1518. {
  1519. resultMatrix[0][0] = cosf(radian);
  1520. resultMatrix[0][1] = sin(radian);
  1521. resultMatrix[0][2] = 0.0;
  1522. resultMatrix[1][0] =-sin(radian);
  1523. resultMatrix[1][1] = cos(radian);
  1524. resultMatrix[1][2] = 0.0;
  1525. resultMatrix[2][0] = 0.0;
  1526. resultMatrix[2][1] = 0.0;
  1527. resultMatrix[2][2] = 1.0;
  1528. }
  1529. // !!! THIS SHIT DOESN'T WORK!! WHY? HAS I EVER?
  1530. void M_AngleAboutAxis(Vector &axis, float radianAngle, M_matrix4x4_t &result)
  1531. {
  1532. float c = cosf(radianAngle);
  1533. float s = sinf(radianAngle);
  1534. float t = 1.0 - c;
  1535. // axis.normalize();
  1536. result[0][0] = t * axis[0] * axis[0] + c;
  1537. result[0][1] = t * axis[0] * axis[1] - s * axis[2];
  1538. result[0][2] = t * axis[0] * axis[2] + s * axis[1];
  1539. result[1][0] = t * axis[0] * axis[1] + s * axis[2];
  1540. result[1][1] = t * axis[1] * axis[1] + c;
  1541. result[1][2] = t * axis[1] * axis[2] - s * axis[0];
  1542. result[2][0] = t * axis[1] * axis[2] - s;
  1543. result[2][1] = t * axis[1] * axis[2] + s * axis[1];
  1544. result[2][2] = t * axis[2] * axis[2] + c * axis[0];
  1545. }
  1546. void M_MatrixInvert( const M_matrix4x4_t& in, M_matrix4x4_t& out )
  1547. {
  1548. // Assert( s_bMathlibInitialized );
  1549. if ( &in == &out )
  1550. {
  1551. M_matrix4x4_t in2;
  1552. M_MatrixCopy( in, in2 );
  1553. M_MatrixInvert( in2, out );
  1554. return;
  1555. }
  1556. float tmp[3];
  1557. // I'm guessing this only works on a 3x4 orthonormal matrix
  1558. out[0][0] = in[0][0];
  1559. out[1][0] = in[0][1];
  1560. out[2][0] = in[0][2];
  1561. out[0][1] = in[1][0];
  1562. out[1][1] = in[1][1];
  1563. out[2][1] = in[1][2];
  1564. out[0][2] = in[2][0];
  1565. out[1][2] = in[2][1];
  1566. out[2][2] = in[2][2];
  1567. tmp[0] = in[3][0];
  1568. tmp[1] = in[3][1];
  1569. tmp[2] = in[3][2];
  1570. float v1[3], v2[3], v3[3];
  1571. v1[0] = out[0][0];
  1572. v1[1] = out[1][0];
  1573. v1[2] = out[2][0];
  1574. v2[0] = out[0][1];
  1575. v2[1] = out[1][1];
  1576. v2[2] = out[2][1];
  1577. v3[0] = out[0][2];
  1578. v3[1] = out[1][2];
  1579. v3[2] = out[2][2];
  1580. out[3][0] = -DotProduct( tmp, v1 );
  1581. out[3][1] = -DotProduct( tmp, v2 );
  1582. out[3][2] = -DotProduct( tmp, v3 );
  1583. // Trivial case
  1584. // if (IS_IDENTITY(matrix))
  1585. // return SbMatrix::identity();
  1586. // // Affine case...
  1587. // // SbMatrix affineAnswer;
  1588. // // if ( affine_inverse( SbMatrix(matrix), affineAnswer ) )
  1589. // // return affineAnswer;
  1590. // int index[4];
  1591. // float d, invmat[4][4], temp;
  1592. // SbMatrix inverse = *this;
  1593. // if(inverse.LUDecomposition(index, d)) {
  1594. // invmat[0][0] = 1.0;
  1595. // invmat[0][1] = 0.0;
  1596. // invmat[0][2] = 0.0;
  1597. // invmat[0][3] = 0.0;
  1598. // inverse.LUBackSubstitution(index, invmat[0]);
  1599. // invmat[1][0] = 0.0;
  1600. // invmat[1][1] = 1.0;
  1601. // invmat[1][2] = 0.0;
  1602. // invmat[1][3] = 0.0;
  1603. // inverse.LUBackSubstitution(index, invmat[1]);
  1604. // invmat[2][0] = 0.0;
  1605. // invmat[2][1] = 0.0;
  1606. // invmat[2][2] = 1.0;
  1607. // invmat[2][3] = 0.0;
  1608. // inverse.LUBackSubstitution(index, invmat[2]);
  1609. // invmat[3][0] = 0.0;
  1610. // invmat[3][1] = 0.0;
  1611. // invmat[3][2] = 0.0;
  1612. // invmat[3][3] = 1.0;
  1613. // inverse.LUBackSubstitution(index, invmat[3]);
  1614. // #define SWAP(i,j) \
  1615. // temp = invmat[i][j]; \
  1616. // invmat[i][j] = invmat[j][i]; \
  1617. // invmat[j][i] = temp;
  1618. // SWAP(1,0);
  1619. // SWAP(2,0);
  1620. // SWAP(2,1);
  1621. // SWAP(3,0);
  1622. // SWAP(3,1);
  1623. // SWAP(3,2);
  1624. // #undef SWAP
  1625. // }
  1626. }
  1627. /*
  1628. ================
  1629. M_ConcatTransforms
  1630. ================
  1631. */
  1632. void M_ConcatTransforms (const M_matrix4x4_t &in1, const M_matrix4x4_t &in2, M_matrix4x4_t &out)
  1633. {
  1634. // Assert( s_bMathlibInitialized );
  1635. // if ( &in1 == &out )
  1636. // {
  1637. // matrix3x4_t in1b;
  1638. // MatrixCopy( in1, in1b );
  1639. // ConcatTransforms( in1b, in2, out );
  1640. // return;
  1641. // }
  1642. // if ( &in2 == &out )
  1643. // {
  1644. // matrix3x4_t in2b;
  1645. // MatrixCopy( in2, in2b );
  1646. // ConcatTransforms( in1, in2b, out );
  1647. // return;
  1648. // }
  1649. #define MULT(i,j) (in1[i][0]*in2[0][j] + \
  1650. in1[i][1]*in2[1][j] + \
  1651. in1[i][2]*in2[2][j] + \
  1652. in1[i][3]*in2[3][j])
  1653. out[0][0] = MULT(0,0);
  1654. out[0][1] = MULT(0,1);
  1655. out[0][2] = MULT(0,2);
  1656. out[0][3] = MULT(0,3);
  1657. out[1][0] = MULT(1,0);
  1658. out[1][1] = MULT(1,1);
  1659. out[1][2] = MULT(1,2);
  1660. out[1][3] = MULT(1,3);
  1661. out[2][0] = MULT(2,0);
  1662. out[2][1] = MULT(2,1);
  1663. out[2][2] = MULT(2,2);
  1664. out[2][3] = MULT(2,3);
  1665. out[3][0] = MULT(3,0);
  1666. out[3][1] = MULT(3,1);
  1667. out[3][2] = MULT(3,2);
  1668. out[3][3] = MULT(3,3);
  1669. #undef MULT
  1670. }
  1671. void M_AngleMatrix( RadianEuler const &angles, const Vector &position, M_matrix4x4_t& matrix )
  1672. {
  1673. // Assert( s_bMathlibInitialized );
  1674. float sx, sy, sz, cx, cy, cz;
  1675. sx = sinf(angles[0]);
  1676. cx = cosf(angles[0]);
  1677. sy = sinf(angles[1]);
  1678. cy = cosf(angles[1]);
  1679. sz = sinf(angles[2]);
  1680. cz = cosf(angles[2]);
  1681. // SinCos( angles[0], &sx, &cx ); // 2
  1682. // SinCos( angles[1], &sy, &cy ); // 1
  1683. // SinCos( angles[2], &sz, &cz ); // 0
  1684. M_matrix4x4_t mx, my, mz, temp1;
  1685. // rotation about x
  1686. mx[1][1] = cx;
  1687. mx[1][2] = sx;
  1688. mx[2][1] = -sx;
  1689. mx[2][2] = cx;
  1690. // rotation about y
  1691. my[0][0] = cy;
  1692. my[0][2] = -sy;
  1693. my[2][0] = sy;
  1694. my[2][2] = cy;
  1695. // rotation about z
  1696. mz[0][0] = cz;
  1697. mz[0][1] = sz;
  1698. mz[1][0] = -sz;
  1699. mz[1][1] = cz;
  1700. // z * y * x
  1701. M_ConcatTransforms(mx, my, temp1);
  1702. M_ConcatTransforms(temp1, mz, matrix);
  1703. // put position in
  1704. matrix[3][0] = position.x;
  1705. matrix[3][1] = position.y;
  1706. matrix[3][2] = position.z;
  1707. }
  1708. //-----------------------------------------------------------------------------
  1709. // Motion mapper functions
  1710. //-----------------------------------------------------------------------------
  1711. #define BONEAXIS 0
  1712. #define BONEDIR 0
  1713. #define BONESIDE 1
  1714. #define BONEUP 2
  1715. #define WORLDUP 2
  1716. #define PRINTMAT(m) \
  1717. printf("\n%f %f %f %f\n", m[0][0], m[0][1], m[0][2], m[0][3]); \
  1718. printf("%f %f %f %f\n", m[1][0], m[1][1], m[1][2], m[1][3]); \
  1719. printf("%f %f %f %f\n", m[2][0], m[2][1], m[2][2], m[2][3]); \
  1720. printf("%f %f %f %f\n", m[3][0], m[3][1], m[3][2], m[3][3]);
  1721. struct s_planeConstraint_t
  1722. {
  1723. char jointNameString[1024];
  1724. float floor;
  1725. int axis;
  1726. };
  1727. struct s_iksolve_t
  1728. {
  1729. char jointNameString[1024];
  1730. int reverseSolve;
  1731. float extremityScale;
  1732. Vector limbRootOffsetScale;
  1733. int doRelativeLock;
  1734. char relativeLockNameString[1024];
  1735. float relativeLockScale;
  1736. };
  1737. struct s_jointScale_t
  1738. {
  1739. char jointNameString[1024];
  1740. float scale;
  1741. };
  1742. struct s_template_t
  1743. {
  1744. char rootScaleJoint[1024];
  1745. float rootScaleAmount;
  1746. int numIKSolves;
  1747. s_iksolve_t *ikSolves[128];
  1748. int numJointScales;
  1749. s_jointScale_t *jointScales[128];
  1750. int numPlaneConstraints;
  1751. s_planeConstraint_t *planeConstraints[128];
  1752. float toeFloorZ;
  1753. int doSkeletonScale;
  1754. float skeletonScale;
  1755. };
  1756. //-----------------------------------------------------------------------------
  1757. // Load a template file into structure
  1758. //-----------------------------------------------------------------------------
  1759. s_template_t *New_Template()
  1760. {
  1761. s_template_t *pTemplate = (s_template_t *)kalloc(1, sizeof(s_template_t));
  1762. pTemplate->rootScaleAmount = 1.0;
  1763. pTemplate->numIKSolves = 0;
  1764. pTemplate->numJointScales = 0;
  1765. pTemplate->toeFloorZ = 2.802277;
  1766. pTemplate->numPlaneConstraints = 0;
  1767. pTemplate->doSkeletonScale = 0;
  1768. pTemplate->skeletonScale = 1.0;
  1769. return pTemplate;
  1770. }
  1771. s_iksolve_t *New_IKSolve()
  1772. {
  1773. s_iksolve_t *pIKSolve = (s_iksolve_t *)kalloc(1, sizeof(s_iksolve_t));
  1774. pIKSolve->reverseSolve = 0;
  1775. pIKSolve->extremityScale = 1.0;
  1776. pIKSolve->limbRootOffsetScale[0] = pIKSolve->limbRootOffsetScale[1] = pIKSolve->limbRootOffsetScale[2] = 0.0;
  1777. pIKSolve->doRelativeLock = 0;
  1778. pIKSolve->relativeLockScale = 1.0;
  1779. return pIKSolve;
  1780. }
  1781. s_planeConstraint_t *New_planeConstraint(float floor)
  1782. {
  1783. s_planeConstraint_t *pConstraint = (s_planeConstraint_t *)kalloc(1, sizeof(s_planeConstraint_t));
  1784. pConstraint->floor = floor;
  1785. pConstraint->axis = 2;
  1786. return pConstraint;
  1787. }
  1788. void Set_DefaultTemplate(s_template_t *pTemplate)
  1789. {
  1790. pTemplate->numJointScales = 0;
  1791. strcpy(pTemplate->rootScaleJoint, "ValveBiped.Bip01_L_Foot");
  1792. pTemplate->rootScaleAmount = 1.0;
  1793. pTemplate->numIKSolves = 4;
  1794. pTemplate->ikSolves[0] = New_IKSolve();
  1795. pTemplate->ikSolves[1] = New_IKSolve();
  1796. pTemplate->ikSolves[2] = New_IKSolve();
  1797. pTemplate->ikSolves[3] = New_IKSolve();
  1798. pTemplate->numPlaneConstraints = 2;
  1799. pTemplate->planeConstraints[0] = New_planeConstraint(pTemplate->toeFloorZ);
  1800. strcpy(pTemplate->planeConstraints[0]->jointNameString, "ValveBiped.Bip01_L_Toe0");
  1801. pTemplate->planeConstraints[1] = New_planeConstraint(pTemplate->toeFloorZ);
  1802. strcpy(pTemplate->planeConstraints[1]->jointNameString, "ValveBiped.Bip01_R_Toe0");
  1803. strcpy(pTemplate->ikSolves[0]->jointNameString, "ValveBiped.Bip01_L_Foot");
  1804. pTemplate->ikSolves[0]->reverseSolve = 0;
  1805. pTemplate->ikSolves[0]->extremityScale = 1.0;
  1806. pTemplate->ikSolves[0]->limbRootOffsetScale[0] = 1.0;
  1807. pTemplate->ikSolves[0]->limbRootOffsetScale[1] = 1.0;
  1808. pTemplate->ikSolves[0]->limbRootOffsetScale[2] = 0.0;
  1809. strcpy(pTemplate->ikSolves[1]->jointNameString, "ValveBiped.Bip01_R_Foot");
  1810. pTemplate->ikSolves[1]->reverseSolve = 0;
  1811. pTemplate->ikSolves[1]->extremityScale = 1.0;
  1812. pTemplate->ikSolves[1]->limbRootOffsetScale[0] = 1.0;
  1813. pTemplate->ikSolves[1]->limbRootOffsetScale[1] = 1.0;
  1814. pTemplate->ikSolves[1]->limbRootOffsetScale[2] = 0.0;
  1815. strcpy(pTemplate->ikSolves[2]->jointNameString, "ValveBiped.Bip01_R_Hand");
  1816. pTemplate->ikSolves[2]->reverseSolve = 1;
  1817. pTemplate->ikSolves[2]->extremityScale = 1.0;
  1818. pTemplate->ikSolves[2]->limbRootOffsetScale[0] = 0.0;
  1819. pTemplate->ikSolves[2]->limbRootOffsetScale[1] = 0.0;
  1820. pTemplate->ikSolves[2]->limbRootOffsetScale[2] = 1.0;
  1821. strcpy(pTemplate->ikSolves[3]->jointNameString, "ValveBiped.Bip01_L_Hand");
  1822. pTemplate->ikSolves[3]->reverseSolve = 1;
  1823. pTemplate->ikSolves[3]->extremityScale = 1.0;
  1824. pTemplate->ikSolves[3]->limbRootOffsetScale[0] = 0.0;
  1825. pTemplate->ikSolves[3]->limbRootOffsetScale[1] = 0.0;
  1826. pTemplate->ikSolves[3]->limbRootOffsetScale[2] = 1.0;
  1827. // pTemplate->ikSolves[3]->doRelativeLock = 1;
  1828. // strcpy(pTemplate->ikSolves[3]->relativeLockNameString, "ValveBiped.Bip01_R_Hand");
  1829. // pTemplate->ikSolves[3]->relativeLockScale = 1.0;
  1830. }
  1831. void split(char *str, char *sep, char **sp)
  1832. {
  1833. char *r = strtok(str, sep);
  1834. while(r != NULL)
  1835. {
  1836. *sp = r;
  1837. sp++;
  1838. r = strtok(NULL, sep);
  1839. }
  1840. *sp = NULL;
  1841. }
  1842. int checkCommand(char *str, char *cmd, int numOptions, int numSplit)
  1843. {
  1844. if(strcmp(str, cmd) == 0)
  1845. {
  1846. if(numOptions <= numSplit)
  1847. return 1;
  1848. else
  1849. {
  1850. printf("Error: Number or argument mismatch in template file cmd %s, requires %i, found %i\n", cmd, numOptions, numSplit);
  1851. return 0;
  1852. }
  1853. }
  1854. return 0;
  1855. }
  1856. s_template_t *Load_Template(char *name )
  1857. {
  1858. // Sanity check file and init
  1859. Assert(name);
  1860. s_template_t *pTemplate = New_Template();
  1861. // Open file
  1862. if (!OpenGlobalFile( name ))
  1863. return 0;
  1864. //March through lines
  1865. g_iLinecount = 0;
  1866. while(fgets( g_szLine, sizeof( g_szLine ), g_fpInput ) != NULL)
  1867. {
  1868. g_iLinecount++;
  1869. if(g_szLine[0] == '#')
  1870. continue;
  1871. char *endP = strrchr(g_szLine, '\n');
  1872. if(endP != NULL)
  1873. *endP = '\0';
  1874. char *sp[128];
  1875. char **spp = sp;
  1876. char sep[] = " ";
  1877. split(g_szLine, sep, sp);
  1878. int numSplit = 0;
  1879. while(*spp != NULL)
  1880. {
  1881. spp++;
  1882. numSplit++;
  1883. }
  1884. if(numSplit < 1 ||
  1885. *sp[0] == '\n')
  1886. continue;
  1887. // int numRead = sscanf( g_szLine, "%s %s %s", cmd, &option, &option2 );
  1888. // // Blank line
  1889. // if ((numRead == EOF) || (numRead == 0))
  1890. // continue;
  1891. // commands
  1892. char *cmd;
  1893. int numOptions = numSplit - 1;
  1894. cmd = sp[0];
  1895. if(checkCommand(cmd, "twoJointIKSolve", 1, numOptions))
  1896. {
  1897. printf("\nCreating two joint IK solve %s\n", sp[1]);
  1898. pTemplate->ikSolves[pTemplate->numIKSolves] = New_IKSolve();
  1899. strcpy(pTemplate->ikSolves[pTemplate->numIKSolves]->jointNameString, sp[1]);
  1900. pTemplate->numIKSolves++;
  1901. }
  1902. else if(checkCommand(cmd, "oneJointPlaneConstraint", 1, numOptions))
  1903. {
  1904. printf("\nCreating one joint plane constraint %s\n", sp[1]);
  1905. pTemplate->planeConstraints[pTemplate->numPlaneConstraints] = New_planeConstraint(pTemplate->toeFloorZ);
  1906. strcpy(pTemplate->planeConstraints[pTemplate->numPlaneConstraints]->jointNameString, sp[1]);
  1907. pTemplate->numPlaneConstraints++;
  1908. }
  1909. else if(checkCommand(cmd, "reverseSolve", 1, numOptions))
  1910. {
  1911. printf("reverseSolve: %s\n", sp[1]);
  1912. pTemplate->ikSolves[pTemplate->numIKSolves - 1]->reverseSolve = atoi(sp[1]);
  1913. }
  1914. else if(checkCommand(cmd, "extremityScale", 1, numOptions))
  1915. {
  1916. printf("extremityScale: %s\n", sp[1]);
  1917. pTemplate->ikSolves[pTemplate->numIKSolves - 1]->extremityScale = atof(sp[1]);
  1918. }
  1919. else if(checkCommand(cmd, "limbRootOffsetScale", 3, numOptions))
  1920. {
  1921. printf("limbRootOffsetScale: %s %s %s\n", sp[1], sp[2], sp[3]);
  1922. pTemplate->ikSolves[pTemplate->numIKSolves - 1]->limbRootOffsetScale[0] = atof(sp[1]);
  1923. pTemplate->ikSolves[pTemplate->numIKSolves - 1]->limbRootOffsetScale[1] = atof(sp[2]);
  1924. pTemplate->ikSolves[pTemplate->numIKSolves - 1]->limbRootOffsetScale[2] = atof(sp[3]);
  1925. }
  1926. else if(checkCommand(cmd, "toeFloorZ", 1, numOptions))
  1927. {
  1928. printf("toeFloorZ: %s\n", sp[1]);
  1929. pTemplate->toeFloorZ = atof(sp[1]);
  1930. }
  1931. else if(checkCommand(cmd, "relativeLock", 2, numOptions))
  1932. {
  1933. printf("relativeLock: %s\n", sp[1]);
  1934. pTemplate->ikSolves[pTemplate->numIKSolves - 1]->doRelativeLock = 1;
  1935. strcpy(pTemplate->ikSolves[pTemplate->numIKSolves - 1]->relativeLockNameString, sp[1]);
  1936. pTemplate->ikSolves[pTemplate->numIKSolves - 1]->relativeLockScale = atof(sp[2]);
  1937. }
  1938. else if(checkCommand(cmd, "rootScaleJoint", 1, numOptions))
  1939. {
  1940. printf("\nrootScaleJoint: %s\n", sp[1]);
  1941. strcpy(pTemplate->rootScaleJoint, sp[1]);
  1942. }
  1943. else if(checkCommand(cmd, "rootScaleAmount", 1, numOptions))
  1944. {
  1945. printf("rootScaleAmount: %s\n", sp[1]);
  1946. pTemplate->rootScaleAmount = atof(sp[1]);
  1947. }
  1948. else if(checkCommand(cmd, "jointScale", 2, numOptions))
  1949. {
  1950. printf("\nCreating joint scale %s of %s\n", sp[1], sp[2]);
  1951. pTemplate->jointScales[pTemplate->numJointScales] = (s_jointScale_t *)kalloc(1, sizeof(s_jointScale_t));
  1952. strcpy(pTemplate->jointScales[pTemplate->numJointScales]->jointNameString, sp[1]);
  1953. pTemplate->jointScales[pTemplate->numJointScales]->scale = atof(sp[2]);
  1954. pTemplate->numJointScales++;
  1955. }
  1956. else if(checkCommand(cmd, "skeletonScale", 2, numOptions))
  1957. {
  1958. printf("\nCreating skeleton scale of %s\n", sp[1]);
  1959. pTemplate->doSkeletonScale = 1;
  1960. pTemplate->skeletonScale = atof(sp[1]);
  1961. }
  1962. else
  1963. {
  1964. MdlWarning("unknown studio command\n" );
  1965. }
  1966. }
  1967. fclose( g_fpInput );
  1968. return pTemplate;
  1969. }
  1970. //-----------------------------------------------------------------------------
  1971. // get node index from node string name
  1972. //-----------------------------------------------------------------------------
  1973. int GetNodeIndex(s_source_t *psource, char *nodeName)
  1974. {
  1975. for(int i = 0; i < psource->numbones; i++)
  1976. {
  1977. if(strcmp(nodeName, psource->localBone[i].name) == 0)
  1978. {
  1979. return i;
  1980. }
  1981. }
  1982. return -1;
  1983. }
  1984. //-----------------------------------------------------------------------------
  1985. // get node index from node string name
  1986. //-----------------------------------------------------------------------------
  1987. void GetNodePath(s_source_t *psource, int startIndex, int endIndex, int *path)
  1988. {
  1989. *path = endIndex;
  1990. s_node_t *nodes;
  1991. nodes = psource->localBone;
  1992. while(*path != startIndex)
  1993. {
  1994. int parent = nodes[*path].parent;
  1995. path++;
  1996. *path = parent;
  1997. }
  1998. path++;
  1999. *path = -1;
  2000. }
  2001. void SumBonePathTranslations(int *indexPath, s_bone_t *boneArray, Vector &resultVector, int rootOffset = 0)
  2002. {
  2003. // walk the path
  2004. int *pathPtr = indexPath;
  2005. // M_matrix4x4_t matrixCum;
  2006. // find length of path
  2007. int length = 0;
  2008. while(*pathPtr != -1)
  2009. {
  2010. length++;
  2011. pathPtr++;
  2012. }
  2013. int l = length - (1 + rootOffset);
  2014. resultVector[0] = 0.0;
  2015. resultVector[1] = 0.0;
  2016. resultVector[2] = 0.0;
  2017. for(int i = l; i > -1; i--)
  2018. {
  2019. s_bone_t *thisBone = boneArray + indexPath[i];
  2020. resultVector += thisBone->pos;
  2021. }
  2022. }
  2023. void CatBonePath(int *indexPath, s_bone_t *boneArray, M_matrix4x4_t &resultMatrix, int rootOffset = 0)
  2024. {
  2025. // walk the path
  2026. int *pathPtr = indexPath;
  2027. // M_matrix4x4_t matrixCum;
  2028. // find length of path
  2029. int length = 0;
  2030. while(*pathPtr != -1)
  2031. {
  2032. length++;
  2033. pathPtr++;
  2034. }
  2035. int l = length - (1 + rootOffset);
  2036. for(int i = l; i > -1; i--)
  2037. {
  2038. s_bone_t *thisBone = boneArray + indexPath[i];
  2039. // printf("bone index: %i %i\n", i, indexPath[i]);
  2040. // printf("pos: %f %f %f, rot: %f %f %f\n", thisBone->pos.x, thisBone->pos.y, thisBone->pos.z, thisBone->rot.x, thisBone->rot.y, thisBone->rot.z);
  2041. M_matrix4x4_t thisMatrix;
  2042. M_AngleMatrix(thisBone->rot, thisBone->pos, thisMatrix);
  2043. // PRINTMAT(thisMatrix)
  2044. M_matrix4x4_t tempCum;
  2045. M_MatrixCopy(resultMatrix, tempCum);
  2046. M_ConcatTransforms(thisMatrix, tempCum, resultMatrix);
  2047. }
  2048. // PRINTMAT(matrixCum);
  2049. // M_MatrixAngles(matrixCum, resultBone.rot, resultBone.pos);
  2050. // printf("pos: %f %f %f, rot: %f %f %f\n", resultBone.pos.x,resultBone.pos.y, resultBone.pos.z, RAD2DEG(resultBone.rot.x),RAD2DEG(resultBone.rot.y),RAD2DEG(resultBone.rot.z));
  2051. }
  2052. // int ConformSources(s_source_t *pSource, s_source_t *pTarget)
  2053. // {
  2054. // if(pSource->numbones != *pTarget->numbones)
  2055. // {
  2056. // printf("ERROR: The number of bones in the target file must match the source file.");
  2057. // return 1;
  2058. // }
  2059. // if(pSource->numframes != pTarget->numframes)
  2060. // {
  2061. // printf("Note: Source and target frame lengths do not match");
  2062. // for(int t = 0; t < pTarget->numframes; t++)
  2063. // {
  2064. // free(pTarget->rawanim[t]);
  2065. // }
  2066. // pTarget->numframes = pSource->numframes;
  2067. // int size = pTarget->numbones * sizeof( s_bone_t );
  2068. // for(t = 0; t < pTarget->numframes; t++)
  2069. // {
  2070. // pTarget->rawanim[t] = (s_bone_t *) kalloc(1, size);
  2071. // memcpy((void *) pSource->rawanim[t], (void *) pTarget->rawanim[t], size
  2072. // }
  2073. // }
  2074. // pTarget->startframe = pSource->startframe;
  2075. // pTarget->endframe = pSource->endframe;
  2076. void ScaleJointsFrame(s_source_t *pSkeleton, s_jointScale_t *jointScale, int t)
  2077. {
  2078. int numBones = pSkeleton->numbones;
  2079. for(int i = 0; i < numBones; i++)
  2080. {
  2081. s_node_t pNode = pSkeleton->localBone[i];
  2082. s_bone_t *pSkelBone = &pSkeleton->rawanim[t][i];
  2083. if(strcmp(jointScale->jointNameString, pNode.name) == 0)
  2084. {
  2085. // printf("Scaling joint %s\n", pNode.name);
  2086. pSkelBone->pos = pSkelBone->pos * jointScale->scale;
  2087. }
  2088. }
  2089. }
  2090. void ScaleJoints(s_source_t *pSkeleton, s_jointScale_t *jointScale)
  2091. {
  2092. int numFrames = pSkeleton->numframes;
  2093. for(int t = 0; t < numFrames; t++)
  2094. {
  2095. ScaleJointsFrame(pSkeleton, jointScale, t);
  2096. }
  2097. }
  2098. void ScaleSkeletonFrame(s_source_t *pSkeleton, float scale, int t)
  2099. {
  2100. int numBones = pSkeleton->numbones;
  2101. for(int i = 0; i < numBones; i++)
  2102. {
  2103. s_bone_t *pSkelBone = &pSkeleton->rawanim[t][i];
  2104. pSkelBone->pos = pSkelBone->pos * scale;
  2105. }
  2106. }
  2107. void ScaleSkeleton(s_source_t *pSkeleton, float scale)
  2108. {
  2109. int numFrames = pSkeleton->numframes;
  2110. for(int t = 0; t < numFrames; t++)
  2111. {
  2112. ScaleSkeletonFrame(pSkeleton, scale, t);
  2113. }
  2114. }
  2115. void CombineSkeletonAnimationFrame(s_source_t *pSkeleton, s_source_t *pAnimation, s_bone_t **ppAnim, int t)
  2116. {
  2117. int numBones = pAnimation->numbones;
  2118. int size = numBones * sizeof( s_bone_t );
  2119. ppAnim[t] = (s_bone_t *) kalloc(1, size);
  2120. for(int i = 0; i < numBones; i++)
  2121. {
  2122. s_node_t pNode = pAnimation->localBone[i];
  2123. s_bone_t pAnimBone = pAnimation->rawanim[t][i];
  2124. if(pNode.parent > -1)
  2125. {
  2126. if ( i < pSkeleton->numbones )
  2127. {
  2128. s_bone_t pSkelBone = pSkeleton->rawanim[0][i];
  2129. ppAnim[t][i].pos = pSkelBone.pos;
  2130. }
  2131. else
  2132. {
  2133. if ( !g_bGaveMissingBoneWarning )
  2134. {
  2135. g_bGaveMissingBoneWarning = true;
  2136. Warning( "Warning: Target skeleton has less bones than source animation. Reverting to source data for extra bones.\n" );
  2137. }
  2138. ppAnim[t][i].pos = pAnimBone.pos;
  2139. }
  2140. }
  2141. else
  2142. {
  2143. ppAnim[t][i].pos = pAnimBone.pos;
  2144. }
  2145. ppAnim[t][i].rot = pAnimBone.rot;
  2146. }
  2147. }
  2148. void CombineSkeletonAnimation(s_source_t *pSkeleton, s_source_t *pAnimation, s_bone_t **ppAnim)
  2149. {
  2150. int numFrames = pAnimation->numframes;
  2151. for(int t = 0; t < numFrames; t++)
  2152. {
  2153. CombineSkeletonAnimationFrame(pSkeleton, pAnimation, ppAnim, t);
  2154. }
  2155. }
  2156. //--------------------------------------------------------------------
  2157. // MotionMap
  2158. //--------------------------------------------------------------------
  2159. s_source_t *MotionMap( s_source_t *pSource, s_source_t *pTarget, s_template_t *pTemplate )
  2160. {
  2161. // scale skeleton
  2162. if(pTemplate->doSkeletonScale)
  2163. {
  2164. ScaleSkeleton(pTarget, pTemplate->skeletonScale);
  2165. }
  2166. // scale joints
  2167. for(int j = 0; j < pTemplate->numJointScales; j++)
  2168. {
  2169. s_jointScale_t *pJointScale = pTemplate->jointScales[j];
  2170. ScaleJoints(pTarget, pJointScale);
  2171. }
  2172. // root stuff
  2173. char rootString[128] = "ValveBiped.Bip01";
  2174. // !!! PARAMETER
  2175. int rootIndex = GetNodeIndex(pSource, rootString);
  2176. int rootScaleIndex = GetNodeIndex(pSource, pTemplate->rootScaleJoint);
  2177. int rootScalePath[512];
  2178. if(rootScaleIndex > -1)
  2179. {
  2180. GetNodePath(pSource, rootIndex, rootScaleIndex, rootScalePath);
  2181. }
  2182. else
  2183. {
  2184. printf("Error: Can't find node\n");
  2185. exit(0);
  2186. }
  2187. float rootScaleLengthSrc = pSource->rawanim[0][rootScaleIndex].pos[BONEDIR];
  2188. float rootScaleParentLengthSrc = pSource->rawanim[0][rootScalePath[1]].pos[BONEDIR];
  2189. float rootScaleSrc = rootScaleLengthSrc + rootScaleParentLengthSrc;
  2190. float rootScaleLengthTgt = pTarget->rawanim[0][rootScaleIndex].pos[BONEDIR];
  2191. float rootScaleParentLengthTgt = pTarget->rawanim[0][rootScalePath[1]].pos[BONEDIR];
  2192. float rootScaleTgt = rootScaleLengthTgt + rootScaleParentLengthTgt;
  2193. float rootScaleFactor = rootScaleTgt / rootScaleSrc;
  2194. if(g_verbose)
  2195. printf("Root Scale Factor: %f\n", rootScaleFactor);
  2196. // root scale origin
  2197. float toeFloorZ = pTemplate->toeFloorZ;
  2198. Vector rootScaleOrigin = pSource->rawanim[0][rootIndex].pos;
  2199. rootScaleOrigin[2] = toeFloorZ;
  2200. // setup workspace
  2201. s_bone_t *combinedRefAnimation[MAXSTUDIOANIMFRAMES];
  2202. s_bone_t *combinedAnimation[MAXSTUDIOANIMFRAMES];
  2203. s_bone_t *sourceAnimation[MAXSTUDIOANIMFRAMES];
  2204. CombineSkeletonAnimation(pTarget, pSource, combinedAnimation);
  2205. CombineSkeletonAnimation(pTarget, pSource, combinedRefAnimation);
  2206. // do source and target sanity checking
  2207. int sourceNumFrames = pSource->numframes;
  2208. // iterate through limb solves
  2209. for(int t = 0; t < sourceNumFrames; t++)
  2210. {
  2211. // setup pTarget for skeleton comparison
  2212. pTarget->rawanim[t] = combinedRefAnimation[t];
  2213. printf("Note: Processing frame: %i\n", t);
  2214. for(int ii = 0; ii < pTemplate->numIKSolves; ii++)
  2215. {
  2216. s_iksolve_t *thisSolve = pTemplate->ikSolves[ii];
  2217. char *thisJointNameString = thisSolve->jointNameString;
  2218. int thisJointIndex = GetNodeIndex(pSource, thisJointNameString);
  2219. // init paths to feet
  2220. int thisJointPathInRoot[512];
  2221. // get paths to feet
  2222. if(thisJointIndex > -1)
  2223. {
  2224. GetNodePath(pSource, rootIndex, thisJointIndex, thisJointPathInRoot);
  2225. }
  2226. else
  2227. {
  2228. printf("Error: Can't find node: %s\n" , thisJointNameString);
  2229. exit(0);
  2230. }
  2231. // leg "root" or thigh pointers
  2232. //int gParentIndex = thisJointPathInRoot[2];
  2233. int *gParentPath = thisJointPathInRoot + 2;
  2234. //----------------------------------------------------------------
  2235. // get limb lengths
  2236. //----------------------------------------------------------------
  2237. float thisJointLengthSrc = pSource->rawanim[0][thisJointIndex].pos[BONEDIR];
  2238. float parentJointLengthSrc = pSource->rawanim[0][thisJointPathInRoot[1]].pos[BONEDIR];
  2239. float thisLimbLengthSrc = thisJointLengthSrc + parentJointLengthSrc;
  2240. float thisJointLengthTgt = pTarget->rawanim[0][thisJointIndex].pos[BONEDIR];
  2241. float parentJointLengthTgt = pTarget->rawanim[0][thisJointPathInRoot[1]].pos[BONEDIR];
  2242. float thisLimbLengthTgt = thisJointLengthTgt + parentJointLengthTgt;
  2243. // Factor leg length delta
  2244. float thisLimbLength = thisLimbLengthSrc - thisLimbLengthTgt;
  2245. float thisLimbLengthFactor = thisLimbLengthTgt / thisLimbLengthSrc;
  2246. if(g_verbose)
  2247. printf("limb length %s: %i: %f, factor %f\n", thisJointNameString, thisJointIndex, thisLimbLength, thisLimbLengthFactor);
  2248. // calculate joint grandparent offset
  2249. // Note: because there's no reference pose this doesn't take rotation into account.
  2250. // This only works because of the assumption that joint translations aren't animated.
  2251. M_matrix4x4_t gParentGlobalMatSrc, gParentGlobalMatTgt;
  2252. Vector gParentGlobalSrc, gParentGlobalTgt;
  2253. // SumBonePathTranslations(gParentPath, pSource->rawanim[t], gParentGlobalSrc, 1);
  2254. // SumBonePathTranslations(gParentPath, pTarget->rawanim[t], gParentGlobalTgt, 1);
  2255. // get root path to source parent
  2256. CatBonePath(gParentPath, pSource->rawanim[t], gParentGlobalMatSrc, 1);
  2257. // check against reference animation
  2258. CatBonePath(gParentPath, pTarget->rawanim[t], gParentGlobalMatTgt, 1);
  2259. gParentGlobalSrc[0] = gParentGlobalMatSrc[3][0];
  2260. gParentGlobalSrc[1] = gParentGlobalMatSrc[3][1];
  2261. gParentGlobalSrc[2] = gParentGlobalMatSrc[3][2];
  2262. gParentGlobalTgt[0] = gParentGlobalMatTgt[3][0];
  2263. gParentGlobalTgt[1] = gParentGlobalMatTgt[3][1];
  2264. gParentGlobalTgt[2] = gParentGlobalMatTgt[3][2];
  2265. Vector gParentDelta(gParentGlobalTgt - gParentGlobalSrc);
  2266. if(g_verbose)
  2267. printf("Grand parent delta: %f %f %f\n", gParentDelta[0], gParentDelta[1], gParentDelta[2]);
  2268. gParentDelta *= thisSolve->limbRootOffsetScale;
  2269. //----------------------------------------------------------------
  2270. // time takes effect here
  2271. // above waste is unavoidable?
  2272. //----------------------------------------------------------------
  2273. M_matrix4x4_t rootMat;
  2274. M_AngleMatrix(pSource->rawanim[t][rootIndex].rot, pSource->rawanim[t][rootIndex].pos, rootMat);
  2275. // OK, time to get it together
  2276. // 1) scale foot by legLengthFactor in the non-translated thigh space
  2277. // 2) translate foot by legRootDelta in the space of the root
  2278. // do we leave everything in the space of the root then? PROBABLY!!
  2279. M_matrix4x4_t thisJointMat, parentJointMat, thisJointInGParentMat;
  2280. M_AngleMatrix(pSource->rawanim[t][thisJointPathInRoot[0]].rot, pSource->rawanim[t][thisJointPathInRoot[0]].pos, thisJointMat);
  2281. M_AngleMatrix(pSource->rawanim[t][thisJointPathInRoot[1]].rot, pSource->rawanim[t][thisJointPathInRoot[1]].pos, parentJointMat);
  2282. M_ConcatTransforms(thisJointMat, parentJointMat, thisJointInGParentMat);
  2283. if(!thisSolve->doRelativeLock)
  2284. {
  2285. // scale around grand parent
  2286. float effectiveScaleFactor = ((thisLimbLengthFactor - 1.0) * thisSolve->extremityScale ) + 1.0;
  2287. thisJointInGParentMat[3][0] *= effectiveScaleFactor;
  2288. thisJointInGParentMat[3][1] *= effectiveScaleFactor;
  2289. thisJointInGParentMat[3][2] *= effectiveScaleFactor;
  2290. }
  2291. // adjust into source root space
  2292. M_matrix4x4_t gParentInRootMat, thisJointInRootMat;
  2293. CatBonePath(gParentPath, pSource->rawanim[t], gParentInRootMat, 1);
  2294. M_ConcatTransforms(thisJointInGParentMat, gParentInRootMat, thisJointInRootMat);
  2295. if(!thisSolve->doRelativeLock)
  2296. {
  2297. // adjust by difference of local root
  2298. thisJointInRootMat[3][0] += gParentDelta[0];
  2299. thisJointInRootMat[3][1] += gParentDelta[1];
  2300. thisJointInRootMat[3][2] += gParentDelta[2];
  2301. }
  2302. else
  2303. {
  2304. char *relativeJointNameString = thisSolve->relativeLockNameString;
  2305. int relativeJointIndex = GetNodeIndex(pSource, relativeJointNameString);
  2306. // init paths to feet
  2307. int relativeJointPathInRoot[512];
  2308. // get paths to feet
  2309. if(relativeJointIndex > -1)
  2310. {
  2311. GetNodePath(pSource, rootIndex, relativeJointIndex, relativeJointPathInRoot);
  2312. }
  2313. else
  2314. {
  2315. printf("Error: Can't find node: %s\n" , relativeJointNameString);
  2316. exit(0);
  2317. }
  2318. // get the source relative joint
  2319. M_matrix4x4_t relativeJointInRootMatSrc, relativeJointInRootMatSrcInverse, thisJointInRelativeSrcMat;
  2320. CatBonePath(relativeJointPathInRoot, pSource->rawanim[t], relativeJointInRootMatSrc, 1);
  2321. M_MatrixInvert(relativeJointInRootMatSrc, relativeJointInRootMatSrcInverse);
  2322. M_ConcatTransforms(thisJointInRootMat, relativeJointInRootMatSrcInverse, thisJointInRelativeSrcMat);
  2323. if(thisSolve->relativeLockScale != 1.0)
  2324. {
  2325. thisJointInRelativeSrcMat[3][0] *= thisSolve->relativeLockScale;
  2326. thisJointInRelativeSrcMat[3][1] *= thisSolve->relativeLockScale;
  2327. thisJointInRelativeSrcMat[3][2] *= thisSolve->relativeLockScale;
  2328. }
  2329. // swap momentarily to get new destination
  2330. // NOTE: the relative lock must have already been solved
  2331. sourceAnimation[t] = pSource->rawanim[t];
  2332. pSource->rawanim[t] = combinedAnimation[t];
  2333. // get new relative location
  2334. M_matrix4x4_t relativeJointInRootMatTgt;
  2335. CatBonePath(relativeJointPathInRoot, pSource->rawanim[t], relativeJointInRootMatTgt, 1);
  2336. M_ConcatTransforms(thisJointInRelativeSrcMat, relativeJointInRootMatTgt, thisJointInRootMat);
  2337. // swap back just for cleanliness
  2338. // a little overkill as it's just swapped
  2339. // just leaving it here for clarity
  2340. combinedAnimation[t] = pSource->rawanim[t];
  2341. pSource->rawanim[t] = sourceAnimation[t];
  2342. }
  2343. //----------------------------------------------------------------
  2344. // swap animation
  2345. //----------------------------------------------------------------
  2346. sourceAnimation[t] = pSource->rawanim[t];
  2347. pSource->rawanim[t] = combinedAnimation[t];
  2348. //----------------------------------------------------------------
  2349. // make thigh data global based on new skeleton
  2350. //----------------------------------------------------------------
  2351. // get thigh in global space
  2352. M_matrix4x4_t gParentInTgtRootMat, ggParentInTgtRootMat;
  2353. // int *gParentPath = thisJointPathInRoot + 2;
  2354. CatBonePath(gParentPath, pSource->rawanim[t], gParentInTgtRootMat, 1);
  2355. CatBonePath(gParentPath+1, pSource->rawanim[t], ggParentInTgtRootMat, 1);
  2356. //----------------------------------------------------------------
  2357. // Calculate IK for legs
  2358. //----------------------------------------------------------------
  2359. float parentJointLength = pSource->rawanim[t][*(thisJointPathInRoot + 1)].pos[BONEDIR];
  2360. float thisJointLength = pSource->rawanim[t][thisJointIndex].pos[BONEDIR];
  2361. Vector thisLimbHypot;
  2362. thisLimbHypot[0] = thisJointInRootMat[3][0] - gParentInTgtRootMat[3][0];
  2363. thisLimbHypot[1] = thisJointInRootMat[3][1] - gParentInTgtRootMat[3][1];
  2364. thisLimbHypot[2] = thisJointInRootMat[3][2] - gParentInTgtRootMat[3][2];
  2365. float thisLimbHypotLength = thisLimbHypot.Length();
  2366. // law of cosines!
  2367. float gParentCos = (thisLimbHypotLength*thisLimbHypotLength + parentJointLength*parentJointLength - thisJointLength*thisJointLength) / (2*parentJointLength*thisLimbHypotLength);
  2368. float parentCos = (parentJointLength*parentJointLength + thisJointLength*thisJointLength - thisLimbHypotLength*thisLimbHypotLength) / (2*parentJointLength*thisJointLength);
  2369. VectorNormalize(thisLimbHypot);
  2370. Vector thisLimbHypotUnit = thisLimbHypot;
  2371. M_matrix4x4_t gParentJointIKMat;
  2372. Vector gParentJointIKRot, gParentJointIKOrth;
  2373. gParentJointIKRot[0] = gParentInTgtRootMat[BONEUP][0];
  2374. gParentJointIKRot[1] = gParentInTgtRootMat[BONEUP][1];
  2375. gParentJointIKRot[2] = gParentInTgtRootMat[BONEUP][2];
  2376. VectorNormalize(gParentJointIKRot);
  2377. gParentJointIKOrth = gParentJointIKRot.Cross(thisLimbHypotUnit);
  2378. VectorNormalize(gParentJointIKOrth);
  2379. gParentJointIKRot = thisLimbHypotUnit.Cross(gParentJointIKOrth);
  2380. VectorNormalize(gParentJointIKRot);
  2381. M_MatrixCopy(gParentInTgtRootMat, gParentJointIKMat);
  2382. gParentJointIKMat[0][0] = thisLimbHypotUnit[0];
  2383. gParentJointIKMat[0][1] = thisLimbHypotUnit[1];
  2384. gParentJointIKMat[0][2] = thisLimbHypotUnit[2];
  2385. gParentJointIKMat[1][0] = gParentJointIKOrth[0];
  2386. gParentJointIKMat[1][1] = gParentJointIKOrth[1];
  2387. gParentJointIKMat[1][2] = gParentJointIKOrth[2];
  2388. gParentJointIKMat[2][0] = gParentJointIKRot[0];
  2389. gParentJointIKMat[2][1] = gParentJointIKRot[1];
  2390. gParentJointIKMat[2][2] = gParentJointIKRot[2];
  2391. M_matrix4x4_t gParentJointIKRotMat, gParentJointResultMat;
  2392. float gParentDeg;
  2393. if(thisSolve->reverseSolve)
  2394. {
  2395. gParentDeg = acos(gParentCos);
  2396. }
  2397. else
  2398. {
  2399. gParentDeg = -acos(gParentCos);
  2400. }
  2401. // sanity check limb length
  2402. if(thisLimbHypotLength < thisLimbLengthTgt)
  2403. {
  2404. M_RotateZMatrix(gParentDeg, gParentJointIKRotMat);
  2405. }
  2406. M_ConcatTransforms(gParentJointIKRotMat, gParentJointIKMat, gParentJointResultMat);
  2407. M_matrix4x4_t parentJointIKRotMat;
  2408. //!!! shouldn't need the 180 degree addition, something in the law of cosines!!!
  2409. float parentDeg;
  2410. if(thisSolve->reverseSolve)
  2411. {
  2412. parentDeg = acos(parentCos)+M_PI;
  2413. }
  2414. else
  2415. {
  2416. parentDeg = -acos(parentCos)+M_PI;
  2417. }
  2418. // sanity check limb length
  2419. if(thisLimbHypotLength < thisLimbLengthTgt)
  2420. {
  2421. M_RotateZMatrix(parentDeg, parentJointIKRotMat);
  2422. }
  2423. // Thighs
  2424. M_matrix4x4_t ggParentInTgtRootMatInverse, gParentJointLocalMat;
  2425. M_MatrixInvert(ggParentInTgtRootMat, ggParentInTgtRootMatInverse);
  2426. M_ConcatTransforms(gParentJointResultMat, ggParentInTgtRootMatInverse, gParentJointLocalMat);
  2427. s_bone_t resultBone;
  2428. // temp test stuff
  2429. // M_MatrixAngles(thisJointInRootMat, resultBone.rot, resultBone.pos);
  2430. // pSource->rawanim[t][thisJointIndex].rot = resultBone.rot;
  2431. // pSource->rawanim[t][thisJointIndex].pos = resultBone.pos;
  2432. // M_MatrixAngles(gParentInTgtRootMat, resultBone.rot, resultBone.pos);
  2433. // pSource->rawanim[t][gParentIndex].rot = resultBone.rot;
  2434. // pSource->rawanim[t][gParentIndex].pos = resultBone.pos;
  2435. M_MatrixAngles(gParentJointLocalMat, resultBone.rot, resultBone.pos);
  2436. pSource->rawanim[t][*gParentPath].pos = resultBone.pos;
  2437. pSource->rawanim[t][*gParentPath].rot = resultBone.rot;
  2438. M_MatrixAngles(parentJointIKRotMat, resultBone.rot, resultBone.pos);
  2439. pSource->rawanim[t][*(thisJointPathInRoot+1)].rot = resultBone.rot;
  2440. M_matrix4x4_t parentJointGlobalMat, parentJointGlobalMatInverse, thisJointLocalMat;
  2441. CatBonePath(thisJointPathInRoot+1, pSource->rawanim[t], parentJointGlobalMat, 1);
  2442. M_MatrixInvert(parentJointGlobalMat, parentJointGlobalMatInverse);
  2443. M_ConcatTransforms(thisJointInRootMat, parentJointGlobalMatInverse, thisJointLocalMat);
  2444. M_MatrixAngles(thisJointLocalMat, resultBone.rot, resultBone.pos);
  2445. pSource->rawanim[t][thisJointIndex].rot = resultBone.rot;
  2446. // swap animation back for next solve
  2447. combinedAnimation[t] = pSource->rawanim[t];
  2448. pSource->rawanim[t] = sourceAnimation[t];
  2449. }
  2450. // swap animation
  2451. sourceAnimation[t] = pSource->rawanim[t];
  2452. pSource->rawanim[t] = combinedAnimation[t];
  2453. //----------------------------------------------------------------
  2454. // adjust root
  2455. //----------------------------------------------------------------
  2456. Vector originBonePos = pSource->rawanim[t][rootIndex].pos;
  2457. Vector rootInScaleOrigin = originBonePos - rootScaleOrigin;
  2458. float effectiveRootScale = ((rootScaleFactor - 1.0) * pTemplate->rootScaleAmount) + 1.0;
  2459. Vector scaledRoot = rootInScaleOrigin * effectiveRootScale;
  2460. pSource->rawanim[t][rootIndex].pos = rootScaleOrigin + scaledRoot;
  2461. //------------------------------------------------------------
  2462. // plane constraints
  2463. //------------------------------------------------------------
  2464. for(int ii = 0; ii < pTemplate->numPlaneConstraints; ii++)
  2465. {
  2466. s_planeConstraint_t *thisSolve = pTemplate->planeConstraints[ii];
  2467. char *thisJointNameString = thisSolve->jointNameString;
  2468. if(g_verbose)
  2469. printf("Executing plane constraint: %s\n", thisJointNameString);
  2470. int thisJointIndex = GetNodeIndex(pSource, thisJointNameString);
  2471. // init paths to feet
  2472. int thisJointPath[512];
  2473. // get paths to feet
  2474. if(thisJointIndex > -1)
  2475. {
  2476. GetNodePath(pSource, -1, thisJointIndex, thisJointPath);
  2477. }
  2478. else
  2479. {
  2480. printf("Error: Can't find node: %s\n" , thisJointNameString);
  2481. exit(0);
  2482. }
  2483. int parentIndex = thisJointPath[1];
  2484. int *parentPath = thisJointPath + 1;
  2485. M_matrix4x4_t thisJointGlobalMat, parentJointGlobalMat, gParentJointGlobalMat, gParentJointGlobalMatInverse;
  2486. CatBonePath(thisJointPath, pSource->rawanim[t], thisJointGlobalMat, 0);
  2487. CatBonePath(parentPath, pSource->rawanim[t], parentJointGlobalMat, 0);
  2488. CatBonePath(parentPath+1, pSource->rawanim[t], gParentJointGlobalMat, 0);
  2489. M_MatrixInvert(gParentJointGlobalMat, gParentJointGlobalMatInverse);
  2490. if(thisJointGlobalMat[3][thisSolve->axis] < thisSolve->floor)
  2491. {
  2492. // printf("-- broken plane: %f\n", thisJointGlobalMat[3][thisSolve->axis]);
  2493. if(parentJointGlobalMat[3][thisSolve->axis] < thisSolve->floor)
  2494. {
  2495. printf("Error: Constraint parent has broken the plane, this frame's plane constraint unsolvable!\n");
  2496. }
  2497. else
  2498. {
  2499. Vector parentJointAtPlane(parentJointGlobalMat[3][0], parentJointGlobalMat[3][1], parentJointGlobalMat[3][2]);
  2500. Vector parentPos(parentJointGlobalMat[3][0], parentJointGlobalMat[3][1], parentJointGlobalMat[3][2]);
  2501. Vector thisJointAtPlane(thisJointGlobalMat[3][0], thisJointGlobalMat[3][1], thisJointGlobalMat[3][2]);
  2502. Vector thisJointPos(thisJointGlobalMat[3][0], thisJointGlobalMat[3][1], thisJointGlobalMat[3][2]);
  2503. thisJointAtPlane[thisSolve->axis] = thisSolve->floor;
  2504. parentJointAtPlane[thisSolve->axis] = thisSolve->floor;
  2505. float thisJointLength = pSource->rawanim[t][thisJointIndex].pos[BONEAXIS];
  2506. float parentLengthToPlane = parentPos[thisSolve->axis] - thisSolve->floor;
  2507. float adjacent = sqrtf((thisJointLength * thisJointLength) - (parentLengthToPlane * parentLengthToPlane));
  2508. Vector parentDirection = thisJointAtPlane - parentJointAtPlane;
  2509. VectorNormalize(parentDirection);
  2510. Vector newJointPos = parentJointAtPlane + (parentDirection * adjacent);
  2511. Vector newParentDir = newJointPos - parentPos;
  2512. Vector parentUp(parentJointGlobalMat[BONEUP][0], parentJointGlobalMat[BONEUP][1], parentJointGlobalMat[BONEUP][2]);
  2513. VectorNormalize(newParentDir);
  2514. VectorNormalize(parentUp);
  2515. // Vector parentSide = newParentDir.Cross(parentUp);
  2516. Vector parentSide = parentUp.Cross(newParentDir);
  2517. VectorNormalize(parentSide);
  2518. parentUp = newParentDir.Cross(parentSide);
  2519. // parentUp = parentSide.Cross(newParentDir);
  2520. VectorNormalize(parentUp);
  2521. parentJointGlobalMat[BONEDIR][0] = newParentDir[0];
  2522. parentJointGlobalMat[BONEDIR][1] = newParentDir[1];
  2523. parentJointGlobalMat[BONEDIR][2] = newParentDir[2];
  2524. parentJointGlobalMat[BONEUP][0] = parentUp[0];
  2525. parentJointGlobalMat[BONEUP][1] = parentUp[1];
  2526. parentJointGlobalMat[BONEUP][2] = parentUp[2];
  2527. parentJointGlobalMat[BONESIDE][0] = parentSide[0];
  2528. parentJointGlobalMat[BONESIDE][1] = parentSide[1];
  2529. parentJointGlobalMat[BONESIDE][2] = parentSide[2];
  2530. M_matrix4x4_t newParentJointMat;
  2531. M_ConcatTransforms(parentJointGlobalMat, gParentJointGlobalMatInverse, newParentJointMat);
  2532. s_bone_t resultBone;
  2533. M_MatrixAngles(newParentJointMat, resultBone.rot, resultBone.pos);
  2534. pSource->rawanim[t][parentIndex].rot = resultBone.rot;
  2535. }
  2536. }
  2537. }
  2538. // swap animation back for next solve
  2539. combinedAnimation[t] = pSource->rawanim[t];
  2540. pSource->rawanim[t] = sourceAnimation[t];
  2541. }
  2542. for(int t = 0; t < sourceNumFrames; t++)
  2543. {
  2544. pTarget->rawanim[t] = combinedAnimation[t];
  2545. }
  2546. pTarget->numframes = sourceNumFrames;
  2547. #if 0
  2548. // Process motion mapping into out and return that
  2549. s_source_t *out = new s_source_t;
  2550. return out;
  2551. #else
  2552. // Just returns the start animation, to test the Save_SMD API.
  2553. return pTarget;
  2554. #endif
  2555. }
  2556. char templates[] =
  2557. "\n\
  2558. #\n\
  2559. # default template file is analogus to not specifying a template file at all\n\
  2560. #\n\
  2561. \n\
  2562. rootScaleJoint ValveBiped.Bip01_L_Foot\n\
  2563. rootScaleAmount 1.0\n\
  2564. toeFloorZ 2.7777\n\
  2565. \n\
  2566. twoJointIKSolve ValveBiped.Bip01_L_Foot\n\
  2567. reverseSolve 0\n\
  2568. extremityScale 1.0\n\
  2569. limbRootOffsetScale 1.0 1.0 0.0\n\
  2570. \n\
  2571. twoJointIKSolve ValveBiped.Bip01_R_Foot\n\
  2572. reverseSolve 0\n\
  2573. extremityScale 1.0\n\
  2574. limbRootOffsetScale 1.0 1.0 0.0\n\
  2575. \n\
  2576. oneJointPlaneConstraint ValveBiped.Bip01_L_Toe0\n\
  2577. \n\
  2578. oneJointPlaneConstraint ValveBiped.Bip01_R_Toe0\n\
  2579. \n\
  2580. twoJointIKSolve ValveBiped.Bip01_R_Hand\n\
  2581. reverseSolve 1\n\
  2582. extremityScale 1.0\n\
  2583. limbRootOffsetScale 0.0 0.0 1.0\n\
  2584. \n\
  2585. twoJointIKSolve ValveBiped.Bip01_L_Hand\n\
  2586. reverseSolve 1\n\
  2587. extremityScale 1.0\n\
  2588. limbRootOffsetScale 0.0 0.0 1.0\n\
  2589. \n\
  2590. ";
  2591. void UsageAndExit()
  2592. {
  2593. MdlError( "usage: motionmapper [-quiet] [-verbose] [-templateFile filename] [-printTemplates] sourceanim.smd targetskeleton.smd output.smd\n\
  2594. \tsourceanim: should contain ref pose and animation data\n\
  2595. \ttargetsekeleton: should contain new ref pose, animation data ignored/can be absent\n\
  2596. \toutput: animation from source mapped onto target skeleton (contains new ref pose)\n\
  2597. \t-templateFile filename : specifies a template file for guiding the mapping of motion\n\
  2598. \t-printTemplate: Causes motionmapper to output the contents of an example template file, which can be used in conjunction with the -templateFile argument to create various motion effects.\n\
  2599. \n");
  2600. }
  2601. void PrintHeader()
  2602. {
  2603. vprint( 0, "Valve Software - motionmapper.exe ((c) Valve Coroporation %s)\n", __DATE__ );
  2604. vprint( 0, "--- Maps motion from one animation/skeleton onto another skeleton ---\n" );
  2605. }
  2606. /*
  2607. ==============
  2608. main
  2609. ==============
  2610. */
  2611. int main (int argc, char **argv)
  2612. {
  2613. int i;
  2614. int useTemplate = 0;
  2615. char templateFileName[1024];
  2616. // Header
  2617. PrintHeader();
  2618. // Init command line stuff
  2619. CommandLine()->CreateCmdLine( argc, argv );
  2620. InstallSpewFunction();
  2621. // init math stuff
  2622. MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
  2623. g_currentscale = g_defaultscale = 1.0;
  2624. g_defaultrotation = RadianEuler( 0, 0, M_PI / 2 );
  2625. // No args?
  2626. if (argc == 1)
  2627. {
  2628. UsageAndExit();
  2629. }
  2630. // Init variable
  2631. g_quiet = false;
  2632. // list template hooey
  2633. CUtlVector< CUtlSymbol > filenames;
  2634. // Get args
  2635. for (i = 1; i < argc; i++)
  2636. {
  2637. // Switches
  2638. if (argv[i][0] == '-')
  2639. {
  2640. if (!stricmp(argv[i], "-allowdebug"))
  2641. {
  2642. // Ignore, used by interface system to catch debug builds checked into release tree
  2643. continue;
  2644. }
  2645. if (!stricmp(argv[i], "-quiet"))
  2646. {
  2647. g_quiet = true;
  2648. g_verbose = false;
  2649. continue;
  2650. }
  2651. if (!stricmp(argv[i], "-verbose"))
  2652. {
  2653. g_quiet = false;
  2654. g_verbose = true;
  2655. continue;
  2656. }
  2657. if (!stricmp(argv[i], "-printTemplate"))
  2658. {
  2659. printf("%s\n", templates);
  2660. exit(0);
  2661. }
  2662. if (!stricmp(argv[i], "-templateFile"))
  2663. {
  2664. if(i + 1 < argc)
  2665. {
  2666. strcpy( templateFileName, argv[i+1]);
  2667. useTemplate = 1;
  2668. printf("Note: %s passed as template file", templateFileName);
  2669. }
  2670. else
  2671. {
  2672. printf("Error: -templateFile requires an argument, none found!");
  2673. UsageAndExit();
  2674. }
  2675. i++;
  2676. continue;
  2677. }
  2678. }
  2679. else
  2680. {
  2681. // more template stuff
  2682. CUtlSymbol sym = argv[ i ];
  2683. filenames.AddToTail( sym );
  2684. }
  2685. }
  2686. // Enough file args?
  2687. if ( filenames.Count() != 3 )
  2688. {
  2689. // misformed arguments
  2690. // otherwise generating unintended results
  2691. printf("Error: 3 file arguments required, %i found!", filenames.Count());
  2692. UsageAndExit();
  2693. }
  2694. // Filename arg indexes
  2695. int sourceanim = 0;
  2696. int targetskel = 1;
  2697. int outputanim = 2;
  2698. // Copy arg string to global variable
  2699. strcpy( g_outfile, filenames[ outputanim ].String() );
  2700. // Init filesystem hooey
  2701. CmdLib_InitFileSystem( g_outfile );
  2702. // ??
  2703. Q_FileBase( g_outfile, g_outfile, sizeof( g_outfile ) );
  2704. // Verbose stuff
  2705. if (!g_quiet)
  2706. {
  2707. vprint( 0, "%s, %s, %s, path %s\n", qdir, gamedir, g_outfile );
  2708. }
  2709. // ??
  2710. Q_DefaultExtension(g_outfile, ".smd", sizeof( g_outfile ) );
  2711. // Verbose stuff
  2712. if (!g_quiet)
  2713. {
  2714. vprint( 0, "Source animation: %s\n", filenames[ sourceanim ].String() );
  2715. vprint( 0, "Target skeleton: %s\n", filenames[ targetskel ].String() );
  2716. vprint( 0, "Creating on \"%s\"\n", g_outfile);
  2717. }
  2718. // fullpath = EXTERNAL GLOBAL!!!???
  2719. strcpy( fullpath, g_outfile );
  2720. strcpy( fullpath, ExpandPath( fullpath ) );
  2721. strcpy( fullpath, ExpandArg( fullpath ) );
  2722. // Load source and target data
  2723. s_source_t *pSource = Load_Source( filenames[sourceanim].String(), "smd", false, false );
  2724. s_source_t *pTarget = Load_Source( filenames[targetskel].String(), "smd", false, false );
  2725. //
  2726. s_template_t *pTemplate = NULL;
  2727. if(useTemplate)
  2728. {
  2729. pTemplate = Load_Template(templateFileName);
  2730. }
  2731. else
  2732. {
  2733. printf("Note: No template file specified, using defaults settings.\n");
  2734. pTemplate = New_Template();
  2735. Set_DefaultTemplate(pTemplate);
  2736. }
  2737. // Process skeleton
  2738. s_source_t *pMappedAnimation = MotionMap( pSource, pTarget, pTemplate );
  2739. // Save output (ref skeleton & animation data);
  2740. Save_SMD( fullpath, pMappedAnimation );
  2741. Q_StripExtension( filenames[outputanim].String(), outname, sizeof( outname ) );
  2742. // Verbose stuff
  2743. if (!g_quiet)
  2744. {
  2745. vprint( 0, "\nCompleted \"%s\"\n", g_outfile);
  2746. }
  2747. return 0;
  2748. }