Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5390 lines
156 KiB

  1. //===== Copyright � 1996-2008, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. //
  9. // write.c: writes a studio .mdl file
  10. //
  11. #pragma warning( disable : 4244 )
  12. #pragma warning( disable : 4237 )
  13. #pragma warning( disable : 4305 )
  14. #include <io.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <sys/stat.h>
  18. #include <limits.h>
  19. #include "cmdlib.h"
  20. #include "scriplib.h"
  21. #include "mathlib/mathlib.h"
  22. #include "studio.h"
  23. #include "studiomdl.h"
  24. #include "collisionmodel.h"
  25. #include "physics2collision.h"
  26. #include "optimize.h"
  27. #include "studiobyteswap.h"
  28. #include "byteswap.h"
  29. #include "materialsystem/IMaterial.h"
  30. #include "materialsystem/IMaterialVar.h"
  31. #include "mdlobjects/dmeboneflexdriver.h"
  32. #include "perfstats.h"
  33. #include "compileclothproxy.h"
  34. #include "tier1/smartptr.h"
  35. #include "tier2/p4helpers.h"
  36. int totalframes = 0;
  37. float totalseconds = 0;
  38. extern int numcommandnodes;
  39. // WriteFile is the only externally visible function in this file.
  40. // pData points to the current location in an output buffer and pStart is
  41. // the beginning of the buffer.
  42. bool FixupToSortedLODVertexes( studiohdr_t *pStudioHdr );
  43. bool Clamp_RootLOD( studiohdr_t *phdr );
  44. static void WriteAllSwappedFiles( const char *filename );
  45. /*
  46. ============
  47. WriteModel
  48. ============
  49. */
  50. static byte *pData;
  51. static byte *pStart;
  52. static byte *pBlockData;
  53. static byte *pBlockStart;
  54. static int sExtraTexcoordsToWrite = 0;
  55. #undef ALIGN16
  56. #undef ALIGN32
  57. #undef ALIGN4
  58. #define ALIGN4( a ) a = (byte *)((int)((byte *)a + 3) & ~ 3)
  59. #define ALIGN16( a ) a = (byte *)((int)((byte *)a + 15) & ~ 15)
  60. #define ALIGN32( a ) a = (byte *)((int)((byte *)a + 31) & ~ 31)
  61. #define ALIGN64( a ) a = (byte *)((int)((byte *)a + 63) & ~ 63)
  62. #define ALIGN512( a ) a = (byte *)((int)((byte *)a + 511) & ~ 511)
  63. int k_memtotal = 0;
  64. //--------------------------------------------------------------------
  65. // Allocate aligned memory of at least nCount * nSize bytes of memory via malloc
  66. // Cannot be freed as the pointer returned isn't necessarily the actual start
  67. // of the block of memory allocated from the heap due to alignment on 512 byte boundaries
  68. // Only use allocation of the written file
  69. //--------------------------------------------------------------------
  70. void *kalloc( int num, int size )
  71. {
  72. // printf( "calloc( %d, %d )\n", num, size );
  73. // printf( "%d ", num * size );
  74. int nMemSize = num * size;
  75. k_memtotal += nMemSize;
  76. // ensure memory alignment on maximum of ALIGN
  77. nMemSize += 511;
  78. void *ptr = malloc( nMemSize );
  79. memset( ptr, 0, nMemSize );
  80. ptr = (byte *)((int)((byte *)ptr + 511) & ~511);
  81. return ptr;
  82. }
  83. #define FILEBUFFER (32 * 1024 * 1024)
  84. void WriteSeqKeyValues( mstudioseqdesc_t *pseqdesc, CUtlVector< char > *pKeyValue );
  85. //-----------------------------------------------------------------------------
  86. // Purpose: stringtable is a session global string table.
  87. //-----------------------------------------------------------------------------
  88. struct stringtable_t
  89. {
  90. byte *base;
  91. int *ptr;
  92. const char *string;
  93. int dupindex;
  94. byte *addr;
  95. };
  96. static int numStrings;
  97. static stringtable_t strings[32768];
  98. static void BeginStringTable( )
  99. {
  100. strings[0].base = NULL;
  101. strings[0].ptr = NULL;
  102. strings[0].string = "";
  103. strings[0].dupindex = -1;
  104. numStrings = 1;
  105. }
  106. //-----------------------------------------------------------------------------
  107. // Purpose: add a string to the file-global string table.
  108. // Keep track of fixup locations
  109. //-----------------------------------------------------------------------------
  110. static void AddToStringTable( void *base, int *ptr, const char *string )
  111. {
  112. if ( !string )
  113. {
  114. string = "";
  115. }
  116. for (int i = 0; i < numStrings; i++)
  117. {
  118. if ( !strcmp( string, strings[i].string ))
  119. {
  120. strings[numStrings].base = (byte *)base;
  121. strings[numStrings].ptr = ptr;
  122. strings[numStrings].string = string;
  123. strings[numStrings].dupindex = i;
  124. numStrings++;
  125. return;
  126. }
  127. }
  128. strings[numStrings].base = (byte *)base;
  129. strings[numStrings].ptr = ptr;
  130. strings[numStrings].string = string;
  131. strings[numStrings].dupindex = -1;
  132. numStrings++;
  133. }
  134. //-----------------------------------------------------------------------------
  135. // Purpose: Write out stringtable
  136. // fixup local pointers
  137. //-----------------------------------------------------------------------------
  138. static byte *WriteStringTable( byte *pData )
  139. {
  140. // force null at first address
  141. strings[0].addr = pData;
  142. *pData = '\0';
  143. pData++;
  144. // save all the rest
  145. for (int i = 1; i < numStrings; i++)
  146. {
  147. if (strings[i].dupindex == -1)
  148. {
  149. // not in table yet
  150. // calc offset relative to local base
  151. *strings[i].ptr = pData - strings[i].base;
  152. // keep track of address in case of duplication
  153. strings[i].addr = pData;
  154. // copy string data, add a terminating \0
  155. strcpy( (char *)pData, strings[i].string );
  156. pData += strlen( strings[i].string );
  157. *pData = '\0';
  158. pData++;
  159. }
  160. else
  161. {
  162. // already in table, calc offset of existing string relative to local base
  163. *strings[i].ptr = strings[strings[i].dupindex].addr - strings[i].base;
  164. }
  165. }
  166. ALIGN4( pData );
  167. return pData;
  168. }
  169. // compare function for qsort below
  170. static int BoneNameCompare( const void *elem1, const void *elem2 )
  171. {
  172. int index1 = *(byte *)elem1;
  173. int index2 = *(byte *)elem2;
  174. // compare bones by name
  175. return strcmpi( g_bonetable[index1].name, g_bonetable[index2].name );
  176. }
  177. //-----------------------------------------------------------------------------
  178. //
  179. //-----------------------------------------------------------------------------
  180. template < class M, class S, int nType >
  181. static S *WriteBaseConstraint( M *pConstraint, mstudiobone_t *pbone )
  182. {
  183. if ( !pConstraint )
  184. return NULL;
  185. S *pProc = (S *)pData;
  186. pData += sizeof( S );
  187. ALIGN4( pData );
  188. pProc->m_slave.m_nBone = pConstraint->m_slave.m_nBone;
  189. pProc->m_slave.m_vBasePosition = pConstraint->m_slave.m_vBaseTranslate;
  190. pProc->m_slave.m_qBaseOrientation = pConstraint->m_slave.m_qBaseRotation;
  191. const int k = pProc->m_slave.m_nBone;
  192. pbone[k].procindex = (byte *)pProc - (byte *)&pbone[k];
  193. pbone[k].proctype = nType;
  194. mstudioconstrainttarget_t *pTarget = (mstudioconstrainttarget_t *)pData;
  195. pProc->m_nTargetCount = pConstraint->m_targets.Count();
  196. pProc->m_nTargetIndex = (byte *)pTarget - (byte *)pProc;
  197. pData += pProc->m_nTargetCount * sizeof( mstudioconstrainttarget_t );
  198. ALIGN4( pData );
  199. for ( int j = 0; j < pConstraint->m_targets.Count(); ++j )
  200. {
  201. s_constraintbonetarget_t &target = pConstraint->m_targets[j];
  202. pTarget[j].m_nBone = target.m_nBone;
  203. pTarget[j].m_flWeight = target.m_flWeight;
  204. pTarget[j].m_vOffset = target.m_vOffset;
  205. pTarget[j].m_qOffset = target.m_qOffset;
  206. }
  207. return pProc;
  208. }
  209. static void WriteBoneInfo( studiohdr_t *phdr )
  210. {
  211. int i, j, k;
  212. mstudiobone_t *pbone;
  213. mstudiobonecontroller_t *pbonecontroller;
  214. mstudioattachment_t *pattachment;
  215. mstudiobbox_t *pbbox;
  216. // save bone info
  217. pbone = (mstudiobone_t *)pData;
  218. phdr->numbones = g_numbones;
  219. phdr->boneindex = pData - pStart;
  220. char* pSurfacePropName = GetDefaultSurfaceProp( );
  221. AddToStringTable( phdr, &phdr->surfacepropindex, pSurfacePropName );
  222. phdr->contents = GetDefaultContents();
  223. for (i = 0; i < g_numbones; i++)
  224. {
  225. AddToStringTable( &pbone[i], &pbone[i].sznameindex, g_bonetable[i].name );
  226. pbone[i].parent = g_bonetable[i].parent;
  227. pbone[i].flags = g_bonetable[i].flags;
  228. pbone[i].procindex = 0;
  229. pbone[i].physicsbone = g_bonetable[i].physicsBoneIndex;
  230. pbone[i].pos = g_bonetable[i].pos;
  231. pbone[i].rot = g_bonetable[i].rot;
  232. pbone[i].posscale = g_bonetable[i].posscale;
  233. pbone[i].rotscale = g_bonetable[i].rotscale;
  234. MatrixInvert( g_bonetable[i].boneToPose, pbone[i].poseToBone );
  235. pbone[i].qAlignment = g_bonetable[i].qAlignment;
  236. AngleQuaternion( RadianEuler( g_bonetable[i].rot[0], g_bonetable[i].rot[1], g_bonetable[i].rot[2] ), pbone[i].quat );
  237. QuaternionAlign( pbone[i].qAlignment, pbone[i].quat, pbone[i].quat );
  238. pSurfacePropName = GetSurfaceProp( g_bonetable[i].name );
  239. AddToStringTable( &pbone[i], &pbone[i].surfacepropidx, pSurfacePropName );
  240. pbone[i].contents = GetContents( g_bonetable[i].name );
  241. }
  242. pData += g_numbones * sizeof( mstudiobone_t );
  243. ALIGN4( pData );
  244. // save procedural bone info
  245. if (g_numaxisinterpbones)
  246. {
  247. mstudioaxisinterpbone_t *pProc = (mstudioaxisinterpbone_t *)pData;
  248. for (i = 0; i < g_numaxisinterpbones; i++)
  249. {
  250. j = g_axisinterpbonemap[i];
  251. k = g_axisinterpbones[j].bone;
  252. pbone[k].procindex = (byte *)&pProc[i] - (byte *)&pbone[k];
  253. pbone[k].proctype = STUDIO_PROC_AXISINTERP;
  254. // printf("bone %d %d\n", j, pbone[k].procindex );
  255. pProc[i].control = g_axisinterpbones[j].control;
  256. pProc[i].axis = g_axisinterpbones[j].axis;
  257. for (k = 0; k < 6; k++)
  258. {
  259. VectorCopy( g_axisinterpbones[j].pos[k], pProc[i].pos[k] );
  260. pProc[i].quat[k] = g_axisinterpbones[j].quat[k];
  261. }
  262. }
  263. pData += g_numaxisinterpbones * sizeof( mstudioaxisinterpbone_t );
  264. ALIGN4( pData );
  265. }
  266. if (g_numquatinterpbones)
  267. {
  268. mstudioquatinterpbone_t *pProc = (mstudioquatinterpbone_t *)pData;
  269. pData += g_numquatinterpbones * sizeof( mstudioquatinterpbone_t );
  270. ALIGN4( pData );
  271. for (i = 0; i < g_numquatinterpbones; i++)
  272. {
  273. j = g_quatinterpbonemap[i];
  274. k = g_quatinterpbones[j].bone;
  275. pbone[k].procindex = (byte *)&pProc[i] - (byte *)&pbone[k];
  276. pbone[k].proctype = STUDIO_PROC_QUATINTERP;
  277. // printf("bone %d %d\n", j, pbone[k].procindex );
  278. pProc[i].control = g_quatinterpbones[j].control;
  279. mstudioquatinterpinfo_t *pTrigger = (mstudioquatinterpinfo_t *)pData;
  280. pProc[i].numtriggers = g_quatinterpbones[j].numtriggers;
  281. pProc[i].triggerindex = (byte *)pTrigger - (byte *)&pProc[i];
  282. pData += pProc[i].numtriggers * sizeof( mstudioquatinterpinfo_t );
  283. for (k = 0; k < pProc[i].numtriggers; k++)
  284. {
  285. pTrigger[k].inv_tolerance = 1.0 / g_quatinterpbones[j].tolerance[k];
  286. pTrigger[k].trigger = g_quatinterpbones[j].trigger[k];
  287. pTrigger[k].pos = g_quatinterpbones[j].pos[k];
  288. pTrigger[k].quat = g_quatinterpbones[j].quat[k];
  289. }
  290. }
  291. }
  292. if (g_numjigglebones)
  293. {
  294. mstudiojigglebone_t *jiggleInfo = (mstudiojigglebone_t *)pData;
  295. for (i = 0; i < g_numjigglebones; i++)
  296. {
  297. j = g_jigglebonemap[i];
  298. k = g_jigglebones[j].bone;
  299. pbone[k].procindex = (byte *)&jiggleInfo[i] - (byte *)&pbone[k];
  300. pbone[k].proctype = STUDIO_PROC_JIGGLE;
  301. jiggleInfo[i] = g_jigglebones[j].data;
  302. }
  303. pData += g_numjigglebones * sizeof( mstudiojigglebone_t );
  304. ALIGN4( pData );
  305. }
  306. // write aim at bones
  307. if (g_numaimatbones)
  308. {
  309. mstudioaimatbone_t *pProc = (mstudioaimatbone_t *)pData;
  310. for (i = 0; i < g_numaimatbones; i++)
  311. {
  312. j = g_aimatbonemap[i];
  313. k = g_aimatbones[j].bone;
  314. pbone[k].procindex = (byte *)&pProc[i] - (byte *)&pbone[k];
  315. pbone[k].proctype = g_aimatbones[j].aimAttach == -1 ? STUDIO_PROC_AIMATBONE : STUDIO_PROC_AIMATATTACH;
  316. pProc[i].parent = g_aimatbones[j].parent;
  317. pProc[i].aim = g_aimatbones[j].aimAttach == -1 ? g_aimatbones[j].aimBone : g_aimatbones[j].aimAttach;
  318. pProc[i].aimvector = g_aimatbones[j].aimvector;
  319. pProc[i].upvector = g_aimatbones[j].upvector;
  320. pProc[i].basepos = g_aimatbones[j].basepos;
  321. }
  322. pData += g_numaimatbones * sizeof( mstudioaimatbone_t );
  323. ALIGN4( pData );
  324. }
  325. // Write twist bones
  326. #if 0 // DISABLED IN CSGO
  327. if ( g_twistbones.Count() > 0 )
  328. {
  329. mstudiotwistbone_t *pProc = (mstudiotwistbone_t *)pData;
  330. pData += g_twistbones.Count() * sizeof( mstudiotwistbone_t );
  331. ALIGN4( pData );
  332. for ( i = 0; i < g_twistbones.Count(); ++i )
  333. {
  334. const CTwistBone &twistBone = g_twistbones[i];
  335. pProc[i].m_bInverse = twistBone.m_bInverse;
  336. pProc[i].m_vUpVector = twistBone.m_vUpVector;
  337. pProc[i].m_nParentBone = twistBone.m_nParentBone;
  338. QuaternionInvert( twistBone.m_qBaseRotation, pProc[i].m_qBaseInv );
  339. pProc[i].m_nChildBone = twistBone.m_nChildBone;
  340. mstudiotwistbonetarget_t *pTarget = (mstudiotwistbonetarget_t *)pData;
  341. pProc[i].m_nTargetCount = twistBone.m_twistBoneTargets.Count();
  342. pProc[i].m_nTargetIndex = (byte *)pTarget - (byte *)&pProc[i];
  343. pData += twistBone.m_twistBoneTargets.Count() * sizeof( mstudiotwistbone_t );
  344. ALIGN4( pData );
  345. for ( j = 0; j < twistBone.m_twistBoneTargets.Count(); ++j )
  346. {
  347. const s_constraintbonetarget_t &twistBoneTarget = twistBone.m_twistBoneTargets[j];
  348. k = twistBoneTarget.m_nBone;
  349. pTarget[j].m_nBone = k;
  350. pTarget[j].m_flWeight = twistBoneTarget.m_flWeight;
  351. pTarget[j].m_vBaseTranslate = twistBoneTarget.m_vOffset;
  352. pTarget[j].m_qBaseRotation = twistBoneTarget.m_qOffset;
  353. pbone[k].procindex = (byte *)&pProc[i] - (byte *)&pbone[k];
  354. pbone[k].proctype = j == 0 ? STUDIO_PROC_TWIST_MASTER : STUDIO_PROC_TWIST_SLAVE;
  355. }
  356. }
  357. }
  358. #endif
  359. // Write constraint bones
  360. if ( g_constraintBones.Count() > 0 )
  361. {
  362. for ( int i = 0; i < g_constraintBones.Count(); ++i )
  363. {
  364. CConstraintBoneBase *pConstraintBone = g_constraintBones[i];
  365. if ( !pConstraintBone )
  366. continue;
  367. {
  368. CPointConstraint *pConstraint = dynamic_cast< CPointConstraint * >( pConstraintBone );
  369. if ( pConstraint )
  370. {
  371. WriteBaseConstraint< CPointConstraint, mstudiopointconstraint_t, STUDIO_PROC_POINT_CONSTRAINT >( pConstraint, pbone );
  372. continue;
  373. }
  374. }
  375. {
  376. COrientConstraint *pConstraint = dynamic_cast< COrientConstraint * >( pConstraintBone );
  377. if ( pConstraint )
  378. {
  379. WriteBaseConstraint< COrientConstraint, mstudioorientconstraint_t, STUDIO_PROC_ORIENT_CONSTRAINT >( pConstraint, pbone );
  380. continue;
  381. }
  382. }
  383. {
  384. CAimConstraint *pConstraint = dynamic_cast< CAimConstraint * >( pConstraintBone );
  385. if ( pConstraint )
  386. {
  387. mstudioaimconstraint_t *pProc =
  388. WriteBaseConstraint< CAimConstraint, mstudioaimconstraint_t, STUDIO_PROC_AIM_CONSTRAINT >( pConstraint, pbone );
  389. if ( pProc )
  390. {
  391. // Local Aim Constraint Parameters
  392. pProc->m_qAimOffset = pConstraint->m_qAimOffset;
  393. pProc->m_vUp = pConstraint->m_vUpVector;
  394. pProc->m_nUpSpaceTarget = pConstraint->m_nUpSpaceTargetBone;
  395. pProc->m_nUpType = pConstraint->m_nUpType;
  396. continue;
  397. }
  398. }
  399. }
  400. {
  401. CParentConstraint *pConstraint = dynamic_cast< CParentConstraint * >( pConstraintBone );
  402. if ( pConstraint )
  403. {
  404. WriteBaseConstraint< CParentConstraint, mstudioparentconstraint_t, STUDIO_PROC_PARENT_CONSTRAINT >( pConstraint, pbone );
  405. continue;
  406. }
  407. }
  408. MdlWarning( "Ignoring Constraint Bone: %s\n", pConstraintBone->m_slave.m_szBoneName );
  409. }
  410. }
  411. // map g_bonecontroller to bones
  412. for (i = 0; i < g_numbones; i++)
  413. {
  414. for (j = 0; j < 6; j++)
  415. {
  416. pbone[i].bonecontroller[j] = -1;
  417. }
  418. }
  419. for (i = 0; i < g_numbonecontrollers; i++)
  420. {
  421. j = g_bonecontroller[i].bone;
  422. switch( g_bonecontroller[i].type & STUDIO_TYPES )
  423. {
  424. case STUDIO_X:
  425. pbone[j].bonecontroller[0] = i;
  426. break;
  427. case STUDIO_Y:
  428. pbone[j].bonecontroller[1] = i;
  429. break;
  430. case STUDIO_Z:
  431. pbone[j].bonecontroller[2] = i;
  432. break;
  433. case STUDIO_XR:
  434. pbone[j].bonecontroller[3] = i;
  435. break;
  436. case STUDIO_YR:
  437. pbone[j].bonecontroller[4] = i;
  438. break;
  439. case STUDIO_ZR:
  440. pbone[j].bonecontroller[5] = i;
  441. break;
  442. default:
  443. MdlError("unknown g_bonecontroller type\n");
  444. }
  445. }
  446. // save g_bonecontroller info
  447. pbonecontroller = (mstudiobonecontroller_t *)pData;
  448. phdr->numbonecontrollers = g_numbonecontrollers;
  449. phdr->bonecontrollerindex = pData - pStart;
  450. for (i = 0; i < g_numbonecontrollers; i++)
  451. {
  452. pbonecontroller[i].bone = g_bonecontroller[i].bone;
  453. pbonecontroller[i].inputfield = g_bonecontroller[i].inputfield;
  454. pbonecontroller[i].type = g_bonecontroller[i].type;
  455. pbonecontroller[i].start = g_bonecontroller[i].start;
  456. pbonecontroller[i].end = g_bonecontroller[i].end;
  457. }
  458. pData += g_numbonecontrollers * sizeof( mstudiobonecontroller_t );
  459. ALIGN4( pData );
  460. // save attachment info
  461. pattachment = (mstudioattachment_t *)pData;
  462. phdr->numlocalattachments = g_numattachments;
  463. phdr->localattachmentindex = pData - pStart;
  464. for (i = 0; i < g_numattachments; i++)
  465. {
  466. pattachment[i].localbone = g_attachment[i].bone;
  467. AddToStringTable( &pattachment[i], &pattachment[i].sznameindex, g_attachment[i].name );
  468. MatrixCopy( g_attachment[i].local, pattachment[i].local );
  469. pattachment[i].flags = g_attachment[i].flags;
  470. }
  471. pData += g_numattachments * sizeof( mstudioattachment_t );
  472. ALIGN4( pData );
  473. // save hitbox sets
  474. phdr->numhitboxsets = g_hitboxsets.Count();
  475. // Remember start spot
  476. mstudiohitboxset_t *hitboxset = (mstudiohitboxset_t *)pData;
  477. phdr->hitboxsetindex = pData - pStart;
  478. pData += phdr->numhitboxsets * sizeof( mstudiohitboxset_t );
  479. ALIGN4( pData );
  480. for ( int s = 0; s < g_hitboxsets.Count(); s++, hitboxset++ )
  481. {
  482. s_hitboxset *set = &g_hitboxsets[ s ];
  483. AddToStringTable( hitboxset, &hitboxset->sznameindex, set->hitboxsetname );
  484. hitboxset->numhitboxes = set->numhitboxes;
  485. hitboxset->hitboxindex = ( pData - (byte *)hitboxset );
  486. // save bbox info
  487. pbbox = (mstudiobbox_t *)pData;
  488. for (i = 0; i < hitboxset->numhitboxes; i++)
  489. {
  490. pbbox[i].bone = set->hitbox[i].bone;
  491. pbbox[i].group = set->hitbox[i].group;
  492. VectorCopy( set->hitbox[i].bmin, pbbox[i].bbmin );
  493. VectorCopy( set->hitbox[i].bmax, pbbox[i].bbmax );
  494. VectorCopy( set->hitbox[i].angOffsetOrientation, pbbox[i].angOffsetOrientation );
  495. pbbox[i].flCapsuleRadius = set->hitbox[i].flCapsuleRadius;
  496. pbbox[i].szhitboxnameindex = 0;
  497. AddToStringTable( &(pbbox[i]), &(pbbox[i].szhitboxnameindex), set->hitbox[i].hitboxname );
  498. }
  499. pData += hitboxset->numhitboxes * sizeof( mstudiobbox_t );
  500. ALIGN4( pData );
  501. }
  502. byte *pBoneTable = pData;
  503. phdr->bonetablebynameindex = (pData - pStart);
  504. // make a table in bone order and sort it with qsort
  505. for ( i = 0; i < phdr->numbones; i++ )
  506. {
  507. pBoneTable[i] = i;
  508. }
  509. qsort( pBoneTable, phdr->numbones, sizeof(byte), BoneNameCompare );
  510. pData += phdr->numbones * sizeof( byte );
  511. ALIGN4( pData );
  512. }
  513. // load a preexisting model to remember its sequence names and indices
  514. CUtlVector< CUtlString > g_vecPreexistingSequences;
  515. void LoadPreexistingSequenceOrder( const char *pFilename )
  516. {
  517. g_vecPreexistingSequences.RemoveAll();
  518. if ( !FileExists( pFilename ) )
  519. {
  520. if ( g_bErrorOnSeqRemapFail )
  521. MdlError( "This model requires a sequence remapping match. Please sync to the latest model on disk before recompiling.\n" );
  522. return;
  523. }
  524. Msg( "Loading preexisting model: %s\n", pFilename );
  525. studiohdr_t *pStudioHdr;
  526. int len = LoadFile((char*)pFilename, (void **)&pStudioHdr);
  527. if ( len && pStudioHdr && pStudioHdr->SequencesAvailable() )
  528. {
  529. Msg( " Found %i preexisting sequences.\n", pStudioHdr->GetNumSeq() );
  530. for ( int i=0; i<pStudioHdr->GetNumSeq(); i++ )
  531. {
  532. //Msg( " Sequence %i : \"%s\"\n", i, pStudioHdr->pSeqdesc(i).pszLabel() );
  533. g_vecPreexistingSequences.AddToTail( pStudioHdr->pSeqdesc(i).pszLabel() );
  534. }
  535. }
  536. else if ( g_bModelIntentionallyHasZeroSequences )
  537. {
  538. // some models like scaffolds, intentionally don't have input sequences. Not sure if this is the best way to allow this exception.
  539. }
  540. else if ( g_bErrorOnSeqRemapFail )
  541. {
  542. MdlError( "Zero-size file or no sequences. This model requires a sequence remapping match.\n" );
  543. }
  544. else
  545. {
  546. MdlWarning( "Zero-size file or no sequences.\n" );
  547. }
  548. }
  549. static void WriteSequenceInfo( studiohdr_t *phdr )
  550. {
  551. int i, j, k;
  552. mstudioseqdesc_t *pseqdesc;
  553. mstudioseqdesc_t *pbaseseqdesc;
  554. mstudioevent_t *pevent;
  555. byte *ptransition;
  556. mstudioanimtag_t *panimtag;
  557. // write models to disk with this flag set false. This will force
  558. // the sequences to be indexed by activity whenever the g_model is loaded
  559. // from disk.
  560. phdr->activitylistversion = 0;
  561. phdr->eventsindexed = 0;
  562. // save g_sequence info
  563. pseqdesc = (mstudioseqdesc_t *)pData;
  564. pbaseseqdesc = pseqdesc;
  565. phdr->numlocalseq = g_sequence.Count();
  566. phdr->localseqindex = (pData - pStart);
  567. pData += g_sequence.Count() * sizeof( mstudioseqdesc_t );
  568. bool bErrors = false;
  569. // build a table to remap new sequence indices to match the preexisting model
  570. bool bUseSeqOrderRemapping = false;
  571. int nSeqOrderRemappingTable[MAXSTUDIOSEQUENCES];
  572. for (i=0; i<MAXSTUDIOSEQUENCES; i++)
  573. nSeqOrderRemappingTable[i] = -1;
  574. bool bAllowSequenceRemoval = false;
  575. if ( g_vecPreexistingSequences.Count() )
  576. {
  577. if ( g_sequence.Count() < g_vecPreexistingSequences.Count() && !bAllowSequenceRemoval )
  578. {
  579. Msg( "\n" );
  580. MdlWarning( "This model has fewer sequences than its predecessor.\nPlease confirm sequence deletion: [y/n] " );
  581. int nInput = 0;
  582. do { nInput = getchar(); } while ( nInput != 121 /* y */ && nInput != 110 /* n */ );
  583. if ( nInput == 110 )
  584. {
  585. MdlError( "Model contains fewer sequences than its predecessor!\n" );
  586. }
  587. else if ( nInput == 121 )
  588. {
  589. bAllowSequenceRemoval = true;
  590. }
  591. }
  592. {
  593. Msg( "Building sequence index remapping table...\n" );
  594. CUtlVector<int> vecNewIndices;
  595. vecNewIndices.RemoveAll();
  596. // map current sequences to their old indices
  597. for (i = 0; i < g_sequence.Count(); i++ )
  598. {
  599. int nIdx = g_vecPreexistingSequences.Find( g_sequence[i].name );
  600. if ( nIdx >= 0 )
  601. {
  602. nSeqOrderRemappingTable[nIdx] = i;
  603. }
  604. else
  605. {
  606. if ( i < g_vecPreexistingSequences.Count() )
  607. {
  608. Msg( " Found new sequence \"%s\" using index of old sequence \"%s\".\n", g_sequence[i].name, g_vecPreexistingSequences[i].Get() );
  609. }
  610. else
  611. {
  612. Msg( " Found new sequence \"%s\".\n", g_sequence[i].name );
  613. }
  614. vecNewIndices.AddToTail(i);
  615. }
  616. }
  617. // slot new sequences into unused indices
  618. while ( vecNewIndices.Count() )
  619. {
  620. for (i = 0; i < MAXSTUDIOSEQUENCES; i++ )
  621. {
  622. if ( nSeqOrderRemappingTable[i] == -1 )
  623. {
  624. nSeqOrderRemappingTable[i] = vecNewIndices[0];
  625. vecNewIndices.Remove(0);
  626. break;
  627. }
  628. }
  629. }
  630. // verify no indices are undefined
  631. for (i = 0; i < g_sequence.Count(); i++ )
  632. {
  633. if ( nSeqOrderRemappingTable[i] == -1 )
  634. {
  635. if ( bAllowSequenceRemoval )
  636. {
  637. do
  638. {
  639. for ( int nB=i; nB<g_vecPreexistingSequences.Count(); nB++ )
  640. {
  641. nSeqOrderRemappingTable[nB] = nSeqOrderRemappingTable[nB+1];
  642. }
  643. }
  644. while (nSeqOrderRemappingTable[i] == -1);
  645. }
  646. else
  647. {
  648. MdlError( "Failed to reorder sequence indices.\n" );
  649. }
  650. }
  651. else if ( nSeqOrderRemappingTable[i] != i )
  652. {
  653. bUseSeqOrderRemapping = true;
  654. }
  655. }
  656. if ( bUseSeqOrderRemapping )
  657. {
  658. Msg( "Sequence indices need re-ordering.\n" );
  659. }
  660. else
  661. {
  662. Msg( "No re-ordering required.\n" );
  663. }
  664. }
  665. }
  666. // build an inverted remapping table so autolayer sequence indices can find their sources later
  667. int nSeqOrderRemappingTableInv[MAXSTUDIOSEQUENCES];
  668. if ( bUseSeqOrderRemapping )
  669. {
  670. for (i=0; i<MAXSTUDIOSEQUENCES; i++)
  671. nSeqOrderRemappingTableInv[nSeqOrderRemappingTable[i]] = i;
  672. }
  673. int m;
  674. for (m = 0; m < g_sequence.Count(); m++, pseqdesc++)
  675. {
  676. if ( bUseSeqOrderRemapping )
  677. {
  678. i = nSeqOrderRemappingTable[m];
  679. if ( i != m )
  680. {
  681. Msg( " Remapping sequence %i to index %i (%s) to retain existing order.\n", i, m, g_sequence[i].name );
  682. }
  683. }
  684. else
  685. {
  686. i = m;
  687. }
  688. byte *pSequenceStart = (byte *)pseqdesc;
  689. AddToStringTable( pseqdesc, &pseqdesc->szlabelindex, g_sequence[i].name );
  690. AddToStringTable( pseqdesc, &pseqdesc->szactivitynameindex, g_sequence[i].activityname );
  691. pseqdesc->baseptr = pStart - (byte *)pseqdesc;
  692. pseqdesc->flags = g_sequence[i].flags;
  693. pseqdesc->numblends = g_sequence[i].numblends;
  694. pseqdesc->groupsize[0] = g_sequence[i].groupsize[0];
  695. pseqdesc->groupsize[1] = g_sequence[i].groupsize[1];
  696. pseqdesc->paramindex[0] = g_sequence[i].paramindex[0];
  697. pseqdesc->paramstart[0] = g_sequence[i].paramstart[0];
  698. pseqdesc->paramend[0] = g_sequence[i].paramend[0];
  699. pseqdesc->paramindex[1] = g_sequence[i].paramindex[1];
  700. pseqdesc->paramstart[1] = g_sequence[i].paramstart[1];
  701. pseqdesc->paramend[1] = g_sequence[i].paramend[1];
  702. if (g_sequence[i].groupsize[0] > 1 || g_sequence[i].groupsize[1] > 1)
  703. {
  704. // save posekey values
  705. float *pposekey = (float *)pData;
  706. pseqdesc->posekeyindex = (pData - pSequenceStart);
  707. pData += (pseqdesc->groupsize[0] + pseqdesc->groupsize[1]) * sizeof( float );
  708. for (j = 0; j < pseqdesc->groupsize[0]; j++)
  709. {
  710. if (g_sequence[i].param0.IsValidIndex(j))
  711. {
  712. *(pposekey++) = g_sequence[i].param0[j];
  713. }
  714. else
  715. {
  716. *(pposekey++) = NULL;
  717. }
  718. // printf("%.2f ", g_sequence[i].param0[j] );
  719. }
  720. for (j = 0; j < pseqdesc->groupsize[1]; j++)
  721. {
  722. if (g_sequence[i].param1.IsValidIndex(j))
  723. {
  724. *(pposekey++) = g_sequence[i].param1[j];
  725. }
  726. else
  727. {
  728. *(pposekey++) = NULL;
  729. }
  730. // printf("%.2f ", g_sequence[i].param1[j] );
  731. }
  732. // printf("\n" );
  733. }
  734. // pseqdesc->motiontype = g_sequence[i].motiontype;
  735. // pseqdesc->motionbone = 0; // g_sequence[i].motionbone;
  736. // VectorCopy( g_sequence[i].linearmovement, pseqdesc->linearmovement );
  737. pseqdesc->activity = g_sequence[i].activity;
  738. pseqdesc->actweight = g_sequence[i].actweight;
  739. pseqdesc->bbmin = g_sequence[i].bmin;
  740. pseqdesc->bbmax = g_sequence[i].bmax;
  741. pseqdesc->fadeintime = g_sequence[i].fadeintime;
  742. pseqdesc->fadeouttime = g_sequence[i].fadeouttime;
  743. pseqdesc->localentrynode = g_sequence[i].entrynode;
  744. pseqdesc->localexitnode = g_sequence[i].exitnode;
  745. //pseqdesc->entryphase = g_sequence[i].entryphase;
  746. //pseqdesc->exitphase = g_sequence[i].exitphase;
  747. pseqdesc->nodeflags = g_sequence[i].nodeflags;
  748. // save events
  749. pevent = (mstudioevent_t *)pData;
  750. pseqdesc->numevents = g_sequence[i].numevents;
  751. pseqdesc->eventindex = (pData - pSequenceStart);
  752. pData += pseqdesc->numevents * sizeof( mstudioevent_t );
  753. for (j = 0; j < g_sequence[i].numevents; j++)
  754. {
  755. k = g_sequence[i].panim[0][0]->numframes - 1;
  756. if (g_sequence[i].event[j].frame <= k)
  757. pevent[j].cycle = g_sequence[i].event[j].frame / ((float)k);
  758. else if (k == 0 && g_sequence[i].event[j].frame == 0)
  759. pevent[j].cycle = 0;
  760. else
  761. {
  762. MdlWarning("Event %d (frame %d) out of range in %s\n", g_sequence[i].event[j].event, g_sequence[i].event[j].frame, g_sequence[i].name );
  763. bErrors = true;
  764. }
  765. //Adrian - Remove me once we phase out the old event system.
  766. if ( V_isdigit( g_sequence[i].event[j].eventname[0] ) )
  767. {
  768. pevent[j].event = atoi( g_sequence[i].event[j].eventname );
  769. pevent[j].type = 0;
  770. pevent[j].szeventindex = 0;
  771. }
  772. else
  773. {
  774. AddToStringTable( &pevent[j], &pevent[j].szeventindex, g_sequence[i].event[j].eventname );
  775. pevent[j].type = NEW_EVENT_STYLE;
  776. }
  777. // printf("%4d : %d %f\n", pevent[j].event, g_sequence[i].event[j].frame, pevent[j].cycle );
  778. // AddToStringTable( &pevent[j], &pevent[j].szoptionindex, g_sequence[i].event[j].options );
  779. strcpy( pevent[j].options, g_sequence[i].event[j].options );
  780. }
  781. ALIGN4( pData );
  782. // save ikrules
  783. pseqdesc->numikrules = g_sequence[i].numikrules;
  784. // save autolayers
  785. mstudioautolayer_t *pautolayer = (mstudioautolayer_t *)pData;
  786. pseqdesc->numautolayers = g_sequence[i].numautolayers;
  787. pseqdesc->autolayerindex = (pData - pSequenceStart);
  788. pData += pseqdesc->numautolayers * sizeof( mstudioautolayer_t );
  789. for (j = 0; j < g_sequence[i].numautolayers; j++)
  790. {
  791. pautolayer[j].iSequence = g_sequence[i].autolayer[j].sequence;
  792. pautolayer[j].iPose = g_sequence[i].autolayer[j].pose;
  793. pautolayer[j].flags = g_sequence[i].autolayer[j].flags;
  794. // autolayer indices are stored by index, so remap them now using the invertex lookup table
  795. if ( bUseSeqOrderRemapping )
  796. {
  797. int nRemapAutoLayer = nSeqOrderRemappingTableInv[ pautolayer[j].iSequence ];
  798. if ( nRemapAutoLayer != pautolayer[j].iSequence )
  799. {
  800. Msg( " Autolayer remapping index %i to %i.\n", pautolayer[j].iSequence, nRemapAutoLayer );
  801. pautolayer[j].iSequence = nRemapAutoLayer;
  802. }
  803. }
  804. if (!(pautolayer[j].flags & STUDIO_AL_POSE))
  805. {
  806. pautolayer[j].start = g_sequence[i].autolayer[j].start / (g_sequence[i].panim[0][0]->numframes - 1);
  807. pautolayer[j].peak = g_sequence[i].autolayer[j].peak / (g_sequence[i].panim[0][0]->numframes - 1);
  808. pautolayer[j].tail = g_sequence[i].autolayer[j].tail / (g_sequence[i].panim[0][0]->numframes - 1);
  809. pautolayer[j].end = g_sequence[i].autolayer[j].end / (g_sequence[i].panim[0][0]->numframes - 1);
  810. }
  811. else
  812. {
  813. pautolayer[j].start = g_sequence[i].autolayer[j].start;
  814. pautolayer[j].peak = g_sequence[i].autolayer[j].peak;
  815. pautolayer[j].tail = g_sequence[i].autolayer[j].tail;
  816. pautolayer[j].end = g_sequence[i].autolayer[j].end;
  817. }
  818. }
  819. // save boneweights
  820. float *pweight = 0;
  821. j = 0;
  822. // look up previous sequence weights and try to find a match
  823. for (k = 0; k < m; k++)
  824. {
  825. j = 0;
  826. // only check newer boneweights than the last one
  827. if (pseqdesc[k-m].pBoneweight( 0 ) > pweight)
  828. {
  829. pweight = pseqdesc[k-m].pBoneweight( 0 );
  830. for (j = 0; j < g_numbones; j++)
  831. {
  832. // we're not walking the linear sequence list if we're remapping, so we need to remap this check
  833. int nRemap = k;
  834. if ( bUseSeqOrderRemapping )
  835. nRemap = nSeqOrderRemappingTable[k];
  836. if (g_sequence[i].weight[j] != g_sequence[nRemap].weight[j])
  837. break;
  838. }
  839. if (j == g_numbones)
  840. break;
  841. }
  842. }
  843. // check to see if all the bones matched
  844. if (j < g_numbones)
  845. {
  846. // allocate new block
  847. //printf("new %08x\n", pData );
  848. pweight = (float *)pData;
  849. pseqdesc->weightlistindex = (pData - pSequenceStart);
  850. pData += g_numbones * sizeof( float );
  851. for (j = 0; j < g_numbones; j++)
  852. {
  853. pweight[j] = g_sequence[i].weight[j];
  854. }
  855. }
  856. else
  857. {
  858. // use previous boneweight
  859. //printf("prev %08x\n", pweight );
  860. pseqdesc->weightlistindex = ((byte *)pweight - pSequenceStart);
  861. }
  862. // save iklocks
  863. mstudioiklock_t *piklock = (mstudioiklock_t *)pData;
  864. pseqdesc->numiklocks = g_sequence[i].numiklocks;
  865. pseqdesc->iklockindex = (pData - pSequenceStart);
  866. pData += pseqdesc->numiklocks * sizeof( mstudioiklock_t );
  867. ALIGN4( pData );
  868. for (j = 0; j < pseqdesc->numiklocks; j++)
  869. {
  870. piklock->chain = g_sequence[i].iklock[j].chain;
  871. piklock->flPosWeight = g_sequence[i].iklock[j].flPosWeight;
  872. piklock->flLocalQWeight = g_sequence[i].iklock[j].flLocalQWeight;
  873. piklock++;
  874. }
  875. // Write animation blend parameters
  876. short *blends = ( short * )pData;
  877. pseqdesc->animindexindex = ( pData - pSequenceStart );
  878. pData += ( g_sequence[i].groupsize[0] * g_sequence[i].groupsize[1] ) * sizeof( short );
  879. ALIGN4( pData );
  880. for ( j = 0; j < g_sequence[i].groupsize[0] ; j++ )
  881. {
  882. for ( k = 0; k < g_sequence[i].groupsize[1]; k++ )
  883. {
  884. // height value * width of row + width value
  885. int offset = k * g_sequence[i].groupsize[0] + j;
  886. if ( g_sequence[i].panim[j][k] )
  887. {
  888. int animindex = g_sequence[i].panim[j][k]->index;
  889. Assert( animindex >= 0 && animindex < SHRT_MAX );
  890. blends[ offset ] = (short)animindex;
  891. }
  892. else
  893. {
  894. blends[ offset ] = 0;
  895. }
  896. }
  897. }
  898. // Write cycle overrides
  899. pseqdesc->cycleposeindex = g_sequence[i].cycleposeindex;
  900. WriteSeqKeyValues( pseqdesc, &g_sequence[i].KeyValue );
  901. // Write activity modifiers
  902. mstudioactivitymodifier_t *pactivitymodifier = (mstudioactivitymodifier_t *)pData;
  903. pseqdesc->numactivitymodifiers = g_sequence[i].numactivitymodifiers;
  904. pseqdesc->activitymodifierindex = (pData - pSequenceStart);
  905. pData += pseqdesc->numactivitymodifiers * sizeof( mstudioactivitymodifier_t );
  906. ALIGN4( pData );
  907. for (j = 0; j < pseqdesc->numactivitymodifiers; j++)
  908. {
  909. AddToStringTable( &pactivitymodifier[j], &pactivitymodifier[j].sznameindex, g_sequence[i].activitymodifier[j].name );
  910. }
  911. // save animtags
  912. panimtag = (mstudioanimtag_t *)pData;
  913. pseqdesc->numanimtags = g_sequence[i].numanimtags;
  914. pseqdesc->animtagindex = (pData - pSequenceStart);
  915. pData += pseqdesc->numanimtags * sizeof( mstudioanimtag_t );
  916. for (j = 0; j < g_sequence[i].numanimtags; j++)
  917. {
  918. panimtag[j].cycle = g_sequence[i].animtags[j].cycle;
  919. AddToStringTable( &panimtag[j], &panimtag[j].sztagindex, g_sequence[i].animtags[j].tagname );
  920. }
  921. if ( g_sequence[i].flags & STUDIO_ROOTXFORM )
  922. {
  923. int bone = findGlobalBone( g_sequence[i].rootDriverBoneName );
  924. if (bone != -1)
  925. {
  926. pseqdesc->rootDriverIndex = bone;
  927. }
  928. else
  929. {
  930. MdlError("unable to find bone %s\n", token );
  931. }
  932. }
  933. else
  934. {
  935. pseqdesc->rootDriverIndex = 0;
  936. }
  937. ALIGN4( pData );
  938. }
  939. if (bErrors)
  940. {
  941. MdlError( "Exiting due to Errors\n");
  942. }
  943. // save transition graph
  944. int *pxnodename = (int *)pData;
  945. phdr->localnodenameindex = (pData - pStart);
  946. pData += g_numxnodes * sizeof( *pxnodename );
  947. ALIGN4( pData );
  948. for (i = 0; i < g_numxnodes; i++)
  949. {
  950. AddToStringTable( phdr, pxnodename, g_xnodename[i+1] );
  951. // printf("%d : %s\n", i, g_xnodename[i+1] );
  952. pxnodename++;
  953. }
  954. ptransition = (byte *)pData;
  955. phdr->numlocalnodes = g_numxnodes;
  956. phdr->localnodeindex = pData - pStart;
  957. pData += g_numxnodes * g_numxnodes * sizeof( byte );
  958. ALIGN4( pData );
  959. for (i = 0; i < g_numxnodes; i++)
  960. {
  961. // printf("%2d (%12s) : ", i + 1, g_xnodename[i+1] );
  962. for (j = 0; j < g_numxnodes; j++)
  963. {
  964. *ptransition++ = g_xnode[i][j];
  965. // printf(" %2d", g_xnode[i][j] );
  966. }
  967. // printf("\n" );
  968. }
  969. }
  970. //-----------------------------------------------------------------------------
  971. // Purpose: Stub implementation
  972. // Input : *group -
  973. //-----------------------------------------------------------------------------
  974. const studiohdr_t *studiohdr_t::FindModel( void **cache, char const *modelname ) const
  975. {
  976. return NULL;
  977. }
  978. virtualmodel_t *studiohdr_t::GetVirtualModel( void ) const
  979. {
  980. return NULL;
  981. }
  982. const studiohdr_t *virtualgroup_t::GetStudioHdr( void ) const
  983. {
  984. return (studiohdr_t *)cache;
  985. }
  986. byte *studiohdr_t::GetAnimBlock( int i, bool preloadIfMissing ) const
  987. {
  988. return NULL;
  989. }
  990. bool studiohdr_t::hasAnimBlockBeenPreloaded( int i ) const
  991. {
  992. return false;
  993. }
  994. int studiohdr_t::GetAutoplayList( unsigned short **pOut ) const
  995. {
  996. return 0;
  997. }
  998. int rawanimbytes = 0;
  999. int animboneframes = 0;
  1000. int numAxis[4] = { 0, 0, 0, 0 };
  1001. int numPos[4] = { 0, 0, 0, 0 };
  1002. int useRaw = 0;
  1003. void WriteRLEAnimationData( s_animation_t *srcanim, mstudioanimdesc_t *destanimdesc, byte *&pData, int w )
  1004. {
  1005. int j, k, n;
  1006. mstudio_rle_anim_t *destanim = (mstudio_rle_anim_t *)pData;
  1007. pData += sizeof( *destanim );
  1008. destanim->bone = 255;
  1009. mstudio_rle_anim_t *prevanim = NULL;
  1010. // save animation value info
  1011. for (j = 0; j < g_numbones; j++)
  1012. {
  1013. // destanim->weight = srcanim->weight[j];
  1014. // printf( "%s %.1f\n", g_bonetable[j].name, destanim->weight );
  1015. destanim->flags = 0;
  1016. s_compressed_t *psrcdata = &srcanim->anim[w][j];
  1017. numPos[ (psrcdata->num[0] != 0) + (psrcdata->num[1] != 0) + (psrcdata->num[2] != 0) ]++;
  1018. numAxis[ (psrcdata->num[3] != 0) + (psrcdata->num[4] != 0) + (psrcdata->num[5] != 0) ]++;
  1019. if (psrcdata->num[0] + psrcdata->num[1] + psrcdata->num[2] + psrcdata->num[3] + psrcdata->num[4] + psrcdata->num[5] == 0)
  1020. {
  1021. // no animation, skip
  1022. continue;
  1023. }
  1024. destanim->bone = j;
  1025. // copy flags over if delta animation
  1026. if (srcanim->flags & STUDIO_DELTA)
  1027. {
  1028. destanim->flags |= STUDIO_ANIM_DELTA;
  1029. }
  1030. if ((srcanim->numframes == 1) || (psrcdata->num[0] <= 2 && psrcdata->num[1] <= 2 && psrcdata->num[2] <= 2 && psrcdata->num[3] <= 2 && psrcdata->num[4] <= 2 && psrcdata->num[5] <= 2))
  1031. {
  1032. // printf("%d : %d %d %d : %d %d %d\n", j, psrcdata->num[0], psrcdata->num[1], psrcdata->num[2], psrcdata->num[3], psrcdata->num[4], psrcdata->num[5] );
  1033. // single frame, if animation detected just store as raw
  1034. int iFrame = MIN( w * srcanim->sectionframes, srcanim->numframes - 1 );
  1035. if (psrcdata->num[3] != 0 || psrcdata->num[4] != 0 || psrcdata->num[5] != 0)
  1036. {
  1037. Quaternion q;
  1038. AngleQuaternion( srcanim->sanim[iFrame][j].rot, q );
  1039. *((Quaternion64 *)pData) = q;
  1040. pData += sizeof( Quaternion64 );
  1041. rawanimbytes += sizeof( Quaternion64 );
  1042. destanim->flags |= STUDIO_ANIM_RAWROT2;
  1043. }
  1044. if (psrcdata->num[0] != 0 || psrcdata->num[1] != 0 || psrcdata->num[2] != 0)
  1045. {
  1046. *((Vector48 *)pData) = srcanim->sanim[iFrame][j].pos;
  1047. pData += sizeof( Vector48 );
  1048. rawanimbytes += sizeof( Vector48 );
  1049. destanim->flags |= STUDIO_ANIM_RAWPOS;
  1050. }
  1051. }
  1052. else
  1053. {
  1054. // look to see if storing raw quat's would have taken less space
  1055. if (psrcdata->num[3] >= srcanim->numframes && psrcdata->num[4] >= srcanim->numframes && psrcdata->num[5] >= srcanim->numframes)
  1056. {
  1057. useRaw++;
  1058. }
  1059. mstudioanim_valueptr_t *posvptr = NULL;
  1060. mstudioanim_valueptr_t *rotvptr = NULL;
  1061. // allocate room for rotation ptrs
  1062. rotvptr = (mstudioanim_valueptr_t *)pData;
  1063. pData += sizeof( *rotvptr );
  1064. // skip all position info if there's no animation
  1065. if (psrcdata->num[0] != 0 || psrcdata->num[1] != 0 || psrcdata->num[2] != 0)
  1066. {
  1067. posvptr = (mstudioanim_valueptr_t *)pData;
  1068. pData += sizeof( *posvptr );
  1069. }
  1070. mstudioanimvalue_t *destanimvalue = (mstudioanimvalue_t *)pData;
  1071. if (rotvptr)
  1072. {
  1073. // store rotation animations
  1074. for (k = 3; k < 6; k++)
  1075. {
  1076. if (psrcdata->num[k] == 0)
  1077. {
  1078. rotvptr->offset[k-3] = 0;
  1079. }
  1080. else
  1081. {
  1082. rotvptr->offset[k-3] = ((byte *)destanimvalue - (byte *)rotvptr);
  1083. for (n = 0; n < psrcdata->num[k]; n++)
  1084. {
  1085. destanimvalue->value = psrcdata->data[k][n].value;
  1086. destanimvalue++;
  1087. }
  1088. }
  1089. }
  1090. destanim->flags |= STUDIO_ANIM_ANIMROT;
  1091. }
  1092. if (posvptr)
  1093. {
  1094. // store position animations
  1095. for (k = 0; k < 3; k++)
  1096. {
  1097. if (psrcdata->num[k] == 0)
  1098. {
  1099. posvptr->offset[k] = 0;
  1100. }
  1101. else
  1102. {
  1103. posvptr->offset[k] = ((byte *)destanimvalue - (byte *)posvptr);
  1104. for (n = 0; n < psrcdata->num[k]; n++)
  1105. {
  1106. destanimvalue->value = psrcdata->data[k][n].value;
  1107. destanimvalue++;
  1108. }
  1109. }
  1110. }
  1111. destanim->flags |= STUDIO_ANIM_ANIMPOS;
  1112. }
  1113. rawanimbytes += ((byte *)destanimvalue - pData);
  1114. pData = (byte *)destanimvalue;
  1115. }
  1116. prevanim = destanim;
  1117. destanim->nextoffset = pData - (byte *)destanim;
  1118. destanim = (mstudio_rle_anim_t *)pData;
  1119. pData += sizeof( *destanim );
  1120. }
  1121. if (prevanim)
  1122. {
  1123. prevanim->nextoffset = 0;
  1124. }
  1125. ALIGN4( pData );
  1126. }
  1127. void WriteFrameAnimationData( s_animation_t *srcanim, mstudioanimdesc_t *destanimdesc, byte *&pData, int w )
  1128. {
  1129. // allocate room for header
  1130. mstudio_frame_anim_t *destframeanim = (mstudio_frame_anim_t *)pData;
  1131. pData += sizeof( *destframeanim );
  1132. // write flags and constants
  1133. byte *flag = pData;
  1134. pData += g_numbones * sizeof( *flag );
  1135. ALIGN4( pData );
  1136. destframeanim->constantsoffset = pData - (byte *)destframeanim;
  1137. int framelength = 0;
  1138. int iFrame = MIN( w * srcanim->sectionframes, srcanim->numframes - 1 );
  1139. for (int j = 0; j < g_numbones; j++)
  1140. {
  1141. s_compressed_t *psrcdata = &srcanim->anim[w][j];
  1142. if (psrcdata->num[3] == 0 && psrcdata->num[4] == 0 && psrcdata->num[5] == 0)
  1143. {
  1144. // no change
  1145. }
  1146. else if (psrcdata->num[3] <= 2 && psrcdata->num[4] <= 2 && psrcdata->num[5] <= 2)
  1147. {
  1148. flag[j] |= STUDIO_FRAME_CONST_ROT2;
  1149. Quaternion q;
  1150. AngleQuaternion( srcanim->sanim[iFrame][j].rot, q );
  1151. *((Quaternion48S *)pData) = q;
  1152. pData += sizeof( Quaternion48S );
  1153. }
  1154. else
  1155. {
  1156. flag[j] |= STUDIO_FRAME_ANIM_ROT2;
  1157. framelength += sizeof( Quaternion48S );
  1158. }
  1159. if (psrcdata->num[0] == 0 && psrcdata->num[1] == 0 && psrcdata->num[2] == 0)
  1160. {
  1161. // no change
  1162. }
  1163. else if (psrcdata->num[0] <= 2 && psrcdata->num[1] <= 2 && psrcdata->num[2] <= 2)
  1164. {
  1165. // single frame
  1166. if (g_bAnimblockHighRes)
  1167. {
  1168. flag[j] |= STUDIO_FRAME_CONST_POS2;
  1169. *((Vector *)pData) = srcanim->sanim[iFrame][j].pos;
  1170. pData += sizeof( Vector );
  1171. }
  1172. else
  1173. {
  1174. flag[j] |= STUDIO_FRAME_CONST_POS;
  1175. *((Vector48 *)pData) = srcanim->sanim[iFrame][j].pos;
  1176. pData += sizeof( Vector48 );
  1177. }
  1178. }
  1179. else
  1180. {
  1181. // multiple frames
  1182. if (g_bAnimblockHighRes)
  1183. {
  1184. flag[j] |= STUDIO_FRAME_ANIM_POS2;
  1185. framelength += sizeof( Vector );
  1186. }
  1187. else
  1188. {
  1189. flag[j] |= STUDIO_FRAME_ANIM_POS;
  1190. framelength += sizeof( Vector48 );
  1191. }
  1192. }
  1193. }
  1194. ALIGN4( pData );
  1195. // write raw data
  1196. destframeanim->frameoffset = pData - (byte *)destframeanim;
  1197. destframeanim->framelength = framelength;
  1198. int iStartFrame = 0;
  1199. int iEndFrame = srcanim->numframes - 1;
  1200. if (srcanim->sectionframes > 0)
  1201. {
  1202. iStartFrame = MIN( w * srcanim->sectionframes, srcanim->numframes - 1 );
  1203. iEndFrame = MIN( (w + 1) * srcanim->sectionframes, srcanim->numframes - 1 );
  1204. }
  1205. /*
  1206. printf("%s (%d : %d %d):\n", srcanim->name, srcanim->numframes, iStartFrame, iEndFrame );
  1207. for (int j = 0; j < g_numbones; j++)
  1208. {
  1209. s_compressed_t *psrcdata = &srcanim->anim[w][j];
  1210. printf(" %2d : %3d %3d %3d %3d %3d %3d\n", j, psrcdata->num[0], psrcdata->num[1], psrcdata->num[2], psrcdata->num[3], psrcdata->num[4], psrcdata->num[5] );
  1211. }
  1212. */
  1213. for (iFrame = iStartFrame; iFrame <= iEndFrame; iFrame++)
  1214. {
  1215. // save animation value info
  1216. for (int j = 0; j < g_numbones; j++)
  1217. {
  1218. if (flag[j] & STUDIO_FRAME_ANIM_ROT2)
  1219. {
  1220. Quaternion q;
  1221. AngleQuaternion( srcanim->sanim[iFrame][j].rot, q );
  1222. *((Quaternion48S *)pData) = q;
  1223. pData += sizeof( Quaternion48S );
  1224. }
  1225. if (flag[j] & STUDIO_FRAME_ANIM_POS)
  1226. {
  1227. *((Vector48 *)pData) = srcanim->sanim[iFrame][j].pos;
  1228. pData += sizeof( Vector48 );
  1229. }
  1230. else if (flag[j] & STUDIO_FRAME_ANIM_POS2)
  1231. {
  1232. *((Vector *)pData) = srcanim->sanim[iFrame][j].pos;
  1233. pData += sizeof( Vector );
  1234. }
  1235. }
  1236. }
  1237. ALIGN4( pData );
  1238. }
  1239. void WriteAnimationData( s_animation_t *srcanim, mstudioanimdesc_t *destanimdesc, byte *&pLocalData, byte *&pExtData )
  1240. {
  1241. byte *pData = NULL;
  1242. for (int w = 0; w < srcanim->numsections; w++)
  1243. {
  1244. bool bUseExtData = false;
  1245. pData = pLocalData;
  1246. if (pExtData != NULL && !srcanim->disableAnimblocks && !((w * srcanim->sectionframes < srcanim->numNostallFrames) && srcanim->isFirstSectionLocal))
  1247. {
  1248. pData = pExtData;
  1249. bUseExtData = true;
  1250. }
  1251. byte *pStartSection = pData;
  1252. // use frameanim if not lowres data
  1253. if (pExtData != NULL && !g_bAnimblockLowRes)
  1254. {
  1255. srcanim->flags |= STUDIO_FRAMEANIM;
  1256. destanimdesc->flags |= STUDIO_FRAMEANIM;
  1257. }
  1258. if (srcanim->flags & STUDIO_FRAMEANIM )
  1259. {
  1260. WriteFrameAnimationData( srcanim, destanimdesc, pData, w );
  1261. }
  1262. else
  1263. {
  1264. WriteRLEAnimationData( srcanim, destanimdesc, pData, w );
  1265. }
  1266. if ( ( pData - pStartSection ) > g_animblocksize && g_animblocksize > 0 )
  1267. {
  1268. MdlWarning( "Single animation \"%s\" is %d. Specificed block size is %d. Use smaller animations or increase the block size.\n", srcanim->name, (int)( pData - pStartSection ) , g_animblocksize);
  1269. }
  1270. // write into anim blocks if needed
  1271. if (destanimdesc->sectionindex)
  1272. {
  1273. if (bUseExtData)
  1274. {
  1275. if (g_numanimblocks && pData - g_animblock[g_numanimblocks-1].start > g_animblocksize)
  1276. {
  1277. // advance to next animblock
  1278. g_animblock[g_numanimblocks-1].end = pStartSection;
  1279. g_animblock[g_numanimblocks].start = pStartSection;
  1280. g_numanimblocks++;
  1281. }
  1282. destanimdesc->pSection(w)->animblock = g_numanimblocks - 1;
  1283. destanimdesc->pSection(w)->animindex = pStartSection - g_animblock[g_numanimblocks-1].start;
  1284. }
  1285. else
  1286. {
  1287. destanimdesc->pSection(w)->animblock = 0;
  1288. destanimdesc->pSection(w)->animindex = pStartSection - (byte *)destanimdesc;
  1289. }
  1290. // printf("%s (%d) : %d:%d\n", srcanim->name, w, destanimdesc->pSection(w)->animblock, destanimdesc->pSection(w)->animindex );
  1291. }
  1292. if (!bUseExtData)
  1293. {
  1294. pLocalData = pData;
  1295. }
  1296. else
  1297. {
  1298. pExtData = pData;
  1299. }
  1300. }
  1301. }
  1302. byte *WriteIkErrors( s_animation_t *srcanim, byte *pData )
  1303. {
  1304. int j, k;
  1305. // write IK error keys
  1306. mstudioikrule_t *pikruledata = (mstudioikrule_t *)pData;
  1307. pData += srcanim->numikrules * sizeof( *pikruledata );
  1308. ALIGN4( pData );
  1309. for (j = 0; j < srcanim->numikrules; j++)
  1310. {
  1311. mstudioikrule_t *pikrule = pikruledata + j;
  1312. pikrule->index = srcanim->ikrule[j].index;
  1313. pikrule->chain = srcanim->ikrule[j].chain;
  1314. pikrule->bone = srcanim->ikrule[j].bone;
  1315. pikrule->type = srcanim->ikrule[j].type;
  1316. pikrule->slot = srcanim->ikrule[j].slot;
  1317. pikrule->pos = srcanim->ikrule[j].pos;
  1318. pikrule->q = srcanim->ikrule[j].q;
  1319. pikrule->height = srcanim->ikrule[j].height;
  1320. pikrule->floor = srcanim->ikrule[j].floor;
  1321. pikrule->radius = srcanim->ikrule[j].radius;
  1322. if (srcanim->numframes > 1.0)
  1323. {
  1324. pikrule->start = srcanim->ikrule[j].start / (srcanim->numframes - 1.0f);
  1325. pikrule->peak = srcanim->ikrule[j].peak / (srcanim->numframes - 1.0f);
  1326. pikrule->tail = srcanim->ikrule[j].tail / (srcanim->numframes - 1.0f);
  1327. pikrule->end = srcanim->ikrule[j].end / (srcanim->numframes - 1.0f);
  1328. pikrule->contact= srcanim->ikrule[j].contact / (srcanim->numframes - 1.0f);
  1329. }
  1330. else
  1331. {
  1332. pikrule->start = 0.0f;
  1333. pikrule->peak = 0.0f;
  1334. pikrule->tail = 1.0f;
  1335. pikrule->end = 1.0f;
  1336. pikrule->contact= 0.0f;
  1337. }
  1338. /*
  1339. printf("%d %d %d %d : %.2f %.2f %.2f %.2f\n",
  1340. srcanim->ikrule[j].start, srcanim->ikrule[j].peak, srcanim->ikrule[j].tail, srcanim->ikrule[j].end,
  1341. pikrule->start, pikrule->peak, pikrule->tail, pikrule->end );
  1342. */
  1343. pikrule->iStart = srcanim->ikrule[j].start;
  1344. #if 0
  1345. // uncompressed
  1346. pikrule->ikerrorindex = (pData - (byte*)pikrule);
  1347. mstudioikerror_t *perror = (mstudioikerror_t *)pData;
  1348. pData += srcanim->ikrule[j].numerror * sizeof( *perror );
  1349. for (k = 0; k < srcanim->ikrule[j].numerror; k++)
  1350. {
  1351. perror[k].pos = srcanim->ikrule[j].pError[k].pos;
  1352. perror[k].q = srcanim->ikrule[j].pError[k].q;
  1353. }
  1354. #endif
  1355. #if 1
  1356. // skip writting the header if there's no IK data
  1357. for (k = 0; k < 6; k++)
  1358. {
  1359. if (srcanim->ikrule[j].errorData.numanim[k]) break;
  1360. }
  1361. if (k == 6)
  1362. continue;
  1363. // compressed
  1364. pikrule->compressedikerrorindex = (pData - (byte*)pikrule);
  1365. mstudiocompressedikerror_t *pCompressed = (mstudiocompressedikerror_t *)pData;
  1366. pData += sizeof( *pCompressed );
  1367. for (k = 0; k < 6; k++)
  1368. {
  1369. pCompressed->scale[k] = srcanim->ikrule[j].errorData.scale[k];
  1370. pCompressed->offset[k] = (pData - (byte*)pCompressed);
  1371. int size = srcanim->ikrule[j].errorData.numanim[k] * sizeof( mstudioanimvalue_t );
  1372. memmove( pData, srcanim->ikrule[j].errorData.anim[k], size );
  1373. pData += size;
  1374. }
  1375. if (strlen( srcanim->ikrule[j].attachment ) > 0)
  1376. {
  1377. // don't use string table, we're probably not in the same file.
  1378. int size = strlen( srcanim->ikrule[j].attachment ) + 1;
  1379. strcpy( (char *)pData, srcanim->ikrule[j].attachment );
  1380. pikrule->szattachmentindex = pData - (byte *)pikrule;
  1381. pData += size;
  1382. }
  1383. ALIGN4( pData );
  1384. #endif
  1385. // AddToStringTable( pikrule, &pikrule->szattachmentindex, srcanim->ikrule[j].attachment );
  1386. }
  1387. return pData;
  1388. }
  1389. byte *WriteLocalHierarchy( s_animation_t *srcanim, byte *pData )
  1390. {
  1391. int j, k;
  1392. // write hierarchy keys
  1393. mstudiolocalhierarchy_t *pHierarchyData = (mstudiolocalhierarchy_t *)pData;
  1394. pData += srcanim->numlocalhierarchy * sizeof( *pHierarchyData );
  1395. ALIGN4( pData );
  1396. for (j = 0; j < srcanim->numlocalhierarchy; j++)
  1397. {
  1398. mstudiolocalhierarchy_t *pHierarchy = pHierarchyData + j;
  1399. pHierarchy->iBone = srcanim->localhierarchy[j].bone;
  1400. pHierarchy->iNewParent = srcanim->localhierarchy[j].newparent;
  1401. if (srcanim->numframes > 1.0)
  1402. {
  1403. pHierarchy->start = srcanim->localhierarchy[j].start / (srcanim->numframes - 1.0f);
  1404. pHierarchy->peak = srcanim->localhierarchy[j].peak / (srcanim->numframes - 1.0f);
  1405. pHierarchy->tail = srcanim->localhierarchy[j].tail / (srcanim->numframes - 1.0f);
  1406. pHierarchy->end = srcanim->localhierarchy[j].end / (srcanim->numframes - 1.0f);
  1407. }
  1408. else
  1409. {
  1410. pHierarchy->start = 0.0f;
  1411. pHierarchy->peak = 0.0f;
  1412. pHierarchy->tail = 1.0f;
  1413. pHierarchy->end = 1.0f;
  1414. }
  1415. pHierarchy->iStart = srcanim->localhierarchy[j].start;
  1416. #if 0
  1417. // uncompressed
  1418. pHierarchy->ikerrorindex = (pData - (byte*)pHierarchy);
  1419. mstudioikerror_t *perror = (mstudioikerror_t *)pData;
  1420. pData += srcanim->ikrule[j].numerror * sizeof( *perror );
  1421. for (k = 0; k < srcanim->ikrule[j].numerror; k++)
  1422. {
  1423. perror[k].pos = srcanim->ikrule[j].pError[k].pos;
  1424. perror[k].q = srcanim->ikrule[j].pError[k].q;
  1425. }
  1426. #endif
  1427. #if 1
  1428. // skip writting the header if there's no IK data
  1429. for (k = 0; k < 6; k++)
  1430. {
  1431. if (srcanim->localhierarchy[j].localData.numanim[k]) break;
  1432. }
  1433. if (k == 6)
  1434. continue;
  1435. // compressed
  1436. pHierarchy->localanimindex = (pData - (byte*)pHierarchy);
  1437. mstudiocompressedikerror_t *pCompressed = (mstudiocompressedikerror_t *)pData;
  1438. pData += sizeof( *pCompressed );
  1439. for (k = 0; k < 6; k++)
  1440. {
  1441. pCompressed->scale[k] = srcanim->localhierarchy[j].localData.scale[k];
  1442. pCompressed->offset[k] = (pData - (byte*)pCompressed);
  1443. int size = srcanim->localhierarchy[j].localData.numanim[k] * sizeof( mstudioanimvalue_t );
  1444. memmove( pData, srcanim->localhierarchy[j].localData.anim[k], size );
  1445. pData += size;
  1446. }
  1447. ALIGN4( pData );
  1448. #endif
  1449. // AddToStringTable( pHierarchy, &pHierarchy->szattachmentindex, srcanim->ikrule[j].attachment );
  1450. }
  1451. return pData;
  1452. }
  1453. static byte *WriteAnimations( byte *pData, byte *pStart, studiohdr_t *phdr )
  1454. {
  1455. int i, j;
  1456. mstudioanimdesc_t *panimdesc;
  1457. // save animations
  1458. panimdesc = (mstudioanimdesc_t *)pData;
  1459. if( phdr )
  1460. {
  1461. phdr->numlocalanim = g_numani;
  1462. phdr->localanimindex = (pData - pStart);
  1463. }
  1464. pData += g_numani * sizeof( *panimdesc );
  1465. ALIGN4( pData );
  1466. // ------------ ------- ------- : ------- (-------)
  1467. if( g_verbose )
  1468. {
  1469. printf(" animation x y ips angle\n");
  1470. }
  1471. for (i = 0; i < g_numani; i++)
  1472. {
  1473. s_animation_t *srcanim = g_panimation[ i ];
  1474. mstudioanimdesc_t *destanim = &panimdesc[i];
  1475. Assert( srcanim );
  1476. AddToStringTable( destanim, &destanim->sznameindex, srcanim->name );
  1477. destanim->baseptr = pStart - (byte *)destanim;
  1478. destanim->fps = srcanim->fps;
  1479. destanim->flags = srcanim->flags;
  1480. destanim->sectionframes = srcanim->sectionframes;
  1481. totalframes += srcanim->numframes;
  1482. totalseconds += srcanim->numframes / srcanim->fps;
  1483. destanim->numframes = srcanim->numframes;
  1484. // destanim->motiontype = srcanim->motiontype;
  1485. // destanim->motionbone = srcanim->motionbone;
  1486. // VectorCopy( srcanim->linearpos, destanim->linearpos );
  1487. if ( g_verbose && ( srcanim->numpiecewisekeys > 0 ) )
  1488. {
  1489. j = srcanim->numpiecewisekeys - 1;
  1490. if ( srcanim->piecewisemove[j].pos[0] != 0 || srcanim->piecewisemove[j].pos[1] != 0 )
  1491. {
  1492. float t = (srcanim->numframes - 1) / srcanim->fps;
  1493. float r = 1 / t;
  1494. float a = atan2( srcanim->piecewisemove[j].pos[1], srcanim->piecewisemove[j].pos[0] ) * (180 / M_PI);
  1495. float d = sqrt( DotProduct( srcanim->piecewisemove[j].pos, srcanim->piecewisemove[j].pos ) );
  1496. printf("%12s %7.2f %7.2f : %7.2f (%7.2f) %.1f\n", srcanim->name, srcanim->piecewisemove[j].pos[0], srcanim->piecewisemove[j].pos[1], d * r, a, t );
  1497. }
  1498. }
  1499. if (srcanim->numsections > 1)
  1500. {
  1501. destanim->sectionindex = pData - (byte *)destanim;
  1502. pData += srcanim->numsections * sizeof( mstudioanimsections_t );
  1503. }
  1504. // VectorCopy( srcanim->linearrot, destanim->linearrot );
  1505. // destanim->automoveposindex = srcanim->automoveposindex;
  1506. // destanim->automoveangleindex = srcanim->automoveangleindex;
  1507. // align all animation data to cache line boundaries
  1508. ALIGN16( pData );
  1509. ALIGN16( pBlockData );
  1510. if (pBlockStart)
  1511. {
  1512. // allocate the first block if needed
  1513. if (g_numanimblocks == 0)
  1514. {
  1515. g_numanimblocks = 1;
  1516. g_animblock[g_numanimblocks].start = pBlockData;
  1517. g_numanimblocks++;
  1518. }
  1519. }
  1520. if (!pBlockStart || (g_bonesaveframe.Count() == 0 && srcanim->numframes == 1))
  1521. {
  1522. // hack
  1523. srcanim->disableAnimblocks = true;
  1524. }
  1525. else if (g_bNoAnimblockStall)
  1526. {
  1527. srcanim->isFirstSectionLocal = true;
  1528. }
  1529. // make sure number of preload frames is initialized
  1530. if ( srcanim->numNostallFrames == 0 )
  1531. {
  1532. srcanim->numNostallFrames = srcanim->fps * g_flPreloadTime;
  1533. }
  1534. // block zero is relative to me
  1535. g_animblock[0].start = (byte *)(destanim);
  1536. byte *pAnimData = NULL;
  1537. byte *pIkData = NULL;
  1538. byte *pLocalHierarchy = NULL;
  1539. byte *pBlockEnd = pBlockData;
  1540. if (srcanim->disableAnimblocks || srcanim->isFirstSectionLocal)
  1541. {
  1542. destanim->animblock = 0;
  1543. pAnimData = pData;
  1544. WriteAnimationData( srcanim, destanim, pData, pBlockEnd );
  1545. pIkData = pData;
  1546. pLocalHierarchy = WriteIkErrors( srcanim, pIkData );
  1547. pData = WriteLocalHierarchy( srcanim, pLocalHierarchy );
  1548. }
  1549. else
  1550. {
  1551. pAnimData = pBlockEnd;
  1552. WriteAnimationData( srcanim, destanim, pData, pBlockEnd );
  1553. if ( destanim->sectionindex )
  1554. {
  1555. // if sections were written, don't move the data already written to the last block
  1556. pBlockData = pBlockEnd;
  1557. }
  1558. destanim->animblock = g_numanimblocks-1;
  1559. pIkData = pBlockEnd;
  1560. pLocalHierarchy = WriteIkErrors( srcanim, pIkData );
  1561. pBlockEnd = WriteLocalHierarchy( srcanim, pLocalHierarchy );
  1562. }
  1563. // printf("%d %x %x %x %s : %d\n", g_numanimblocks - 1, g_animblock[g_numanimblocks-1].start, pBlockData, pBlockEnd, srcanim->name, srcanim->numsections );
  1564. if (pBlockData != pBlockEnd && pBlockEnd - g_animblock[g_numanimblocks-1].start > g_animblocksize)
  1565. {
  1566. g_animblock[g_numanimblocks-1].end = pBlockData;
  1567. g_animblock[g_numanimblocks].start = pBlockData;
  1568. g_numanimblocks++;
  1569. destanim->animblock = g_numanimblocks-1;
  1570. }
  1571. destanim->animindex = pAnimData - g_animblock[destanim->animblock].start;
  1572. if ( srcanim->numikrules )
  1573. {
  1574. destanim->numikrules = srcanim->numikrules;
  1575. if (destanim->animblock == 0)
  1576. {
  1577. destanim->ikruleindex = pIkData - g_animblock[destanim->animblock].start;
  1578. }
  1579. else
  1580. {
  1581. destanim->animblockikruleindex = pIkData - g_animblock[destanim->animblock].start;
  1582. }
  1583. }
  1584. if ( srcanim->numlocalhierarchy )
  1585. {
  1586. destanim->numlocalhierarchy = srcanim->numlocalhierarchy;
  1587. destanim->localhierarchyindex = pLocalHierarchy - g_animblock[destanim->animblock].start;
  1588. }
  1589. if (g_numanimblocks)
  1590. {
  1591. g_animblock[g_numanimblocks-1].end = pBlockEnd;
  1592. pBlockData = pBlockEnd;
  1593. }
  1594. // printf("%s : %d:%d\n", srcanim->name, destanim->animblock, destanim->animindex );
  1595. //if (pData != pAStart)
  1596. // printf("extra %d : %s\n", pData - (byte *)pAStart, srcanim->name);
  1597. }
  1598. if( !g_quiet )
  1599. {
  1600. /*
  1601. for (i = 0; i < g_numanimblocks; i++)
  1602. {
  1603. printf("%2d (%3d:%3d): %d\n", i, g_animblock[i].iStartAnim, g_animblock[i].iEndAnim, g_animblock[i].end - g_animblock[i].start );
  1604. }
  1605. */
  1606. }
  1607. if( !g_quiet )
  1608. {
  1609. /*
  1610. printf("raw anim data %d : %d\n", rawanimbytes, animboneframes );
  1611. printf("pos %d %d %d %d\n", numPos[0], numPos[1], numPos[2], numPos[3] );
  1612. printf("axis %d %d %d %d : %d\n", numAxis[0], numAxis[1], numAxis[2], numAxis[3], useRaw );
  1613. */
  1614. }
  1615. // write movement keys
  1616. for (i = 0; i < g_numani; i++)
  1617. {
  1618. s_animation_t *anim = g_panimation[ i ];
  1619. // panimdesc[i].entrancevelocity = anim->entrancevelocity;
  1620. panimdesc[i].nummovements = anim->numpiecewisekeys;
  1621. if (panimdesc[i].nummovements)
  1622. {
  1623. panimdesc[i].movementindex = pData - (byte*)&panimdesc[i];
  1624. mstudiomovement_t *pmove = (mstudiomovement_t *)pData;
  1625. pData += panimdesc[i].nummovements * sizeof( *pmove );
  1626. ALIGN4( pData );
  1627. for (j = 0; j < panimdesc[i].nummovements; j++)
  1628. {
  1629. pmove[j].endframe = anim->piecewisemove[j].endframe;
  1630. pmove[j].motionflags = anim->piecewisemove[j].flags;
  1631. pmove[j].v0 = anim->piecewisemove[j].v0;
  1632. pmove[j].v1 = anim->piecewisemove[j].v1;
  1633. pmove[j].angle = RAD2DEG( anim->piecewisemove[j].rot[2] );
  1634. VectorCopy( anim->piecewisemove[j].vector, pmove[j].vector );
  1635. VectorCopy( anim->piecewisemove[j].pos, pmove[j].position );
  1636. }
  1637. }
  1638. }
  1639. // only write zero frames if the animation data is demand loaded
  1640. if (!pBlockStart)
  1641. return pData;
  1642. // calculate what bones should be have zero frame saved out
  1643. if (g_bonesaveframe.Count() == 0)
  1644. {
  1645. for (j = 0; j < g_numbones; j++)
  1646. {
  1647. if ((g_bonetable[j].parent == -1) || (g_bonetable[j].posrange.Length() >= g_flMinZeroFramePosDelta))
  1648. {
  1649. g_bonetable[j].flags |= BONE_HAS_SAVEFRAME_POS;
  1650. }
  1651. if (g_bZeroFramesHighres)
  1652. {
  1653. g_bonetable[j].flags |= BONE_HAS_SAVEFRAME_ROT64;
  1654. }
  1655. else
  1656. {
  1657. g_bonetable[j].flags |= BONE_HAS_SAVEFRAME_ROT32;
  1658. }
  1659. if ((!g_quiet) && (g_bonetable[j].flags & (BONE_HAS_SAVEFRAME_POS | BONE_HAS_SAVEFRAME_ROT64 | BONE_HAS_SAVEFRAME_ROT32)))
  1660. {
  1661. printf("$BoneSaveFrame \"%s\"", g_bonetable[j].name );
  1662. if (g_bonetable[j].flags & BONE_HAS_SAVEFRAME_POS)
  1663. {
  1664. printf(" position" );
  1665. }
  1666. if (g_bonetable[j].flags & BONE_HAS_SAVEFRAME_ROT64)
  1667. {
  1668. printf(" rotation64" );
  1669. }
  1670. else if (g_bonetable[j].flags & BONE_HAS_SAVEFRAME_ROT32)
  1671. {
  1672. printf(" rotation" );
  1673. }
  1674. if (!(g_bonetable[j].flags & BONE_HAS_SAVEFRAME_POS) && g_bonetable[j].posrange.Length() > 0.1)
  1675. {
  1676. printf(" // (%.2f)", g_bonetable[j].posrange.Length() );
  1677. }
  1678. printf("\n");
  1679. }
  1680. }
  1681. }
  1682. else
  1683. {
  1684. for (i = 0; i < g_bonesaveframe.Count(); i++)
  1685. {
  1686. j = findGlobalBone( g_bonesaveframe[i].name );
  1687. if (j != -1)
  1688. {
  1689. if (g_bonesaveframe[i].bSavePos)
  1690. {
  1691. g_bonetable[j].flags |= BONE_HAS_SAVEFRAME_POS;
  1692. }
  1693. if (g_bonesaveframe[i].bSaveRot)
  1694. {
  1695. if (g_bZeroFramesHighres)
  1696. {
  1697. g_bonetable[j].flags |= BONE_HAS_SAVEFRAME_ROT64;
  1698. }
  1699. else
  1700. {
  1701. g_bonetable[j].flags |= BONE_HAS_SAVEFRAME_ROT32;
  1702. }
  1703. }
  1704. else if (g_bonesaveframe[i].bSaveRot64)
  1705. {
  1706. g_bonetable[j].flags |= BONE_HAS_SAVEFRAME_ROT64;
  1707. }
  1708. }
  1709. else
  1710. {
  1711. MdlError("Unknown $BoneSaveFrame \"%s\"\n", g_bonesaveframe[i].name );
  1712. }
  1713. }
  1714. }
  1715. for (j = 0; j < g_numbones; j++)
  1716. {
  1717. ((mstudiobone_t *)phdr->pBone(j))->flags |= g_bonetable[j].flags;
  1718. }
  1719. ALIGN4( pData );
  1720. // write zero frames
  1721. for (i = 0; i < g_numani; i++)
  1722. {
  1723. s_animation_t *anim = g_panimation[ i ];
  1724. mstudioanimdesc_t *destanim = &panimdesc[i];
  1725. if (destanim->animblock != 0)
  1726. {
  1727. destanim->zeroframeindex = pData - (byte *)destanim;
  1728. int k = MIN( destanim->numframes - 1, 9 );
  1729. if (destanim->flags & STUDIO_LOOPING)
  1730. {
  1731. k = MIN( (destanim->numframes - 1) / 2, k );
  1732. }
  1733. destanim->zeroframespan = k;
  1734. if (k > 2)
  1735. {
  1736. destanim->zeroframecount = MIN( (destanim->numframes - 1) / destanim->zeroframespan, 3 ); // save frames 0..24 frames
  1737. }
  1738. if (destanim->zeroframecount < 1)
  1739. destanim->zeroframecount = 1;
  1740. destanim->zeroframecount = MIN( destanim->zeroframecount, g_nMaxZeroFrames );
  1741. for (j = 0; j < g_numbones; j++)
  1742. {
  1743. if (g_bonetable[j].flags & BONE_HAS_SAVEFRAME_POS)
  1744. {
  1745. for (int n = 0; n < destanim->zeroframecount; n++)
  1746. {
  1747. *(Vector48 *)pData = anim->sanim[destanim->zeroframespan*n][j].pos;
  1748. pData += sizeof( Vector48 );
  1749. }
  1750. }
  1751. if (g_bonetable[j].flags & BONE_HAS_SAVEFRAME_ROT64)
  1752. {
  1753. for (int n = 0; n < destanim->zeroframecount; n++)
  1754. {
  1755. Quaternion q;
  1756. AngleQuaternion( anim->sanim[destanim->zeroframespan*n][j].rot, q );
  1757. *((Quaternion64 *)pData) = q;
  1758. pData += sizeof( Quaternion64 );
  1759. }
  1760. }
  1761. else if (g_bonetable[j].flags & BONE_HAS_SAVEFRAME_ROT32)
  1762. {
  1763. for (int n = 0; n < destanim->zeroframecount; n++)
  1764. {
  1765. Quaternion q;
  1766. AngleQuaternion( anim->sanim[destanim->zeroframespan*n][j].rot, q );
  1767. *((Quaternion32 *)pData) = q;
  1768. pData += sizeof( Quaternion32 );
  1769. }
  1770. }
  1771. }
  1772. ALIGN4( pData );
  1773. // write zero frame IK data
  1774. if (destanim->numikrules)
  1775. {
  1776. mstudioikrulezeroframe_t *pdestikrule = (mstudioikrulezeroframe_t *)pData;
  1777. destanim->ikrulezeroframeindex = pData - (byte *)destanim;
  1778. pData += sizeof( *pdestikrule ) * destanim->numikrules;
  1779. // printf("%s : %d : %d %x : %x %x\n", phdr->name, destanim->numikrules, destanim->animblock, destanim->ikruleindex, destanim->animblockikruleindex, destanim->ikrulezeroframeindex );
  1780. mstudioikrule_t *psrcikrule;
  1781. if (destanim->ikruleindex)
  1782. {
  1783. psrcikrule = (mstudioikrule_t *)((byte *)destanim + destanim->ikruleindex);
  1784. }
  1785. else
  1786. {
  1787. psrcikrule = (mstudioikrule_t *)(g_animblock[destanim->animblock].start + destanim->animblockikruleindex);
  1788. }
  1789. for (j = 0; j < destanim->numikrules; j++, psrcikrule++, pdestikrule++ )
  1790. {
  1791. pdestikrule->slot = psrcikrule->slot;
  1792. pdestikrule->chain = psrcikrule->chain;
  1793. pdestikrule->start.SetFloat( psrcikrule->start );
  1794. pdestikrule->peak.SetFloat( psrcikrule->peak );
  1795. pdestikrule->tail.SetFloat( psrcikrule->tail );
  1796. pdestikrule->end.SetFloat( psrcikrule->end );
  1797. }
  1798. }
  1799. ALIGN4( pData );
  1800. }
  1801. }
  1802. ALIGN4( pData );
  1803. return pData;
  1804. }
  1805. static void WriteTextures( studiohdr_t *phdr )
  1806. {
  1807. int i, j;
  1808. short *pref;
  1809. // save texture info
  1810. mstudiotexture_t *ptexture = (mstudiotexture_t *)pData;
  1811. phdr->numtextures = g_nummaterials;
  1812. phdr->textureindex = pData - pStart;
  1813. pData += g_nummaterials * sizeof( mstudiotexture_t );
  1814. for (i = 0; i < g_nummaterials; i++)
  1815. {
  1816. j = g_material[i];
  1817. AddToStringTable( &ptexture[i], &ptexture[i].sznameindex, g_texture[j].name );
  1818. }
  1819. ALIGN4( pData );
  1820. int *cdtextureoffset = (int *)pData;
  1821. phdr->numcdtextures = numcdtextures;
  1822. phdr->cdtextureindex = pData - pStart;
  1823. pData += numcdtextures * sizeof( int );
  1824. for (i = 0; i < numcdtextures; i++)
  1825. {
  1826. AddToStringTable( phdr, &cdtextureoffset[i], cdtextures[i] );
  1827. }
  1828. ALIGN4( pData );
  1829. // save texture directory info
  1830. phdr->skinindex = (pData - pStart);
  1831. phdr->numskinref = g_numskinref;
  1832. phdr->numskinfamilies = g_numskinfamilies;
  1833. pref = (short *)pData;
  1834. for (i = 0; i < phdr->numskinfamilies; i++)
  1835. {
  1836. for (j = 0; j < phdr->numskinref; j++)
  1837. {
  1838. *pref = g_skinref[i][j];
  1839. pref++;
  1840. }
  1841. }
  1842. pData = (byte *)pref;
  1843. ALIGN4( pData );
  1844. }
  1845. //-----------------------------------------------------------------------------
  1846. // Write source bone transforms
  1847. //-----------------------------------------------------------------------------
  1848. static void WriteBoneTransforms( studiohdr2_t *phdr, const mstudiobone_t *pBone )
  1849. {
  1850. matrix3x4_t identity;
  1851. SetIdentityMatrix( identity );
  1852. int nTransformCount = 0;
  1853. for (int i = 0; i < g_numbones; i++)
  1854. {
  1855. if ( g_bonetable[i].flags & BONE_ALWAYS_PROCEDURAL )
  1856. continue;
  1857. int nParent = g_bonetable[i].parent;
  1858. // Transformation is necessary if either you or your parent was realigned
  1859. if ( MatricesAreEqual( identity, g_bonetable[i].srcRealign ) &&
  1860. ( ( nParent < 0 ) || MatricesAreEqual( identity, g_bonetable[nParent].srcRealign ) ) )
  1861. continue;
  1862. ++nTransformCount;
  1863. }
  1864. // save bone transform info
  1865. mstudiosrcbonetransform_t *pSrcBoneTransform = (mstudiosrcbonetransform_t *)pData;
  1866. phdr->numsrcbonetransform = nTransformCount;
  1867. phdr->srcbonetransformindex = pData - pStart;
  1868. pData += nTransformCount * sizeof( mstudiosrcbonetransform_t );
  1869. int bt = 0;
  1870. for ( int i = 0; i < g_numbones; i++ )
  1871. {
  1872. if ( g_bonetable[i].flags & BONE_ALWAYS_PROCEDURAL )
  1873. continue;
  1874. int nParent = g_bonetable[i].parent;
  1875. if ( MatricesAreEqual( identity, g_bonetable[i].srcRealign ) &&
  1876. ( ( nParent < 0 ) || MatricesAreEqual( identity, g_bonetable[nParent].srcRealign ) ) )
  1877. continue;
  1878. // What's going on here?
  1879. // So, when we realign a bone, we want to do it in a way so that the child bones
  1880. // have the same bone->world transform. If we take T as the src realignment transform
  1881. // for the parent, P is the parent to world, and C is the child to parent, we expect
  1882. // the child->world is constant after realignment:
  1883. // CtoW = P * C = ( P * T ) * ( T^-1 * C )
  1884. // therefore Cnew = ( T^-1 * C )
  1885. if ( nParent >= 0 )
  1886. {
  1887. MatrixInvert( g_bonetable[nParent].srcRealign, pSrcBoneTransform[bt].pretransform );
  1888. }
  1889. else
  1890. {
  1891. SetIdentityMatrix( pSrcBoneTransform[bt].pretransform );
  1892. }
  1893. MatrixCopy( g_bonetable[i].srcRealign, pSrcBoneTransform[bt].posttransform );
  1894. AddToStringTable( &pSrcBoneTransform[bt], &pSrcBoneTransform[bt].sznameindex, g_bonetable[i].name );
  1895. ++bt;
  1896. }
  1897. ALIGN4( pData );
  1898. if (g_numbones > 1)
  1899. {
  1900. // write second bone table
  1901. phdr->linearboneindex = pData - (byte *)phdr;
  1902. mstudiolinearbone_t *pLinearBone = (mstudiolinearbone_t *)pData;
  1903. pData += sizeof( *pLinearBone );
  1904. pLinearBone->numbones = g_numbones;
  1905. #define WRITE_BONE_BLOCK( type, srcfield, dest, destindex ) \
  1906. type *##dest = (type *)pData; \
  1907. pLinearBone->##destindex = pData - (byte *)pLinearBone; \
  1908. pData += g_numbones * sizeof( *##dest ); \
  1909. ALIGN4( pData ); \
  1910. for ( int i = 0; i < g_numbones; i++) \
  1911. dest##[i] = pBone[i].##srcfield;
  1912. WRITE_BONE_BLOCK( int, flags, pFlags, flagsindex );
  1913. WRITE_BONE_BLOCK( int, parent, pParent, parentindex );
  1914. WRITE_BONE_BLOCK( Vector, pos, pPos, posindex );
  1915. WRITE_BONE_BLOCK( Quaternion, quat, pQuat, quatindex );
  1916. WRITE_BONE_BLOCK( RadianEuler, rot, pRot, rotindex );
  1917. WRITE_BONE_BLOCK( matrix3x4_t, poseToBone, pPoseToBone, posetoboneindex );
  1918. WRITE_BONE_BLOCK( Vector, posscale, pPoseScale, posscaleindex );
  1919. WRITE_BONE_BLOCK( Vector, rotscale, pRotScale, rotscaleindex );
  1920. WRITE_BONE_BLOCK( Quaternion, qAlignment, pQAlignment, qalignmentindex );
  1921. }
  1922. }
  1923. static void WriteBodyGroupPresets( studiohdr2_t *pStudioHdr2 )
  1924. {
  1925. ALIGN4( pData );
  1926. pStudioHdr2->m_nBodyGroupPresetCount = g_numbodygrouppresets;
  1927. pStudioHdr2->m_nBodyGroupPresetIndex = 0;
  1928. if ( g_numbodygrouppresets <= 0 )
  1929. return;
  1930. mstudiobodygrouppreset_t *pBodygroupPreset = (mstudiobodygrouppreset_t *)pData;
  1931. pStudioHdr2->m_nBodyGroupPresetIndex = pData - (byte *)pStudioHdr2;
  1932. pData += g_numbodygrouppresets * sizeof( mstudiobodygrouppreset_t );
  1933. ALIGN4( pData );
  1934. for ( int i=0; i<g_numbodygrouppresets; i++ )
  1935. {
  1936. AddToStringTable( &pBodygroupPreset[i], &pBodygroupPreset[i].sznameindex, g_bodygrouppresets[i].name );
  1937. pBodygroupPreset[i].iValue = g_bodygrouppresets[i].iValue;
  1938. pBodygroupPreset[i].iMask = g_bodygrouppresets[i].iMask;
  1939. ALIGN4( pData );
  1940. }
  1941. }
  1942. //-----------------------------------------------------------------------------
  1943. // Write the bone flex drivers
  1944. //-----------------------------------------------------------------------------
  1945. static void WriteBoneFlexDrivers( studiohdr2_t *pStudioHdr2 )
  1946. {
  1947. ALIGN4( pData );
  1948. pStudioHdr2->m_nBoneFlexDriverCount = 0;
  1949. pStudioHdr2->m_nBoneFlexDriverIndex = 0;
  1950. CDmeBoneFlexDriverList *pDmeBoneFlexDriverList = GetElement< CDmeBoneFlexDriverList >( g_hDmeBoneFlexDriverList );
  1951. if ( !pDmeBoneFlexDriverList )
  1952. return;
  1953. const int nBoneFlexDriverCount = pDmeBoneFlexDriverList->m_eBoneFlexDriverList.Count();
  1954. if ( nBoneFlexDriverCount <= 0 )
  1955. return;
  1956. mstudioboneflexdriver_t *pBoneFlexDriver = (mstudioboneflexdriver_t *)pData;
  1957. pStudioHdr2->m_nBoneFlexDriverCount = nBoneFlexDriverCount;
  1958. pStudioHdr2->m_nBoneFlexDriverIndex = pData - (byte *)pStudioHdr2;
  1959. pData += nBoneFlexDriverCount * sizeof( mstudioboneflexdriver_t );
  1960. ALIGN4( pData );
  1961. for ( int i = 0; i < nBoneFlexDriverCount; ++i )
  1962. {
  1963. CDmeBoneFlexDriver *pDmeBoneFlexDriver = pDmeBoneFlexDriverList->m_eBoneFlexDriverList[i];
  1964. Assert( pDmeBoneFlexDriver );
  1965. Assert( pDmeBoneFlexDriver->m_eControlList.Count() > 0 );
  1966. Assert( pDmeBoneFlexDriver->GetValue< int >( "__boneIndex", -1 ) >= 0 );
  1967. pBoneFlexDriver->m_nBoneIndex = pDmeBoneFlexDriver->GetValue< int >( "__boneIndex", 0 );
  1968. pBoneFlexDriver->m_nControlCount = pDmeBoneFlexDriver->m_eControlList.Count();
  1969. pBoneFlexDriver->m_nControlIndex = pData - (byte *)pBoneFlexDriver;
  1970. mstudioboneflexdrivercontrol_t *pControl = reinterpret_cast< mstudioboneflexdrivercontrol_t * >( pData );
  1971. for ( int j = 0; j < pBoneFlexDriver->m_nControlCount; ++j )
  1972. {
  1973. CDmeBoneFlexDriverControl *pDmeControl = pDmeBoneFlexDriver->m_eControlList[j];
  1974. Assert( pDmeControl );
  1975. Assert( pDmeControl->GetValue< int >( "__flexControlIndex", -1 ) >= 0 );
  1976. Assert( pDmeControl->m_nBoneComponent >= STUDIO_BONE_FLEX_TX );
  1977. Assert( pDmeControl->m_nBoneComponent <= STUDIO_BONE_FLEX_TZ );
  1978. pControl[j].m_nFlexControllerIndex = pDmeControl->GetValue< int >( "__flexControlIndex", 0 );
  1979. pControl[j].m_nBoneComponent = pDmeControl->m_nBoneComponent;
  1980. pControl[j].m_flMin = pDmeControl->m_flMin;
  1981. pControl[j].m_flMax = pDmeControl->m_flMax;
  1982. }
  1983. pData += pBoneFlexDriver->m_nControlCount * sizeof( mstudioboneflexdrivercontrol_t );
  1984. ALIGN4( pData );
  1985. ++pBoneFlexDriver;
  1986. }
  1987. }
  1988. //-----------------------------------------------------------------------------
  1989. // Write the processed vertices
  1990. //-----------------------------------------------------------------------------
  1991. static void WriteVertices( studiohdr_t *phdr )
  1992. {
  1993. char fileName[MAX_PATH];
  1994. byte *pStart;
  1995. byte *pData;
  1996. int i;
  1997. int j;
  1998. int k;
  1999. int cur;
  2000. bool bExtraData = (phdr->flags & STUDIOHDR_FLAGS_EXTRA_VERTEX_DATA) != 0;
  2001. if (!g_nummodelsbeforeLOD)
  2002. return;
  2003. strcpy( fileName, gamedir );
  2004. // if( *g_pPlatformName )
  2005. // {
  2006. // strcat( fileName, "platform_" );
  2007. // strcat( fileName, g_pPlatformName );
  2008. // strcat( fileName, "/" );
  2009. // }
  2010. strcat( fileName, "models/" );
  2011. strcat( fileName, g_outname );
  2012. Q_StripExtension( fileName, fileName, sizeof( fileName ) );
  2013. strcat( fileName, ".vvd" );
  2014. if ( !g_quiet )
  2015. {
  2016. printf ("---------------------\n");
  2017. printf ("writing %s:\n", fileName);
  2018. }
  2019. pStart = (byte *)kalloc( 1, FILEBUFFER );
  2020. pData = pStart;
  2021. vertexFileHeader_t *fileHeader = (vertexFileHeader_t *)pData;
  2022. pData += sizeof(vertexFileHeader_t);
  2023. fileHeader->id = MODEL_VERTEX_FILE_ID;
  2024. fileHeader->version = MODEL_VERTEX_FILE_VERSION;
  2025. fileHeader->checksum = phdr->checksum;
  2026. // data has no fixes and requires no fixes
  2027. fileHeader->numFixups = 0;
  2028. fileHeader->fixupTableStart = 0;
  2029. // unfinalized during first pass, fixed during second pass
  2030. // data can be considered as single lod at lod 0
  2031. fileHeader->numLODs = 1;
  2032. fileHeader->numLODVertexes[0] = 0;
  2033. // store vertexes grouped by mesh order
  2034. ALIGN16( pData );
  2035. fileHeader->vertexDataStart = pData-pStart;
  2036. for (i = 0; i < g_nummodelsbeforeLOD; i++)
  2037. {
  2038. s_loddata_t *pLodData = g_model[i]->m_pLodData;
  2039. // skip blank empty model
  2040. if (!pLodData)
  2041. continue;
  2042. // save vertices
  2043. ALIGN16( pData );
  2044. cur = (int)pData;
  2045. mstudiovertex_t *pVert = (mstudiovertex_t *)pData;
  2046. pData += pLodData->numvertices * sizeof( mstudiovertex_t );
  2047. for (j = 0; j < pLodData->numvertices; j++)
  2048. {
  2049. // printf( "saving bone weight %d for model %d at 0x%p\n",
  2050. // j, i, &pbone[j] );
  2051. const s_vertexinfo_t &lodVertex = pLodData->vertex[j];
  2052. VectorCopy( lodVertex.position, pVert[j].m_vecPosition );
  2053. VectorCopy( lodVertex.normal, pVert[j].m_vecNormal );
  2054. Vector2DCopy( lodVertex.texcoord[0], pVert[j].m_vecTexCoord );
  2055. mstudioboneweight_t *pBoneWeight = &pVert[j].m_BoneWeights;
  2056. memset( pBoneWeight, 0, sizeof( mstudioboneweight_t ) );
  2057. pBoneWeight->numbones = lodVertex.boneweight.numbones;
  2058. for (k = 0; k < pBoneWeight->numbones; k++)
  2059. {
  2060. pBoneWeight->bone[k] = lodVertex.boneweight.bone[k];
  2061. pBoneWeight->weight[k] = lodVertex.boneweight.weight[k];
  2062. }
  2063. }
  2064. fileHeader->numLODVertexes[0] += pLodData->numvertices;
  2065. if (!g_quiet)
  2066. {
  2067. printf( "vertices %7d bytes (%d vertices)\n", (int)(pData - cur), pLodData->numvertices );
  2068. }
  2069. }
  2070. // store tangents grouped by mesh order
  2071. ALIGN4( pData );
  2072. fileHeader->tangentDataStart = pData-pStart;
  2073. for (i = 0; i < g_nummodelsbeforeLOD; i++)
  2074. {
  2075. s_loddata_t *pLodData = g_model[i]->m_pLodData;
  2076. // skip blank empty model
  2077. if (!pLodData)
  2078. continue;
  2079. // save tangent space S
  2080. ALIGN4( pData );
  2081. cur = (int)pData;
  2082. Vector4D *ptangents = (Vector4D *)pData;
  2083. pData += pLodData->numvertices * sizeof( Vector4D );
  2084. for (j = 0; j < pLodData->numvertices; j++)
  2085. {
  2086. Vector4DCopy( pLodData->vertex[j].tangentS, ptangents[j] );
  2087. #ifdef _DEBUG
  2088. float w = ptangents[j].w;
  2089. Assert( w == 1.0f || w == -1.0f );
  2090. #endif
  2091. }
  2092. if (!g_quiet)
  2093. {
  2094. printf( "tangents %7d bytes (%d vertices)\n", (int)(pData - cur), pLodData->numvertices );
  2095. }
  2096. }
  2097. if ( bExtraData )
  2098. {
  2099. ALIGN4( pData );
  2100. cur = (int)pData;
  2101. byte* pExtraDataStart = pData;
  2102. ExtraVertexAttributesHeader_t* pExtraheader = (ExtraVertexAttributesHeader_t*)pData;
  2103. pData += sizeof( ExtraVertexAttributesHeader_t );
  2104. pExtraheader->m_count = sExtraTexcoordsToWrite;
  2105. ExtraVertexAttributeIndex_t* pIndex = (ExtraVertexAttributeIndex_t*)pData;
  2106. pData += sizeof( ExtraVertexAttributeIndex_t ) * sExtraTexcoordsToWrite;
  2107. for ( int e = 0; e < sExtraTexcoordsToWrite; ++e )
  2108. {
  2109. ALIGN4( pData );
  2110. // Populate Index: type and byteoffset
  2111. pIndex[e].m_type = (ExtraVertexAttributeType_t)(STUDIO_EXTRA_ATTRIBUTE_TEXCOORD0 + e + 1);
  2112. pIndex[e].m_offset = (int)(pData - pExtraDataStart);
  2113. pIndex[e].m_bytes = 2 * sizeof( float );
  2114. // store extra vertex data, one entry per vertex, order matches main vertex data
  2115. for ( i = 0; i < g_nummodelsbeforeLOD; i++ )
  2116. {
  2117. s_loddata_t *pLodData = g_model[i]->m_pLodData;
  2118. // skip blank empty model
  2119. if ( !pLodData )
  2120. continue;
  2121. // save extra texcoord
  2122. cur = (int)pData;
  2123. float* pExtraTexcoord = (float*)pData;
  2124. for ( j = 0; j < pLodData->numvertices; j++ )
  2125. {
  2126. const s_vertexinfo_t &lodVertex = pLodData->vertex[j];
  2127. *pExtraTexcoord = lodVertex.texcoord[e + 1].x;
  2128. pExtraTexcoord++;
  2129. *pExtraTexcoord = lodVertex.texcoord[e + 1].y;
  2130. pExtraTexcoord++;
  2131. }
  2132. pData = (byte*)pExtraTexcoord;
  2133. if ( !g_quiet )
  2134. {
  2135. printf( "extra vertex data %7d bytes (%d vertices)\n", (int)(pData - cur), pLodData->numvertices );
  2136. }
  2137. }
  2138. }
  2139. pExtraheader->m_totalbytes = (int)(pData - pExtraDataStart);
  2140. }
  2141. if (!g_quiet)
  2142. {
  2143. printf( "total %7d bytes\n", pData - pStart );
  2144. }
  2145. // fileHeader->length = pData - pStart;
  2146. {
  2147. CP4AutoEditAddFile autop4( fileName );
  2148. SaveFile( fileName, pStart, pData - pStart );
  2149. }
  2150. }
  2151. //-----------------------------------------------------------------------------
  2152. // Computes the maximum absolute value of any component of all vertex animation
  2153. // pos (x,y,z) normal (x,y,z) or wrinkle
  2154. //
  2155. // Returns the fixed point scale and also sets appropriate values & flags in
  2156. // passed studiohdr_t
  2157. //-----------------------------------------------------------------------------
  2158. float ComputeVertAnimFixedPointScale( studiohdr_t *pStudioHdr )
  2159. {
  2160. float flVertAnimRange = 0.0f;
  2161. for ( int j = 0; j < g_numflexkeys; ++j )
  2162. {
  2163. if ( g_flexkey[j].numvanims <= 0 )
  2164. continue;
  2165. const bool bWrinkleVAnim = ( g_flexkey[j].vanimtype == STUDIO_VERT_ANIM_WRINKLE );
  2166. s_vertanim_t *pVertAnim = g_flexkey[j].vanim;
  2167. for ( int k = 0; k < g_flexkey[j].numvanims; ++k )
  2168. {
  2169. if ( fabs( pVertAnim->pos.x ) > flVertAnimRange )
  2170. {
  2171. flVertAnimRange = fabs( pVertAnim->pos.x );
  2172. }
  2173. if ( fabs( pVertAnim->pos.y ) > flVertAnimRange )
  2174. {
  2175. flVertAnimRange = fabs( pVertAnim->pos.y );
  2176. }
  2177. if ( fabs( pVertAnim->pos.z ) > flVertAnimRange )
  2178. {
  2179. flVertAnimRange = fabs( pVertAnim->pos.z );
  2180. }
  2181. if ( fabs( pVertAnim->normal.x ) > flVertAnimRange )
  2182. {
  2183. flVertAnimRange = fabs( pVertAnim->normal.x );
  2184. }
  2185. if ( fabs( pVertAnim->normal.y ) > flVertAnimRange )
  2186. {
  2187. flVertAnimRange = fabs( pVertAnim->normal.y );
  2188. }
  2189. if ( fabs( pVertAnim->normal.z ) > flVertAnimRange )
  2190. {
  2191. flVertAnimRange = fabs( pVertAnim->normal.z );
  2192. }
  2193. if ( bWrinkleVAnim )
  2194. {
  2195. if ( fabs( pVertAnim->wrinkle ) > flVertAnimRange )
  2196. {
  2197. flVertAnimRange = fabs( pVertAnim->wrinkle );
  2198. }
  2199. }
  2200. pVertAnim++;
  2201. }
  2202. }
  2203. // Legacy value
  2204. float flVertAnimFixedPointScale = 1.0 / 4096.0f;
  2205. if ( flVertAnimRange > 0.0f )
  2206. {
  2207. if ( flVertAnimRange > 32767 )
  2208. {
  2209. MdlWarning( "Flex value too large: %.2f, Max: 32767\n", flVertAnimRange );
  2210. flVertAnimFixedPointScale = 1.0f;
  2211. }
  2212. else
  2213. {
  2214. const float flTmpScale = flVertAnimRange / 32767.0f;
  2215. if ( flTmpScale > flVertAnimFixedPointScale )
  2216. {
  2217. flVertAnimFixedPointScale = flTmpScale;
  2218. }
  2219. }
  2220. }
  2221. if ( flVertAnimFixedPointScale != 1.0f / 4096.0f )
  2222. {
  2223. pStudioHdr->flags |= STUDIOHDR_FLAGS_VERT_ANIM_FIXED_POINT_SCALE;
  2224. pStudioHdr->flVertAnimFixedPointScale = flVertAnimFixedPointScale;
  2225. }
  2226. return flVertAnimFixedPointScale;
  2227. }
  2228. static void WriteModel( studiohdr_t *phdr )
  2229. {
  2230. int i, j, k, m;
  2231. mstudiobodyparts_t *pbodypart;
  2232. mstudiomodel_t *pmodel;
  2233. s_source_t *psource;
  2234. mstudiovertanim_t *pvertanim;
  2235. s_vertanim_t *pvanim;
  2236. int cur = (int)pData;
  2237. // vertex data is written to external file, offsets kept internal
  2238. // track expected external base to store proper offsets
  2239. byte *externalVertexIndex = 0;
  2240. byte *externalTangentsIndex = 0;
  2241. // write bodypart info
  2242. pbodypart = (mstudiobodyparts_t *)pData;
  2243. phdr->numbodyparts = g_numbodyparts;
  2244. phdr->bodypartindex = pData - pStart;
  2245. pData += g_numbodyparts * sizeof( mstudiobodyparts_t );
  2246. pmodel = (mstudiomodel_t *)pData;
  2247. pData += g_nummodelsbeforeLOD * sizeof( mstudiomodel_t );
  2248. for (i = 0, j = 0; i < g_numbodyparts; i++)
  2249. {
  2250. AddToStringTable( &pbodypart[i], &pbodypart[i].sznameindex, g_bodypart[i].name );
  2251. pbodypart[i].nummodels = g_bodypart[i].nummodels;
  2252. pbodypart[i].base = g_bodypart[i].base;
  2253. pbodypart[i].modelindex = ((byte *)&pmodel[j]) - (byte *)&pbodypart[i];
  2254. j += g_bodypart[i].nummodels;
  2255. }
  2256. ALIGN4( pData );
  2257. // write global flex names
  2258. mstudioflexdesc_t *pflexdesc = (mstudioflexdesc_t *)pData;
  2259. phdr->numflexdesc = g_numflexdesc;
  2260. phdr->flexdescindex = pData - pStart;
  2261. pData += g_numflexdesc * sizeof( mstudioflexdesc_t );
  2262. ALIGN4( pData );
  2263. for (j = 0; j < g_numflexdesc; j++)
  2264. {
  2265. // printf("%d %s\n", j, g_flexdesc[j].FACS );
  2266. AddToStringTable( pflexdesc, &pflexdesc->szFACSindex, g_flexdesc[j].FACS );
  2267. pflexdesc++;
  2268. }
  2269. // write global flex controllers
  2270. mstudioflexcontroller_t *pflexcontroller = (mstudioflexcontroller_t *)pData;
  2271. phdr->numflexcontrollers = g_numflexcontrollers;
  2272. phdr->flexcontrollerindex = pData - pStart;
  2273. pData += g_numflexcontrollers * sizeof( mstudioflexcontroller_t );
  2274. ALIGN4( pData );
  2275. for (j = 0; j < g_numflexcontrollers; j++)
  2276. {
  2277. AddToStringTable( pflexcontroller, &pflexcontroller->sznameindex, g_flexcontroller[j].name );
  2278. AddToStringTable( pflexcontroller, &pflexcontroller->sztypeindex, g_flexcontroller[j].type );
  2279. pflexcontroller->min = g_flexcontroller[j].min;
  2280. pflexcontroller->max = g_flexcontroller[j].max;
  2281. pflexcontroller->localToGlobal = -1;
  2282. pflexcontroller++;
  2283. }
  2284. // write flex rules
  2285. mstudioflexrule_t *pflexrule = (mstudioflexrule_t *)pData;
  2286. phdr->numflexrules = g_numflexrules;
  2287. phdr->flexruleindex = pData - pStart;
  2288. pData += g_numflexrules * sizeof( mstudioflexrule_t );
  2289. ALIGN4( pData );
  2290. for (j = 0; j < g_numflexrules; j++)
  2291. {
  2292. pflexrule->flex = g_flexrule[j].flex;
  2293. pflexrule->numops = g_flexrule[j].numops;
  2294. pflexrule->opindex = (pData - (byte *)pflexrule);
  2295. mstudioflexop_t *pflexop = (mstudioflexop_t *)pData;
  2296. for (i = 0; i < pflexrule->numops; i++)
  2297. {
  2298. pflexop[i].op = g_flexrule[j].op[i].op;
  2299. pflexop[i].d.index = g_flexrule[j].op[i].d.index;
  2300. }
  2301. pData += sizeof( mstudioflexop_t ) * pflexrule->numops;
  2302. ALIGN4( pData );
  2303. pflexrule++;
  2304. }
  2305. // write global flex controller information
  2306. mstudioflexcontrollerui_t *pFlexControllerUI = (mstudioflexcontrollerui_t *)pData;
  2307. phdr->numflexcontrollerui = 0;
  2308. phdr->flexcontrolleruiindex = pData - pStart;
  2309. // Loop through all defined controllers and create a UI structure for them
  2310. // All actual controllers will be defined as a member of some ui structure
  2311. // and all actual controllers can only be a member of one ui structure
  2312. bool *pControllerHandled = ( bool * )_alloca( g_numflexcontrollers * sizeof( bool ) );
  2313. memset( pControllerHandled, 0, g_numflexcontrollers * sizeof( bool ) );
  2314. for ( j = 0; j < g_numflexcontrollers; ++j )
  2315. {
  2316. // Don't handle controls twice
  2317. if ( pControllerHandled[ j ] )
  2318. continue;
  2319. const s_flexcontroller_t &flexcontroller = g_flexcontroller[ j ];
  2320. bool found = false;
  2321. // See if this controller is in the remap table
  2322. for ( k = 0; k < g_FlexControllerRemap.Count(); ++k )
  2323. {
  2324. s_flexcontrollerremap_t &remap = g_FlexControllerRemap[ k ];
  2325. if ( j == remap.m_Index || j == remap.m_LeftIndex || j == remap.m_RightIndex || j == remap.m_MultiIndex )
  2326. {
  2327. AddToStringTable( pFlexControllerUI, &pFlexControllerUI->sznameindex, remap.m_Name );
  2328. pFlexControllerUI->stereo = remap.m_bIsStereo;
  2329. if ( pFlexControllerUI->stereo )
  2330. {
  2331. Assert( !pControllerHandled[ remap.m_LeftIndex ] );
  2332. pFlexControllerUI->szindex0 = (
  2333. phdr->flexcontrollerindex - int( pData - pStart ) +
  2334. remap.m_LeftIndex * sizeof( mstudioflexcontroller_t ) );
  2335. pControllerHandled[ remap.m_LeftIndex ] = true;
  2336. Assert( !pControllerHandled[ remap.m_RightIndex ] );
  2337. pFlexControllerUI->szindex1 = (
  2338. phdr->flexcontrollerindex - int( pData - pStart ) +
  2339. remap.m_RightIndex * sizeof( mstudioflexcontroller_t ) );
  2340. pControllerHandled[ remap.m_RightIndex ] = true;
  2341. }
  2342. else
  2343. {
  2344. Assert( !pControllerHandled[ remap.m_Index ] );
  2345. pFlexControllerUI->szindex0 = (
  2346. phdr->flexcontrollerindex - int( pData - pStart ) +
  2347. remap.m_Index * sizeof( mstudioflexcontroller_t ) );
  2348. pControllerHandled[ remap.m_Index ] = true;
  2349. pFlexControllerUI->szindex1 = ( 0 );
  2350. }
  2351. pFlexControllerUI->remaptype = remap.m_RemapType;
  2352. if ( pFlexControllerUI->remaptype == FLEXCONTROLLER_REMAP_NWAY || pFlexControllerUI->remaptype == FLEXCONTROLLER_REMAP_EYELID )
  2353. {
  2354. Assert( remap.m_MultiIndex != -1 );
  2355. Assert( !pControllerHandled[ remap.m_MultiIndex ] );
  2356. pFlexControllerUI->szindex2 = (
  2357. phdr->flexcontrollerindex - int( pData - pStart ) +
  2358. remap.m_MultiIndex * sizeof( mstudioflexcontroller_t ) );
  2359. pControllerHandled[ remap.m_MultiIndex ] = true;
  2360. }
  2361. else
  2362. {
  2363. pFlexControllerUI->szindex2 = 0;
  2364. }
  2365. found = true;
  2366. break;
  2367. }
  2368. }
  2369. if ( !found )
  2370. {
  2371. pFlexControllerUI->remaptype = FLEXCONTROLLER_REMAP_PASSTHRU;
  2372. pFlexControllerUI->szindex2 = 0; // Unused in this case
  2373. if ( j < g_numflexcontrollers - 1 &&
  2374. StringAfterPrefixCaseSensitive( flexcontroller.name, "right_" ) &&
  2375. StringAfterPrefixCaseSensitive( g_flexcontroller[ j + 1 ].name, "left_" ) &&
  2376. !Q_strcmp( StringAfterPrefixCaseSensitive( flexcontroller.name, "right_" ), StringAfterPrefixCaseSensitive( g_flexcontroller[ j + 1 ].name, "left_" ) ) )
  2377. {
  2378. AddToStringTable( pFlexControllerUI, &pFlexControllerUI->sznameindex, flexcontroller.name + 6 );
  2379. pFlexControllerUI->stereo = true;
  2380. Assert( !pControllerHandled[ j + 1 ] );
  2381. pFlexControllerUI->szindex0 = (
  2382. phdr->flexcontrollerindex - int( pData - pStart ) +
  2383. ( j + 1 ) * sizeof( mstudioflexcontroller_t ) );
  2384. pControllerHandled[ j + 1 ] = true;
  2385. Assert( !pControllerHandled[ j ] );
  2386. pFlexControllerUI->szindex1 = (
  2387. phdr->flexcontrollerindex - int( pData - pStart ) +
  2388. j * sizeof( mstudioflexcontroller_t ) );
  2389. pControllerHandled[ j ] = true;
  2390. }
  2391. else if ( j > 0 &&
  2392. StringAfterPrefixCaseSensitive( flexcontroller.name, "left_" ) &&
  2393. StringAfterPrefixCaseSensitive( g_flexcontroller[ j - 1 ].name, "right_" ) &&
  2394. !Q_strcmp( StringAfterPrefixCaseSensitive( flexcontroller.name, "left_" ), StringAfterPrefixCaseSensitive( g_flexcontroller[ j - 1 ].name, "right_" ) ) )
  2395. {
  2396. AddToStringTable( pFlexControllerUI, &pFlexControllerUI->sznameindex, flexcontroller.name + 5 );
  2397. pFlexControllerUI->stereo = true;
  2398. Assert( !pControllerHandled[ j ] );
  2399. pFlexControllerUI->szindex0 = (
  2400. phdr->flexcontrollerindex - int( pData - pStart ) +
  2401. j * sizeof( mstudioflexcontroller_t ) );
  2402. pControllerHandled[ j ] = true;
  2403. Assert( !pControllerHandled[ j - 1 ] );
  2404. pFlexControllerUI->szindex1 = (
  2405. phdr->flexcontrollerindex - int( pData - pStart ) +
  2406. ( j - 1 ) * sizeof( mstudioflexcontroller_t ) );
  2407. pControllerHandled[ j - 1 ] = true;
  2408. }
  2409. else
  2410. {
  2411. AddToStringTable( pFlexControllerUI, &pFlexControllerUI->sznameindex, flexcontroller.name );
  2412. pFlexControllerUI->stereo = false;
  2413. pFlexControllerUI->szindex0 = (
  2414. phdr->flexcontrollerindex - int( pData - pStart ) +
  2415. j * sizeof( mstudioflexcontroller_t ) );
  2416. pFlexControllerUI->szindex1 = 0; // Unused in this case
  2417. pControllerHandled[ j ] = true;
  2418. }
  2419. }
  2420. phdr->numflexcontrollerui++;
  2421. pData += sizeof( mstudioflexcontrollerui_t );
  2422. ++pFlexControllerUI;
  2423. }
  2424. ALIGN4( pData );
  2425. #ifdef _DEBUG
  2426. for ( j = 0; j < g_numflexcontrollers; ++j )
  2427. {
  2428. Assert( pControllerHandled[ j ] );
  2429. }
  2430. #endif // _DEBUG
  2431. // write ik chains
  2432. mstudioikchain_t *pikchain = (mstudioikchain_t *)pData;
  2433. phdr->numikchains = g_numikchains;
  2434. phdr->ikchainindex = pData - pStart;
  2435. pData += g_numikchains * sizeof( mstudioikchain_t );
  2436. ALIGN4( pData );
  2437. for (j = 0; j < g_numikchains; j++)
  2438. {
  2439. AddToStringTable( pikchain, &pikchain->sznameindex, g_ikchain[j].name );
  2440. pikchain->numlinks = g_ikchain[j].numlinks;
  2441. mstudioiklink_t *piklink = (mstudioiklink_t *)pData;
  2442. pikchain->linkindex = (pData - (byte *)pikchain);
  2443. pData += pikchain->numlinks * sizeof( mstudioiklink_t );
  2444. for (i = 0; i < pikchain->numlinks; i++)
  2445. {
  2446. piklink[i].bone = g_ikchain[j].link[i].bone;
  2447. piklink[i].kneeDir = g_ikchain[j].link[i].kneeDir;
  2448. }
  2449. pikchain++;
  2450. }
  2451. // save autoplay locks
  2452. mstudioiklock_t *piklock = (mstudioiklock_t *)pData;
  2453. phdr->numlocalikautoplaylocks = g_numikautoplaylocks;
  2454. phdr->localikautoplaylockindex = pData - pStart;
  2455. pData += g_numikautoplaylocks * sizeof( mstudioiklock_t );
  2456. ALIGN4( pData );
  2457. for (j = 0; j < g_numikautoplaylocks; j++)
  2458. {
  2459. piklock->chain = g_ikautoplaylock[j].chain;
  2460. piklock->flPosWeight = g_ikautoplaylock[j].flPosWeight;
  2461. piklock->flLocalQWeight = g_ikautoplaylock[j].flLocalQWeight;
  2462. piklock++;
  2463. }
  2464. // save mouth info
  2465. mstudiomouth_t *pmouth = (mstudiomouth_t *)pData;
  2466. phdr->nummouths = g_nummouths;
  2467. phdr->mouthindex = pData - pStart;
  2468. pData += g_nummouths * sizeof( mstudiomouth_t );
  2469. ALIGN4( pData );
  2470. for (i = 0; i < g_nummouths; i++) {
  2471. pmouth[i].bone = g_mouth[i].bone;
  2472. VectorCopy( g_mouth[i].forward, pmouth[i].forward );
  2473. pmouth[i].flexdesc = g_mouth[i].flexdesc;
  2474. }
  2475. // save pose parameters
  2476. mstudioposeparamdesc_t *ppose = (mstudioposeparamdesc_t *)pData;
  2477. phdr->numlocalposeparameters = g_numposeparameters;
  2478. phdr->localposeparamindex = pData - pStart;
  2479. pData += g_numposeparameters * sizeof( mstudioposeparamdesc_t );
  2480. ALIGN4( pData );
  2481. for (i = 0; i < g_numposeparameters; i++)
  2482. {
  2483. AddToStringTable( &ppose[i], &ppose[i].sznameindex, g_pose[i].name );
  2484. ppose[i].start = g_pose[i].min;
  2485. ppose[i].end = g_pose[i].max;
  2486. ppose[i].flags = g_pose[i].flags;
  2487. ppose[i].loop = g_pose[i].loop;
  2488. }
  2489. if( !g_quiet )
  2490. {
  2491. printf("ik/pose %7d bytes\n", (int)(pData - cur) );
  2492. }
  2493. cur = (int)pData;
  2494. const float flVertAnimFixedPointScale = ComputeVertAnimFixedPointScale( phdr );
  2495. // Check all source models for extra texcoords
  2496. // If any exist, add model flag to indicate that extra vertex data will be appended to the VVD file
  2497. bool bExtraVertexData = false;
  2498. sExtraTexcoordsToWrite = 0;
  2499. for ( int i = 0; (i < phdr->numbodyparts) && !bExtraVertexData; ++i )
  2500. {
  2501. for ( int j = 0; j < g_bodypart[i].nummodels; ++j )
  2502. {
  2503. if ( g_bodypart[i].pmodel[j] && g_bodypart[i].pmodel[j]->source->numvertices > 0 )
  2504. {
  2505. if ( g_bodypart[i].pmodel[j] && g_bodypart[i].pmodel[j]->source->vertex[0].numTexcoord > 1 )
  2506. {
  2507. bExtraVertexData = true;
  2508. sExtraTexcoordsToWrite = g_bodypart[i].pmodel[j]->source->vertex[0].numTexcoord - 1;
  2509. break;
  2510. }
  2511. }
  2512. }
  2513. }
  2514. if ( bExtraVertexData )
  2515. {
  2516. phdr->flags |= STUDIOHDR_FLAGS_EXTRA_VERTEX_DATA;
  2517. }
  2518. // write model
  2519. for (i = 0; i < g_nummodelsbeforeLOD; i++)
  2520. {
  2521. int n = 0;
  2522. byte *pModelStart = (byte *)(&pmodel[i]);
  2523. strcpy( pmodel[i].name, g_model[i]->filename );
  2524. // AddToStringTable( &pmodel[i], &pmodel[i].sznameindex, g_model[i]->filename );
  2525. // pmodel[i].mrmbias = g_model[i]->mrmbias;
  2526. // pmodel[i].minresolution = g_model[i]->minresolution;
  2527. // pmodel[i].maxresolution = g_model[i]->maxresolution;
  2528. // save bbox info
  2529. psource = g_model[i]->source;
  2530. s_loddata_t *pLodData = g_model[i]->m_pLodData;
  2531. // save mesh info
  2532. if (pLodData)
  2533. {
  2534. pmodel[i].numvertices = pLodData->numvertices;
  2535. }
  2536. else
  2537. {
  2538. // empty model
  2539. pmodel[i].numvertices = 0;
  2540. }
  2541. if ( pmodel[i].numvertices >= MAXSTUDIOVERTS )
  2542. {
  2543. // We have to check this here so that we don't screw up decal
  2544. // vert caching in the runtime.
  2545. MdlError( "Too many verts in model. (%d verts, MAXSTUDIOVERTS==%d)\n",
  2546. pmodel[i].numvertices, ( int )MAXSTUDIOVERTS );
  2547. }
  2548. mstudiomesh_t *pmesh = (mstudiomesh_t *)pData;
  2549. pmodel[i].meshindex = (pData - pModelStart);
  2550. pData += psource->nummeshes * sizeof( mstudiomesh_t );
  2551. ALIGN4( pData );
  2552. pmodel[i].nummeshes = psource->nummeshes;
  2553. for (m = 0; m < pmodel[i].nummeshes; m++)
  2554. {
  2555. n = psource->meshindex[m];
  2556. pmesh[m].material = n;
  2557. pmesh[m].modelindex = (byte *)&pmodel[i] - (byte *)&pmesh[m];
  2558. pmesh[m].numvertices = pLodData->mesh[n].numvertices;
  2559. pmesh[m].vertexoffset = pLodData->mesh[n].vertexoffset;
  2560. }
  2561. // set expected base offsets to external data
  2562. ALIGN16( externalVertexIndex );
  2563. pmodel[i].vertexindex = (int)externalVertexIndex;
  2564. externalVertexIndex += pmodel[i].numvertices * sizeof(mstudiovertex_t);
  2565. // set expected base offsets to external data
  2566. ALIGN4( externalTangentsIndex );
  2567. pmodel[i].tangentsindex = (int)externalTangentsIndex;
  2568. externalTangentsIndex += pmodel[i].numvertices * sizeof( Vector4D );
  2569. cur = (int)pData;
  2570. // save eyeballs
  2571. mstudioeyeball_t *peyeball;
  2572. peyeball = (mstudioeyeball_t *)pData;
  2573. pmodel[i].numeyeballs = g_model[i]->numeyeballs;
  2574. pmodel[i].eyeballindex = pData - pModelStart;
  2575. pData += g_model[i]->numeyeballs * sizeof( mstudioeyeball_t );
  2576. ALIGN4( pData );
  2577. for (j = 0; j < g_model[i]->numeyeballs; j++)
  2578. {
  2579. k = g_model[i]->eyeball[j].mesh;
  2580. pmesh[k].materialtype = 1; // FIXME: tag custom material
  2581. pmesh[k].materialparam = j; // FIXME: tag custom material
  2582. peyeball[j].bone = g_model[i]->eyeball[j].bone;
  2583. VectorCopy( g_model[i]->eyeball[j].org, peyeball[j].org );
  2584. peyeball[j].zoffset = g_model[i]->eyeball[j].zoffset;
  2585. peyeball[j].radius = g_model[i]->eyeball[j].radius;
  2586. VectorCopy( g_model[i]->eyeball[j].up, peyeball[j].up );
  2587. VectorCopy( g_model[i]->eyeball[j].forward, peyeball[j].forward );
  2588. peyeball[j].iris_scale = g_model[i]->eyeball[j].iris_scale;
  2589. for (k = 0; k < 3; k++)
  2590. {
  2591. peyeball[j].upperflexdesc[k] = g_model[i]->eyeball[j].upperflexdesc[k];
  2592. peyeball[j].lowerflexdesc[k] = g_model[i]->eyeball[j].lowerflexdesc[k];
  2593. peyeball[j].uppertarget[k] = g_model[i]->eyeball[j].uppertarget[k];
  2594. peyeball[j].lowertarget[k] = g_model[i]->eyeball[j].lowertarget[k];
  2595. }
  2596. peyeball[j].upperlidflexdesc = g_model[i]->eyeball[j].upperlidflexdesc;
  2597. peyeball[j].lowerlidflexdesc = g_model[i]->eyeball[j].lowerlidflexdesc;
  2598. }
  2599. if ( !g_quiet )
  2600. {
  2601. printf("eyeballs %7d bytes (%d eyeballs)\n", (int)(pData - cur), g_model[i]->numeyeballs );
  2602. }
  2603. // move flexes into individual meshes
  2604. cur = (int)pData;
  2605. for (m = 0; m < pmodel[i].nummeshes; m++)
  2606. {
  2607. int numflexkeys[MAXSTUDIOFLEXKEYS];
  2608. pmesh[m].numflexes = 0;
  2609. // initialize array
  2610. for (j = 0; j < g_numflexkeys; j++)
  2611. {
  2612. numflexkeys[j] = 0;
  2613. }
  2614. // count flex instances per mesh
  2615. for (j = 0; j < g_numflexkeys; j++)
  2616. {
  2617. if (g_flexkey[j].imodel == i)
  2618. {
  2619. for (k = 0; k < g_flexkey[j].numvanims; k++)
  2620. {
  2621. n = g_flexkey[j].vanim[k].vertex - pmesh[m].vertexoffset;
  2622. if (n >= 0 && n < pmesh[m].numvertices)
  2623. {
  2624. if (numflexkeys[j]++ == 0)
  2625. {
  2626. pmesh[m].numflexes++;
  2627. }
  2628. }
  2629. }
  2630. }
  2631. }
  2632. if (pmesh[m].numflexes)
  2633. {
  2634. pmesh[m].flexindex = ( pData - (byte *)&pmesh[m] );
  2635. mstudioflex_t *pflex = (mstudioflex_t *)pData;
  2636. pData += pmesh[m].numflexes * sizeof( mstudioflex_t );
  2637. ALIGN4( pData );
  2638. for (j = 0; j < g_numflexkeys; j++)
  2639. {
  2640. if (!numflexkeys[j])
  2641. continue;
  2642. pflex->flexdesc = g_flexkey[j].flexdesc;
  2643. pflex->target0 = g_flexkey[j].target0;
  2644. pflex->target1 = g_flexkey[j].target1;
  2645. pflex->target2 = g_flexkey[j].target2;
  2646. pflex->target3 = g_flexkey[j].target3;
  2647. pflex->numverts = numflexkeys[j];
  2648. pflex->vertindex = (pData - (byte *)pflex);
  2649. pflex->flexpair = g_flexkey[j].flexpair;
  2650. pflex->vertanimtype = g_flexkey[j].vanimtype;
  2651. // printf("%d %d %s : %f %f %f %f\n", j, g_flexkey[j].flexdesc, g_flexdesc[g_flexkey[j].flexdesc].FACS, g_flexkey[j].target0, g_flexkey[j].target1, g_flexkey[j].target2, g_flexkey[j].target3 );
  2652. // if (j < 9) printf("%d %d %s : %d (%d) %f\n", j, g_flexkey[j].flexdesc, g_flexdesc[g_flexkey[j].flexdesc].FACS, g_flexkey[j].numvanims, pflex->numverts, g_flexkey[j].target );
  2653. // printf("%d %d : %d %f\n", j, g_flexkey[j].flexnum, g_flexkey[j].numvanims, g_flexkey[j].target );
  2654. pvanim = g_flexkey[j].vanim;
  2655. bool bWrinkleVAnim = ( pflex->vertanimtype == STUDIO_VERT_ANIM_WRINKLE );
  2656. int nVAnimDeltaSize = bWrinkleVAnim ? sizeof(mstudiovertanim_wrinkle_t) : sizeof(mstudiovertanim_t);
  2657. pvertanim = (mstudiovertanim_t *)pData;
  2658. pData += pflex->numverts * nVAnimDeltaSize;
  2659. ALIGN4( pData );
  2660. for ( k = 0; k < g_flexkey[j].numvanims; k++ )
  2661. {
  2662. n = g_flexkey[j].vanim[k].vertex - pmesh[m].vertexoffset;
  2663. if ( n >= 0 && n < pmesh[m].numvertices )
  2664. {
  2665. pvertanim->index = n;
  2666. pvertanim->speed = 255.0F*pvanim->speed;
  2667. pvertanim->side = 255.0F*pvanim->side;
  2668. pvertanim->SetDeltaFloat( pvanim->pos );
  2669. pvertanim->SetNDeltaFloat( pvanim->normal );
  2670. if ( bWrinkleVAnim )
  2671. {
  2672. ( (mstudiovertanim_wrinkle_t*)pvertanim )->SetWrinkleFixed( pvanim->wrinkle, flVertAnimFixedPointScale );
  2673. }
  2674. pvertanim = (mstudiovertanim_t*)( (byte*)pvertanim + nVAnimDeltaSize );
  2675. /*
  2676. if ((tmp - pvanim->pos).Length() > 0.1)
  2677. {
  2678. pvertanim->delta.x = pvanim->pos.x;
  2679. printf("%f %f %f : %f %f %f\n",
  2680. pvanim->pos[0], pvanim->pos[1], pvanim->pos[2],
  2681. tmp.x, tmp.y, tmp.z );
  2682. }
  2683. */
  2684. // if (j < 9) printf("%d %.2f %.2f %.2f\n", n, pvanim->pos[0], pvanim->pos[1], pvanim->pos[2] );
  2685. }
  2686. // printf("%d %.2f %.2f %.2f\n", pvanim->vertex, pvanim->pos[0], pvanim->pos[1], pvanim->pos[2] );
  2687. pvanim++;
  2688. }
  2689. pflex++;
  2690. }
  2691. }
  2692. }
  2693. if( !g_quiet )
  2694. {
  2695. printf("flexes %7d bytes (%d flexes)\n", (int)(pData - cur), g_numflexkeys );
  2696. }
  2697. cur = (int)pData;
  2698. }
  2699. ALIGN4( pData );
  2700. mstudiomodelgroup_t *pincludemodel = (mstudiomodelgroup_t *)pData;
  2701. phdr->numincludemodels = g_numincludemodels;
  2702. phdr->includemodelindex = pData - pStart;
  2703. pData += g_numincludemodels * sizeof( mstudiomodelgroup_t );
  2704. for (i = 0; i < g_numincludemodels; i++)
  2705. {
  2706. AddToStringTable( pincludemodel, &pincludemodel->sznameindex, g_includemodel[i].name );
  2707. pincludemodel++;
  2708. }
  2709. // save animblock group info
  2710. mstudioanimblock_t *panimblock = (mstudioanimblock_t *)pData;
  2711. phdr->numanimblocks = g_numanimblocks;
  2712. phdr->animblockindex = pData - pStart;
  2713. pData += phdr->numanimblocks * sizeof( mstudioanimblock_t );
  2714. ALIGN4( pData );
  2715. for (i = 1; i < g_numanimblocks; i++)
  2716. {
  2717. panimblock[i].datastart = g_animblock[i].start - pBlockStart;
  2718. panimblock[i].dataend = g_animblock[i].end - pBlockStart;
  2719. // printf("block %d : %x %x (%d)\n", i, panimblock[i].datastart, panimblock[i].dataend, panimblock[i].dataend - panimblock[i].datastart );
  2720. }
  2721. AddToStringTable( phdr, &phdr->szanimblocknameindex, g_animblockname );
  2722. }
  2723. static void AssignMeshIDs( studiohdr_t *pStudioHdr )
  2724. {
  2725. int i;
  2726. int j;
  2727. int m;
  2728. int numMeshes;
  2729. mstudiobodyparts_t *pStudioBodyPart;
  2730. mstudiomodel_t *pStudioModel;
  2731. mstudiomesh_t *pStudioMesh;
  2732. numMeshes = 0;
  2733. for (i=0; i<pStudioHdr->numbodyparts; i++)
  2734. {
  2735. pStudioBodyPart = pStudioHdr->pBodypart(i);
  2736. for (j=0; j<pStudioBodyPart->nummodels; j++)
  2737. {
  2738. pStudioModel = pStudioBodyPart->pModel(j);
  2739. for (m=0; m<pStudioModel->nummeshes; m++)
  2740. {
  2741. // get each mesh
  2742. pStudioMesh = pStudioModel->pMesh(m);
  2743. pStudioMesh->meshid = numMeshes + m;
  2744. }
  2745. numMeshes += pStudioModel->nummeshes;
  2746. }
  2747. }
  2748. }
  2749. void LoadMaterials( studiohdr_t *phdr )
  2750. {
  2751. int i, j;
  2752. // get index of each material
  2753. if( phdr->textureindex != 0 )
  2754. {
  2755. for( i = 0; i < phdr->numtextures; i++ )
  2756. {
  2757. char szPath[MAX_PATH];
  2758. IMaterial *pMaterial = NULL;
  2759. // search through all specified directories until a valid material is found
  2760. for( j = 0; j < phdr->numcdtextures && IsErrorMaterial( pMaterial ); j++ )
  2761. {
  2762. strcpy( szPath, phdr->pCdtexture( j ) );
  2763. strcat( szPath, phdr->pTexture( i )->pszName( ) );
  2764. pMaterial = g_pMaterialSystem->FindMaterial( szPath, TEXTURE_GROUP_OTHER, false );
  2765. }
  2766. if( IsErrorMaterial( pMaterial ) && !g_quiet )
  2767. {
  2768. // hack - if it isn't found, go through the motions of looking for it again
  2769. // so that the materialsystem will give an error.
  2770. for( j = 0; j < phdr->numcdtextures; j++ )
  2771. {
  2772. strcpy( szPath, phdr->pCdtexture( j ) );
  2773. strcat( szPath, phdr->pTexture( i )->pszName( ) );
  2774. g_pMaterialSystem->FindMaterial( szPath, TEXTURE_GROUP_OTHER, true );
  2775. }
  2776. }
  2777. else
  2778. {
  2779. char szTemp[MAX_PATH];
  2780. V_ComposeFileName( gamedir, "materials", szTemp, sizeof(szTemp) );
  2781. char szTemp2[MAX_PATH];
  2782. V_ComposeFileName( szTemp, szPath, szTemp2, sizeof(szTemp2) );
  2783. V_SetExtension( szTemp2, ".vmt", MAX_PATH );
  2784. V_FixupPathName( szTemp, MAX_PATH, szTemp2 );
  2785. if ( g_pFullFileSystem->FileExists( szTemp ) )
  2786. {
  2787. CP4AutoAddFile p4_add_dep_file( szTemp );
  2788. }
  2789. else
  2790. {
  2791. MdlWarning( "Could not locate VMT for p4 add: %s\n", szTemp );
  2792. }
  2793. }
  2794. phdr->pTexture( i )->material = pMaterial;
  2795. // FIXME: hack, needs proper client side material system interface
  2796. bool found = false;
  2797. IMaterialVar *clientShaderVar = pMaterial->FindVar( "$clientShader", &found, false );
  2798. if( found )
  2799. {
  2800. if (stricmp( clientShaderVar->GetStringValue(), "MouthShader") == 0)
  2801. {
  2802. phdr->pTexture( i )->flags = 1;
  2803. }
  2804. phdr->pTexture( i )->used = 1;
  2805. }
  2806. }
  2807. }
  2808. }
  2809. void WriteKeyValues( studiohdr_t *phdr, CUtlVector< char > *pKeyValue )
  2810. {
  2811. phdr->keyvalueindex = (pData - pStart);
  2812. phdr->keyvaluesize = KeyValueTextSize( pKeyValue );
  2813. if (phdr->keyvaluesize)
  2814. {
  2815. memcpy( pData, KeyValueText( pKeyValue ), phdr->keyvaluesize );
  2816. // Add space for a null terminator
  2817. pData[phdr->keyvaluesize] = 0;
  2818. ++phdr->keyvaluesize;
  2819. pData += phdr->keyvaluesize * sizeof( char );
  2820. }
  2821. ALIGN4( pData );
  2822. }
  2823. #define KV_HEAD_CAP "mdlkeyvalue\n{\n"
  2824. #define KV_TAIL_CAP "}\n"
  2825. void CapKeyValues( void )
  2826. {
  2827. if ( g_KeyValueText.Count() )
  2828. {
  2829. g_KeyValueText.InsertMultipleBefore( 0, Q_strlen( KV_HEAD_CAP ), KV_HEAD_CAP );
  2830. g_KeyValueText.AddMultipleToTail( Q_strlen( KV_TAIL_CAP ), KV_TAIL_CAP );
  2831. }
  2832. }
  2833. void WriteQCPath( void )
  2834. {
  2835. char relative_qc_path[1024];
  2836. g_pFullFileSystem->FullPathToRelativePathEx( qdir, "CONTENT", relative_qc_path, sizeof(relative_qc_path) );
  2837. strcat( relative_qc_path, V_GetFileName( g_fullpath ) );
  2838. if ( Q_strlen( relative_qc_path ) > 0 )
  2839. {
  2840. char new_qcpath_block[2048];
  2841. V_sprintf_safe( new_qcpath_block, "qc_path {\n\"value\" \"%s\" }\n", relative_qc_path );
  2842. g_KeyValueText.AddMultipleToTail( Q_strlen( new_qcpath_block ), new_qcpath_block );
  2843. }
  2844. }
  2845. void WriteSeqKeyValues( mstudioseqdesc_t *pseqdesc, CUtlVector< char > *pKeyValue )
  2846. {
  2847. pseqdesc->keyvalueindex = (pData - (byte *)pseqdesc);
  2848. pseqdesc->keyvaluesize = KeyValueTextSize( pKeyValue );
  2849. if (pseqdesc->keyvaluesize)
  2850. {
  2851. memcpy( pData, KeyValueText( pKeyValue ), pseqdesc->keyvaluesize );
  2852. // Add space for a null terminator
  2853. pData[pseqdesc->keyvaluesize] = 0;
  2854. ++pseqdesc->keyvaluesize;
  2855. pData += pseqdesc->keyvaluesize * sizeof( char );
  2856. }
  2857. ALIGN4( pData );
  2858. }
  2859. void EnsureFileDirectoryExists( const char *pFilename )
  2860. {
  2861. char dirName[MAX_PATH];
  2862. Q_strncpy( dirName, pFilename, sizeof( dirName ) );
  2863. Q_FixSlashes( dirName );
  2864. char *pLastSlash = strrchr( dirName, CORRECT_PATH_SEPARATOR );
  2865. if ( pLastSlash )
  2866. {
  2867. *pLastSlash = 0;
  2868. if ( _access( dirName, 0 ) != 0 )
  2869. {
  2870. char cmdLine[512];
  2871. Q_snprintf( cmdLine, sizeof( cmdLine ), "md \"%s\"", dirName );
  2872. system( cmdLine );
  2873. }
  2874. }
  2875. }
  2876. void WriteModelFiles(void)
  2877. {
  2878. FileHandle_t modelouthandle = 0;
  2879. FileHandle_t blockouthandle = 0;
  2880. CPlainAutoPtr< CP4File > spFileBlockOut, spFileModelOut;
  2881. int total = 0;
  2882. int i;
  2883. char filename[260];
  2884. studiohdr_t *phdr;
  2885. studiohdr_t *pblockhdr = 0;
  2886. pStart = (byte *)kalloc( 1, FILEBUFFER );
  2887. pBlockData = NULL;
  2888. pBlockStart = NULL;
  2889. Q_StripExtension( g_outname, g_outname, sizeof( g_outname ) );
  2890. if (g_animblocksize != 0)
  2891. {
  2892. // write the non-default g_sequence group data to separate files
  2893. sprintf( g_animblockname, "models/%s.ani", g_outname );
  2894. strcpy( filename, gamedir );
  2895. strcat( filename, g_animblockname );
  2896. if ( *g_szInternalName )
  2897. {
  2898. Q_StripExtension( g_szInternalName, g_szInternalName, sizeof( g_szInternalName ) );
  2899. sprintf( g_animblockname, "models/%s.ani", g_szInternalName );
  2900. }
  2901. EnsureFileDirectoryExists( filename );
  2902. if (!g_bVerifyOnly)
  2903. {
  2904. spFileBlockOut.Attach( g_p4factory->AccessFile( filename ) );
  2905. spFileBlockOut->Edit();
  2906. blockouthandle = SafeOpenWrite( filename );
  2907. }
  2908. pBlockStart = (byte *)kalloc( 1, FILEBUFFER );
  2909. pBlockData = pBlockStart;
  2910. pblockhdr = (studiohdr_t *)pBlockData;
  2911. pblockhdr->id = IDSTUDIOANIMGROUPHEADER;
  2912. pblockhdr->version = STUDIO_VERSION;
  2913. pBlockData += sizeof( *pblockhdr );
  2914. }
  2915. //
  2916. // write the g_model output file
  2917. //
  2918. phdr = (studiohdr_t *)pStart;
  2919. phdr->id = IDSTUDIOHEADER;
  2920. phdr->version = STUDIO_VERSION;
  2921. strcat( g_outname, ".mdl");
  2922. // strcpy( outname, ExpandPath( outname ) );
  2923. strcpy( filename, gamedir );
  2924. // if( *g_pPlatformName )
  2925. // {
  2926. // strcat( filename, "platform_" );
  2927. // strcat( filename, g_pPlatformName );
  2928. // strcat( filename, "/" );
  2929. // }
  2930. strcat( filename, "models/" );
  2931. strcat( filename, g_outname );
  2932. // Create the directory.
  2933. EnsureFileDirectoryExists( filename );
  2934. if( !g_quiet )
  2935. {
  2936. printf ("---------------------\n");
  2937. printf ("writing %s:\n", filename);
  2938. }
  2939. LoadPreexistingSequenceOrder( filename );
  2940. if ( g_parseable_completion_output )
  2941. {
  2942. char szRelativePath[260];
  2943. V_MakeRelativePath( filename, getenv("VGAME"), szRelativePath, sizeof(szRelativePath) );
  2944. printf("\nOUTPUT MODEL: %s\n", szRelativePath);
  2945. }
  2946. if (!g_bVerifyOnly)
  2947. {
  2948. spFileModelOut.Attach( g_p4factory->AccessFile( filename ) );
  2949. spFileModelOut->Edit();
  2950. modelouthandle = SafeOpenWrite (filename);
  2951. }
  2952. phdr->eyeposition = eyeposition;
  2953. phdr->illumposition = illumposition;
  2954. if ( !g_wrotebbox && g_sequence.Count() > 0)
  2955. {
  2956. VectorCopy( g_sequence[0].bmin, bbox[0] );
  2957. VectorCopy( g_sequence[0].bmax, bbox[1] );
  2958. CollisionModel_ExpandBBox( bbox[0], bbox[1] );
  2959. VectorCopy( bbox[0], g_sequence[0].bmin );
  2960. VectorCopy( bbox[1], g_sequence[0].bmax );
  2961. }
  2962. if ( !g_wrotecbox )
  2963. {
  2964. // no default clipping box, just use per-sequence box
  2965. VectorCopy( vec3_origin, cbox[0] );
  2966. VectorCopy( vec3_origin, cbox[1] );
  2967. }
  2968. phdr->hull_min = bbox[0];
  2969. phdr->hull_max = bbox[1];
  2970. phdr->view_bbmin = cbox[0];
  2971. phdr->view_bbmax = cbox[1];
  2972. phdr->flags = gflags;
  2973. phdr->mass = GetCollisionModelMass();
  2974. phdr->constdirectionallightdot = g_constdirectionalightdot;
  2975. if ( g_numAllowedRootLODs > 0 )
  2976. {
  2977. phdr->numAllowedRootLODs = g_numAllowedRootLODs;
  2978. }
  2979. pData = (byte *)phdr + sizeof( studiohdr_t );
  2980. // FIXME: Remove when we up the model version
  2981. phdr->studiohdr2index = ( pData - pStart );
  2982. studiohdr2_t* phdr2 = (studiohdr2_t*)pData;
  2983. memset( phdr2, 0, sizeof(studiohdr2_t) );
  2984. pData = (byte*)phdr2 + sizeof(studiohdr2_t);
  2985. phdr2->illumpositionattachmentindex = g_illumpositionattachment;
  2986. phdr2->flMaxEyeDeflection = g_flMaxEyeDeflection;
  2987. BeginStringTable( );
  2988. if ( *g_szInternalName )
  2989. {
  2990. V_strncpy( phdr->name, g_szInternalName, sizeof( phdr->name ) - 1 );
  2991. AddToStringTable( phdr2, &phdr2->sznameindex, g_szInternalName );
  2992. }
  2993. else
  2994. {
  2995. V_strncpy( phdr->name, g_outname, sizeof( phdr->name ) - 1 );
  2996. AddToStringTable( phdr2, &phdr2->sznameindex, g_outname );
  2997. }
  2998. WriteBoneInfo( phdr );
  2999. if( !g_quiet )
  3000. {
  3001. printf("bones %7d bytes (%d)\n", pData - pStart - total, g_numbones );
  3002. }
  3003. total = pData - pStart;
  3004. pData = WriteAnimations( pData, pStart, phdr );
  3005. if( !g_quiet )
  3006. {
  3007. printf("animations %7d bytes (%d anims) (%d frames) [%d:%02d]\n", pData - pStart - total, g_numani, totalframes, (int)totalseconds / 60, (int)totalseconds % 60 );
  3008. }
  3009. total = pData - pStart;
  3010. WriteSequenceInfo( phdr );
  3011. if( !g_quiet )
  3012. {
  3013. printf("sequences %7d bytes (%d seq) \n", pData - pStart - total, g_sequence.Count() );
  3014. }
  3015. total = pData - pStart;
  3016. Msg("hdr@%p=%p\n",&phdr,phdr);
  3017. WriteModel( phdr );
  3018. Msg("hdr@%p=%p\n",&phdr,phdr);
  3019. /*
  3020. if( !g_quiet )
  3021. {
  3022. printf("models %7d bytes\n", pData - pStart - total );
  3023. }
  3024. */
  3025. total = pData - pStart;
  3026. WriteTextures( phdr );
  3027. if( !g_quiet )
  3028. {
  3029. printf("textures %7d bytes\n", pData - pStart - total );
  3030. }
  3031. total = pData - pStart;
  3032. WriteQCPath( );
  3033. CapKeyValues( );
  3034. WriteKeyValues( phdr, &g_KeyValueText );
  3035. if( !g_quiet )
  3036. {
  3037. printf("keyvalues %7d bytes\n", pData - pStart - total );
  3038. }
  3039. total = pData - pStart;
  3040. Msg("hdr@%p=%p\n",&phdr2,phdr2);
  3041. WriteBoneTransforms( phdr2, phdr->pBone( 0 ) );
  3042. Msg("hdr@%p=%p\n",&phdr,phdr);
  3043. if( !g_quiet )
  3044. {
  3045. printf("bone transforms %7d bytes\n", pData - pStart - total );
  3046. }
  3047. total = pData - pStart;
  3048. WriteBoneFlexDrivers( phdr2 );
  3049. if ( !g_quiet )
  3050. {
  3051. printf("bone flex driver %7d bytes\n", pData - pStart - total );
  3052. }
  3053. total = pData - pStart;
  3054. WriteBodyGroupPresets( phdr2 );
  3055. if ( !g_quiet )
  3056. {
  3057. printf("bodygroup presets %7d bytes\n", pData - pStart - total );
  3058. }
  3059. total = pData - pStart;
  3060. pData = WriteStringTable( pData );
  3061. total = pData - pStart;
  3062. phdr->checksum = 0;
  3063. for (i = 0; i < total; i += 4)
  3064. {
  3065. // TODO: does this need something more than a simple shift left and add checksum?
  3066. phdr->checksum = (phdr->checksum << 1) + ((phdr->checksum & 0x8000000) ? 1 : 0) + *((long *)(pStart + i));
  3067. }
  3068. if (g_bVerifyOnly)
  3069. return;
  3070. CollisionModel_Write( phdr->checksum );
  3071. // Physics2Collision_Write();
  3072. if( !g_quiet )
  3073. {
  3074. printf("collision %7d bytes\n", pData - pStart - total );
  3075. }
  3076. AssignMeshIDs( phdr );
  3077. total = pData - pStart;
  3078. if ( g_pClothProxyCompiler && !g_pClothProxyCompiler->IsEmpty() )
  3079. {
  3080. // we've got some cloth to write out!
  3081. g_pClothProxyCompiler->Cook();
  3082. // we need to write SSE data, align the whole buffer for SSE and potentially AVX for futureproofing
  3083. // Note: MDL Cache aligns studiohdr buffer by 32 bytes, so this alignment can't effectively be more than 32 bytes without changing MDL Cache
  3084. pData = ( byte* )( ( uintp( pData ) + 31 ) & ~31 ); // skip up to 31 bytes for alignment
  3085. CResourceStreamFixed stream( pData, pStart + FILEBUFFER - pData );
  3086. phdr2->m_pFeModel = g_pClothProxyCompiler->Compile( &stream );
  3087. if ( !phdr2->m_pFeModel.IsNull() )
  3088. {
  3089. extern QAngle s_angClothPrerotate;
  3090. if ( s_angClothPrerotate != vec3_angle )
  3091. {
  3092. Quaternion qPrerotate = AngleQuaternion( s_angClothPrerotate );
  3093. for ( int i = 0; i < phdr2->m_pFeModel->m_InitPose.Count(); ++i )
  3094. {
  3095. CTransform &tm = phdr2->m_pFeModel->m_InitPose[ i ];
  3096. tm.m_vPosition = VectorRotate( tm.m_vPosition, qPrerotate );
  3097. tm.m_orientation = qPrerotate * tm.m_orientation;
  3098. }
  3099. }
  3100. }
  3101. if ( !g_quiet )
  3102. {
  3103. printf( "cloth %7d bytes\n", stream.GetTotalSize() );
  3104. }
  3105. pData += stream.GetTotalSize();
  3106. }
  3107. total = pData - pStart;
  3108. phdr->length = pData - pStart;
  3109. if( !g_quiet )
  3110. {
  3111. printf("total %7d\n", phdr->length );
  3112. }
  3113. // Load materials for this model via the material system so that the
  3114. // optimizer can ask questions about the materials.
  3115. LoadMaterials( phdr );
  3116. SafeWrite( modelouthandle, pStart, phdr->length );
  3117. g_pFileSystem->Close(modelouthandle);
  3118. if ( spFileModelOut.IsValid() ) spFileModelOut->Add();
  3119. if (pBlockStart)
  3120. {
  3121. pblockhdr->length = pBlockData - pBlockStart;
  3122. if ( g_bX360 )
  3123. {
  3124. // Before writing this .ani, write the byteswapped version
  3125. int outBaseSize = pblockhdr->length + BYTESWAP_ALIGNMENT_PADDING;
  3126. void *pOutBase = kalloc( 1, outBaseSize );
  3127. int finalSize = StudioByteSwap::ByteswapANI( phdr, pOutBase, outBaseSize, pBlockStart, pblockhdr->length );
  3128. if ( finalSize <= 0 )
  3129. {
  3130. MdlError("Aborted ANI byteswap on '%s':\n", g_animblockname);
  3131. }
  3132. char outname[ MAX_PATH ];
  3133. Q_StripExtension( g_animblockname, outname, sizeof( outname ) );
  3134. Q_strcat( outname, ".360.ani", sizeof( outname ) );
  3135. {
  3136. CP4AutoEditAddFile autop4( outname );
  3137. SaveFile( outname, pOutBase, finalSize );
  3138. }
  3139. }
  3140. SafeWrite( blockouthandle, pBlockStart, pblockhdr->length );
  3141. g_pFileSystem->Close( blockouthandle );
  3142. if ( spFileBlockOut.IsValid() ) spFileBlockOut->Add();
  3143. if ( !g_quiet )
  3144. {
  3145. printf ("---------------------\n");
  3146. printf("writing %s:\n", g_animblockname);
  3147. printf("blocks %7d\n", g_numanimblocks );
  3148. printf("total %7d\n", pblockhdr->length );
  3149. }
  3150. }
  3151. if (phdr->numbodyparts != 0)
  3152. {
  3153. // vertices have become an external peer data store
  3154. // write now prior to impending vertex access from any further code
  3155. // vertex accessors hide shifting vertex data
  3156. WriteVertices( phdr );
  3157. #ifdef _DEBUG
  3158. int bodyPartID;
  3159. for( bodyPartID = 0; bodyPartID < phdr->numbodyparts; bodyPartID++ )
  3160. {
  3161. mstudiobodyparts_t *pBodyPart = phdr->pBodypart( bodyPartID );
  3162. int modelID;
  3163. for( modelID = 0; modelID < pBodyPart->nummodels; modelID++ )
  3164. {
  3165. mstudiomodel_t *pModel = pBodyPart->pModel( modelID );
  3166. const mstudio_modelvertexdata_t *vertData = pModel->GetVertexData();
  3167. Assert( vertData ); // This can only return NULL on X360 for now
  3168. int vertID;
  3169. for( vertID = 0; vertID < pModel->numvertices; vertID++ )
  3170. {
  3171. Vector4D *pTangentS = vertData->TangentS( vertID );
  3172. Assert( pTangentS->w == -1.0f || pTangentS->w == 1.0f );
  3173. }
  3174. }
  3175. }
  3176. #endif
  3177. s_bodypart_t *pBodyParts = (s_bodypart_t *)calloc( phdr->numbodyparts, sizeof( s_bodypart_t ) );
  3178. for (int i = 0; i < phdr->numbodyparts; i++)
  3179. {
  3180. pBodyParts[i] = g_bodypart[i];
  3181. }
  3182. OptimizedModel::WriteOptimizedFiles( phdr, pBodyParts );
  3183. free( pBodyParts );
  3184. // now have external finalized vtx (windings) and vvd (vertexes)
  3185. // re-open files, sort vertexes, perform fixups, and rewrite
  3186. // purposely isolated as a post process for stability
  3187. if (!FixupToSortedLODVertexes( phdr ))
  3188. {
  3189. MdlError("Aborted vertex sort fixup on '%s':\n", filename);
  3190. }
  3191. if (!Clamp_RootLOD( phdr ))
  3192. {
  3193. MdlError("Aborted root lod shift '%s':\n", filename);
  3194. }
  3195. }
  3196. if ( g_bX360 )
  3197. {
  3198. // now all files have been finalized and fixed up.
  3199. // re-open the files once more and swap all little-endian
  3200. // data to big-endian format to produce Xbox360 files.
  3201. WriteAllSwappedFiles( filename );
  3202. }
  3203. // NOTE! If you don't want to go through the effort of loading studiorender for perf reasons,
  3204. // make sure spewFlags ends up being zero.
  3205. unsigned int spewFlags = SPEWPERFSTATS_SHOWSTUDIORENDERWARNINGS;
  3206. if ( g_bPerf )
  3207. {
  3208. spewFlags |= SPEWPERFSTATS_SHOWPERF;
  3209. }
  3210. if( spewFlags )
  3211. {
  3212. SpewPerfStats( phdr, filename, spewFlags );
  3213. }
  3214. }
  3215. const vertexFileHeader_t * mstudiomodel_t::CacheVertexData( void * pModelData )
  3216. {
  3217. static vertexFileHeader_t *pVertexHdr;
  3218. char filename[260];
  3219. Assert( pModelData == NULL );
  3220. if (pVertexHdr)
  3221. {
  3222. // studiomdl is a single model process, can simply persist data in static
  3223. goto hasData;
  3224. }
  3225. // load and persist the vertex file
  3226. strcpy( filename, gamedir );
  3227. // if( *g_pPlatformName )
  3228. // {
  3229. // strcat( filename, "platform_" );
  3230. // strcat( filename, g_pPlatformName );
  3231. // strcat( filename, "/" );
  3232. // }
  3233. strcat( filename, "models/" );
  3234. strcat( filename, g_outname );
  3235. Q_StripExtension( filename, filename, sizeof( filename ) );
  3236. strcat( filename, ".vvd" );
  3237. LoadFile(filename, (void**)&pVertexHdr);
  3238. // check id
  3239. if (pVertexHdr->id != MODEL_VERTEX_FILE_ID)
  3240. {
  3241. MdlError("Error Vertex File: '%s' (id %d should be %d)\n", filename, pVertexHdr->id, MODEL_VERTEX_FILE_ID);
  3242. }
  3243. // check version
  3244. if (pVertexHdr->version != MODEL_VERTEX_FILE_VERSION)
  3245. {
  3246. MdlError("Error Vertex File: '%s' (version %d should be %d)\n", filename, pVertexHdr->version, MODEL_VERTEX_FILE_VERSION);
  3247. }
  3248. hasData:
  3249. return pVertexHdr;
  3250. }
  3251. typedef struct
  3252. {
  3253. int meshVertID;
  3254. int finalMeshVertID;
  3255. int vertexOffset;
  3256. int lodFlags;
  3257. } usedVertex_t;
  3258. typedef struct
  3259. {
  3260. int offsets[MAX_NUM_LODS];
  3261. int numVertexes[MAX_NUM_LODS];
  3262. } lodMeshInfo_t;
  3263. typedef struct
  3264. {
  3265. usedVertex_t *pVertexList;
  3266. int *pVertexMap;
  3267. int numVertexes;
  3268. lodMeshInfo_t lodMeshInfo;
  3269. } vertexPool_t;
  3270. #define ALIGN(b,s) (((unsigned int)(b)+(s)-1)&~((s)-1))
  3271. //-----------------------------------------------------------------------------
  3272. // FindVertexOffsets
  3273. //
  3274. // Iterate sorted vertex list to determine mesh starts and counts.
  3275. //-----------------------------------------------------------------------------
  3276. void FindVertexOffsets(int vertexOffset, int offsets[MAX_NUM_LODS], int counts[MAX_NUM_LODS], int numLods, const usedVertex_t *pVertexList, int numVertexes)
  3277. {
  3278. int lodFlags;
  3279. int i;
  3280. int j;
  3281. int k;
  3282. // vertexOffset uniquely identifies a single mesh's vertexes in lod vertex sorted list
  3283. // lod vertex list is sorted from lod N..lod 0
  3284. for (i=numLods-1; i>=0; i--)
  3285. {
  3286. offsets[i] = 0;
  3287. counts[i] = 0;
  3288. lodFlags = (1<<(i+1))-1;
  3289. for (j=0; j<numVertexes; j++)
  3290. {
  3291. // determine start of mesh at desired lod
  3292. if (pVertexList[j].lodFlags > lodFlags)
  3293. continue;
  3294. if (pVertexList[j].vertexOffset != vertexOffset)
  3295. continue;
  3296. for (k=j; k<numVertexes; k++)
  3297. {
  3298. // determine end of mesh at desired lod
  3299. if (pVertexList[k].vertexOffset != vertexOffset)
  3300. break;
  3301. if (!(pVertexList[k].lodFlags & (1<<i)))
  3302. break;
  3303. }
  3304. offsets[i] = j;
  3305. counts[i] = k-j;
  3306. break;
  3307. }
  3308. }
  3309. }
  3310. //-----------------------------------------------------------------------------
  3311. // _CompareUsedVertexes
  3312. //
  3313. // qsort callback
  3314. //-----------------------------------------------------------------------------
  3315. static int _CompareUsedVertexes(const void *a, const void *b)
  3316. {
  3317. usedVertex_t *pVertexA;
  3318. usedVertex_t *pVertexB;
  3319. int sort;
  3320. int lodA;
  3321. int lodB;
  3322. pVertexA = (usedVertex_t*)a;
  3323. pVertexB = (usedVertex_t*)b;
  3324. // determine highest (lowest detail) lod
  3325. // forces grouping into discrete MAX_NUM_LODS sections
  3326. lodA = Q_log2(pVertexA->lodFlags);
  3327. lodB = Q_log2(pVertexB->lodFlags);
  3328. // descending sort (LodN..Lod0)
  3329. sort = lodB-lodA;
  3330. if (sort)
  3331. return sort;
  3332. // within same lod, sub sort (ascending) by mesh
  3333. sort = pVertexA->vertexOffset - pVertexB->vertexOffset;
  3334. if (sort)
  3335. return sort;
  3336. // within same mesh, sub sort (ascending) by vertex
  3337. sort = pVertexA->meshVertID - pVertexB->meshVertID;
  3338. return sort;
  3339. }
  3340. //-----------------------------------------------------------------------------
  3341. // UsedVertexLookup_t is used to accelerate the sorted-to-unsorted mapping
  3342. //
  3343. // qsort callback
  3344. //-----------------------------------------------------------------------------
  3345. struct UsedVertexLookup_t
  3346. {
  3347. int vertexOffset;
  3348. int meshVertID;
  3349. int index;
  3350. };
  3351. bool UsedVertexCompareFunc( const UsedVertexLookup_t &a, const UsedVertexLookup_t &b )
  3352. {
  3353. return ( ( a.vertexOffset == b.vertexOffset ) && ( a.meshVertID == b.meshVertID ) );
  3354. }
  3355. unsigned int UsedVertexKeyFunc( const UsedVertexLookup_t &a )
  3356. {
  3357. return Hash8( &a );
  3358. }
  3359. //-----------------------------------------------------------------------------
  3360. // BuildSortedVertexList
  3361. //
  3362. // Generates the sorted vertex list. Routine is purposely serial to
  3363. // ensure vertex integrity.
  3364. //-----------------------------------------------------------------------------
  3365. bool BuildSortedVertexList(const studiohdr_t *pStudioHdr, const void *pVtxBuff, vertexPool_t **ppVertexPools, int *pNumVertexPools, usedVertex_t **ppVertexList, int *pNumVertexes)
  3366. {
  3367. OptimizedModel::FileHeader_t *pVtxHdr;
  3368. OptimizedModel::BodyPartHeader_t *pBodyPartHdr;
  3369. OptimizedModel::ModelHeader_t *pModelHdr;
  3370. OptimizedModel::ModelLODHeader_t *pModelLODHdr;
  3371. OptimizedModel::MeshHeader_t *pMeshHdr;
  3372. OptimizedModel::StripGroupHeader_t *pStripGroupHdr;
  3373. OptimizedModel::Vertex_t *pStripVertex;
  3374. mstudiobodyparts_t *pStudioBodyPart;
  3375. mstudiomodel_t *pStudioModel;
  3376. mstudiomesh_t *pStudioMesh;
  3377. usedVertex_t *usedVertexes;
  3378. vertexPool_t *pVertexPools;
  3379. vertexPool_t *pPool;
  3380. usedVertex_t *pVertexList;
  3381. int *pVertexes;
  3382. int *pVertexMap;
  3383. int index;
  3384. int currLod;
  3385. int vertexOffset;
  3386. int i,j,k,m,n,p;
  3387. int poolStart;
  3388. int numVertexPools;
  3389. int numVertexes;
  3390. int numMeshVertexes;
  3391. int offsets[MAX_NUM_LODS];
  3392. int counts[MAX_NUM_LODS];
  3393. int finalMeshVertID;
  3394. int baseMeshVertID;
  3395. *ppVertexPools = NULL;
  3396. *pNumVertexPools = 0;
  3397. *ppVertexList = NULL;
  3398. *pNumVertexes = 0;
  3399. pVtxHdr = (OptimizedModel::FileHeader_t*)pVtxBuff;
  3400. // determine number of vertex pools
  3401. if (pStudioHdr->numbodyparts != pVtxHdr->numBodyParts)
  3402. return false;
  3403. numVertexPools = 0;
  3404. for (i=0; i<pVtxHdr->numBodyParts; i++)
  3405. {
  3406. pBodyPartHdr = pVtxHdr->pBodyPart(i);
  3407. pStudioBodyPart = pStudioHdr->pBodypart(i);
  3408. if (pStudioBodyPart->nummodels != pBodyPartHdr->numModels)
  3409. return false;
  3410. // the model's subordinate lods only reference from a single top level pool
  3411. // no new verts are created for sub lods
  3412. // each model's subordinate mesh dictates its own vertex pool
  3413. for (j=0; j<pBodyPartHdr->numModels; j++)
  3414. {
  3415. pStudioModel = pStudioBodyPart->pModel(j);
  3416. numVertexPools += pStudioModel->nummeshes;
  3417. }
  3418. }
  3419. // allocate pools
  3420. pVertexPools = (vertexPool_t*)malloc(numVertexPools*sizeof(vertexPool_t));
  3421. memset(pVertexPools, 0, numVertexPools*sizeof(vertexPool_t));
  3422. // iterate lods, mark referenced indexes
  3423. numVertexPools = 0;
  3424. for (i=0; i<pVtxHdr->numBodyParts; i++)
  3425. {
  3426. pBodyPartHdr = pVtxHdr->pBodyPart(i);
  3427. pStudioBodyPart = pStudioHdr->pBodypart(i);
  3428. for (j=0; j<pBodyPartHdr->numModels; j++)
  3429. {
  3430. pModelHdr = pBodyPartHdr->pModel(j);
  3431. pStudioModel = pStudioBodyPart->pModel(j);
  3432. // allocate each mesh's vertex list
  3433. poolStart = numVertexPools;
  3434. for (k=0; k<pStudioModel->nummeshes; k++)
  3435. {
  3436. // track the expected relative offset into a flattened vertex list
  3437. vertexOffset = 0;
  3438. for (m=0; m<poolStart+k; m++)
  3439. vertexOffset += pVertexPools[m].numVertexes;
  3440. pStudioMesh = pStudioModel->pMesh(k);
  3441. numMeshVertexes = pStudioMesh->numvertices;
  3442. if (numMeshVertexes)
  3443. {
  3444. usedVertexes = (usedVertex_t*)malloc(numMeshVertexes*sizeof(usedVertex_t));
  3445. pVertexMap = (int *)malloc(numMeshVertexes*sizeof(int));
  3446. for (n=0; n<numMeshVertexes; n++)
  3447. {
  3448. // setup mapping
  3449. // due to the hierarchical layout, the vertID's map per mesh's pool
  3450. // a linear layout of the vertexes requires a unique signature to achieve a remap
  3451. // the offset and index form a unique signature
  3452. usedVertexes[n].meshVertID = n;
  3453. usedVertexes[n].finalMeshVertID = -1;
  3454. usedVertexes[n].vertexOffset = vertexOffset;
  3455. usedVertexes[n].lodFlags = 0;
  3456. pVertexMap[n] = n;
  3457. }
  3458. pVertexPools[numVertexPools].pVertexList = usedVertexes;
  3459. pVertexPools[numVertexPools].pVertexMap = pVertexMap;
  3460. }
  3461. pVertexPools[numVertexPools].numVertexes = numMeshVertexes;
  3462. numVertexPools++;
  3463. }
  3464. // iterate all lods
  3465. for (currLod=0; currLod<pVtxHdr->numLODs; currLod++)
  3466. {
  3467. pModelLODHdr = pModelHdr->pLOD(currLod);
  3468. if (pModelLODHdr->numMeshes != pStudioModel->nummeshes)
  3469. return false;
  3470. for (k=0; k<pModelLODHdr->numMeshes; k++)
  3471. {
  3472. pMeshHdr = pModelLODHdr->pMesh(k);
  3473. pStudioMesh = pStudioModel->pMesh(k);
  3474. for (m=0; m<pMeshHdr->numStripGroups; m++)
  3475. {
  3476. pStripGroupHdr = pMeshHdr->pStripGroup(m);
  3477. // sanity check the indexes have 100% coverage of the vertexes
  3478. pVertexes = (int*)malloc(pStripGroupHdr->numVerts*sizeof(int));
  3479. memset(pVertexes, 0xFF, pStripGroupHdr->numVerts*sizeof(int));
  3480. for (n=0; n<pStripGroupHdr->numIndices; n++)
  3481. {
  3482. index = *pStripGroupHdr->pIndex(n);
  3483. if (index < 0 || index >= pStripGroupHdr->numVerts)
  3484. return false;
  3485. pVertexes[index] = index;
  3486. }
  3487. // sanity check for coverage
  3488. for (n=0; n<pStripGroupHdr->numVerts; n++)
  3489. {
  3490. if (pVertexes[n] != n)
  3491. return false;
  3492. }
  3493. free(pVertexes);
  3494. // iterate vertexes
  3495. pPool = &pVertexPools[poolStart + k];
  3496. for (n=0; n<pStripGroupHdr->numVerts; n++)
  3497. {
  3498. pStripVertex = pStripGroupHdr->pVertex(n);
  3499. if (pStripVertex->origMeshVertID < 0 || pStripVertex->origMeshVertID >= pPool->numVertexes)
  3500. return false;
  3501. // arrange binary flags for numerical sorting
  3502. // the lowest detail lod's verts at the top, the root lod's verts at the bottom
  3503. pPool->pVertexList[pStripVertex->origMeshVertID].lodFlags |= 1<<currLod;
  3504. }
  3505. }
  3506. }
  3507. }
  3508. }
  3509. }
  3510. // flatten the vertex pool hierarchy into a linear sequence
  3511. numVertexes = 0;
  3512. for (i=0; i<numVertexPools; i++)
  3513. numVertexes += pVertexPools[i].numVertexes;
  3514. pVertexList = (usedVertex_t*)malloc(numVertexes*sizeof(usedVertex_t));
  3515. numVertexes = 0;
  3516. for (i=0; i<numVertexPools; i++)
  3517. {
  3518. pPool = &pVertexPools[i];
  3519. for (j=0; j<pPool->numVertexes; j++)
  3520. {
  3521. if (!pPool->pVertexList[j].lodFlags)
  3522. {
  3523. // found an orphaned vertex that is unreferenced at any lod strip winding
  3524. // don't know how these occur or who references them
  3525. // cannot cull the orphaned vertexes, otherwise vertex counts are wrong
  3526. // every vertex must be remapped
  3527. // force the vertex to belong to the lowest lod
  3528. // lod flags must be nonzero for proper sorted runs
  3529. pPool->pVertexList[j].lodFlags = 1<<(pVtxHdr->numLODs-1);
  3530. }
  3531. }
  3532. memcpy(&pVertexList[numVertexes], pPool->pVertexList, pPool->numVertexes*sizeof(usedVertex_t));
  3533. numVertexes += pPool->numVertexes;
  3534. }
  3535. // sort the vertexes based on lod flags
  3536. // the sort dictates the linear sequencing of the .vvd data file
  3537. // the vtx file indexes get remapped to the new sort order
  3538. qsort( pVertexList, numVertexes, sizeof(usedVertex_t), _CompareUsedVertexes );
  3539. // build a mapping table from mesh relative indexes to the flat lod sorted array
  3540. CUtlHash< UsedVertexLookup_t > usedVertexHash( numVertexes, 0, 0, UsedVertexCompareFunc, UsedVertexKeyFunc );
  3541. for (k=0; k<numVertexes; k++)
  3542. {
  3543. UsedVertexLookup_t usedVertexLookup = { pVertexList[ k ].vertexOffset, pVertexList[ k ].meshVertID, k };
  3544. usedVertexHash.Insert( usedVertexLookup );
  3545. }
  3546. vertexOffset = 0;
  3547. for (i=0; i<numVertexPools; i++)
  3548. {
  3549. pPool = &pVertexPools[i];
  3550. for (j=0; j<pPool->numVertexes; j++)
  3551. {
  3552. // search flattened sorted vertexes
  3553. UsedVertexLookup_t usedVertexLookup = { vertexOffset, j, -1 };
  3554. UtlHashHandle_t handle = usedVertexHash.Find( usedVertexLookup );
  3555. Assert( handle != usedVertexHash.InvalidHandle() );
  3556. pPool->pVertexMap[j] = usedVertexHash[ handle ].index;
  3557. }
  3558. vertexOffset += pPool->numVertexes;
  3559. }
  3560. // build offsets and counts that identifies mesh's distribution across lods
  3561. // calculate final fixed vertex location if vertexes were gathered to mesh order from lod sorted list
  3562. finalMeshVertID = 0;
  3563. poolStart = 0;
  3564. for (i=0; i<pStudioHdr->numbodyparts; i++)
  3565. {
  3566. pStudioBodyPart = pStudioHdr->pBodypart(i);
  3567. for (j=0; j<pStudioBodyPart->nummodels; j++)
  3568. {
  3569. pStudioModel = pStudioBodyPart->pModel(j);
  3570. for (m=0; m<pStudioModel->nummeshes; m++)
  3571. {
  3572. // track the expected offset into linear vertexes
  3573. vertexOffset = 0;
  3574. for (n=0; n<poolStart+m; n++)
  3575. vertexOffset += pVertexPools[n].numVertexes;
  3576. // skip counting if there's no vertices in this mesh
  3577. if ( pStudioModel->pMesh( m )->numvertices == 0 )
  3578. {
  3579. for ( n=0; n < pVtxHdr->numLODs; n++ )
  3580. {
  3581. counts[n] = 0;
  3582. }
  3583. }
  3584. else
  3585. {
  3586. // vertexOffset works as unique key to identify vertexes for a specific mesh
  3587. // a mesh's verts are distributed, but guaranteed sequential in the lod sorted vertex list
  3588. // determine base index and offset and run length for target mesh for all lod levels
  3589. FindVertexOffsets( vertexOffset, offsets, counts, pVtxHdr->numLODs, pVertexList, numVertexes );
  3590. }
  3591. for ( n=0; n < pVtxHdr->numLODs; n++ )
  3592. {
  3593. if ( !counts[n] )
  3594. offsets[n] = 0;
  3595. pVertexPools[poolStart+m].lodMeshInfo.offsets[n] = offsets[n];
  3596. pVertexPools[poolStart+m].lodMeshInfo.numVertexes[n] = counts[n];
  3597. }
  3598. // iterate using calculated offsets to walk each mesh
  3599. // set its expected final vertex id, which is its "gathered" index relative to mesh
  3600. baseMeshVertID = finalMeshVertID;
  3601. for (n=pVtxHdr->numLODs-1; n>=0; n--)
  3602. {
  3603. // iterate each vert in the mesh
  3604. // vertex id is relative to
  3605. for (p=0; p<counts[n]; p++)
  3606. {
  3607. pVertexList[offsets[n] + p].finalMeshVertID = finalMeshVertID - baseMeshVertID;
  3608. finalMeshVertID++;
  3609. }
  3610. }
  3611. }
  3612. poolStart += pStudioModel->nummeshes;
  3613. }
  3614. }
  3615. // safety check
  3616. // every referenced vertex should have been remapped correctly
  3617. // some models do have orphaned vertexes, ignore these
  3618. for (i=0; i<numVertexes; i++)
  3619. {
  3620. if (pVertexList[i].lodFlags && pVertexList[i].finalMeshVertID == -1)
  3621. {
  3622. // should never happen, data occurred in unknown manner
  3623. // don't build corrupted data
  3624. return false;
  3625. }
  3626. }
  3627. // provide generated tables
  3628. *ppVertexPools = pVertexPools;
  3629. *pNumVertexPools = numVertexPools;
  3630. *ppVertexList = pVertexList;
  3631. *pNumVertexes = numVertexes;
  3632. // success
  3633. return true;
  3634. }
  3635. //-----------------------------------------------------------------------------
  3636. // FixupVVDFile
  3637. //
  3638. // VVD files get vertexes remapped to a flat lod sorted order.
  3639. //-----------------------------------------------------------------------------
  3640. bool FixupVVDFile(const char *fileName, const studiohdr_t *pStudioHdr, const void *pVtxBuff, const vertexPool_t *pVertexPools, int numVertexPools, const usedVertex_t *pVertexList, int numVertexes)
  3641. {
  3642. OptimizedModel::FileHeader_t *pVtxHdr;
  3643. vertexFileHeader_t *pFileHdr_old;
  3644. vertexFileHeader_t *pFileHdr_new;
  3645. mstudiobodyparts_t *pStudioBodyPart;
  3646. mstudiomodel_t *pStudioModel;
  3647. mstudiomesh_t *pStudioMesh;
  3648. mstudiovertex_t *pVertex_old;
  3649. mstudiovertex_t *pVertex_new;
  3650. Vector4D *pTangent_new;
  3651. Vector4D *pTangent_old;
  3652. byte *pExtraData_new = NULL;
  3653. byte *pExtraData_old = NULL;
  3654. mstudiovertex_t **pFlatVertexes;
  3655. Vector4D **pFlatTangents;
  3656. byte **pFlatExtraData = NULL;
  3657. vertexFileFixup_t *pFixupTable;
  3658. const lodMeshInfo_t *pLodMeshInfo;
  3659. byte *pStart_new;
  3660. byte *pData_new;
  3661. byte *pStart_base;
  3662. byte *pVertexBase_old;
  3663. byte *pTangentBase_old;
  3664. byte *pExtraDataBase_old = NULL;
  3665. byte *pExtraDataBase_new = NULL;
  3666. void *pVvdBuff;
  3667. int i;
  3668. int j;
  3669. int k;
  3670. int n;
  3671. int p;
  3672. int numFixups;
  3673. int numFlat;
  3674. int oldIndex;
  3675. int mask;
  3676. int maxCount;
  3677. int numMeshes;
  3678. int numOutFixups;
  3679. bool bExtraData = (pStudioHdr->flags & STUDIOHDR_FLAGS_EXTRA_VERTEX_DATA) != 0;
  3680. ExtraVertexAttributeIndex_t* pExtraIndex_old = NULL;
  3681. ExtraVertexAttributeIndex_t* pExtraIndex_new = NULL;
  3682. ExtraVertexAttributesHeader_t* pExtraHeader_old = NULL;
  3683. ExtraVertexAttributesHeader_t* pExtraHeader_new = NULL;
  3684. pVtxHdr = (OptimizedModel::FileHeader_t*)pVtxBuff;
  3685. LoadFile((char*)fileName, &pVvdBuff);
  3686. pFileHdr_old = (vertexFileHeader_t*)pVvdBuff;
  3687. if (pFileHdr_old->numLODs != 1)
  3688. {
  3689. // file has wrong expected state
  3690. return false;
  3691. }
  3692. // meshes need relocation fixup from lod order back to mesh order
  3693. numFixups = 0;
  3694. numMeshes = 0;
  3695. for (i=0; i<pStudioHdr->numbodyparts; i++)
  3696. {
  3697. pStudioBodyPart = pStudioHdr->pBodypart(i);
  3698. for (j=0; j<pStudioBodyPart->nummodels; j++)
  3699. {
  3700. pStudioModel = pStudioBodyPart->pModel(j);
  3701. for (k=0; k<pStudioModel->nummeshes; k++)
  3702. {
  3703. pStudioMesh = pStudioModel->pMesh(k);
  3704. if (!pStudioMesh->numvertices)
  3705. {
  3706. // no vertexes for this mesh, skip it
  3707. continue;
  3708. }
  3709. for (n=pVtxHdr->numLODs-1; n>=0; n--)
  3710. {
  3711. pLodMeshInfo = &pVertexPools[numMeshes+k].lodMeshInfo;
  3712. if (!pLodMeshInfo->numVertexes[n])
  3713. {
  3714. // no vertexes for this portion of the mesh at this lod, skip it
  3715. continue;
  3716. }
  3717. numFixups++;
  3718. }
  3719. }
  3720. numMeshes += k;
  3721. }
  3722. }
  3723. if (numMeshes == 1 || numFixups == 1 || pVtxHdr->numLODs == 1)
  3724. {
  3725. // no fixup required for a single mesh
  3726. // no fixup required for single lod
  3727. // no fixup required when mesh data is contiguous as expected
  3728. numFixups = 0;
  3729. }
  3730. pStart_base = (byte*)malloc(FILEBUFFER);
  3731. memset(pStart_base, 0, FILEBUFFER);
  3732. pStart_new = (byte*)ALIGN(pStart_base,16);
  3733. pData_new = pStart_new;
  3734. // setup headers
  3735. pFileHdr_new = (vertexFileHeader_t*)pData_new;
  3736. pData_new += sizeof(vertexFileHeader_t);
  3737. // clone and fixup new header
  3738. *pFileHdr_new = *pFileHdr_old;
  3739. pFileHdr_new->numLODs = pVtxHdr->numLODs;
  3740. pFileHdr_new->numFixups = numFixups;
  3741. // skip new fixup table
  3742. pData_new = (byte*)ALIGN(pData_new, 4);
  3743. pFixupTable = (vertexFileFixup_t*)pData_new;
  3744. pFileHdr_new->fixupTableStart = pData_new - pStart_new;
  3745. pData_new += numFixups*sizeof(vertexFileFixup_t);
  3746. // skip new vertex data
  3747. pData_new = (byte*)ALIGN(pData_new, 16);
  3748. pVertex_new = (mstudiovertex_t*)pData_new;
  3749. pFileHdr_new->vertexDataStart = pData_new - pStart_new;
  3750. pData_new += numVertexes*sizeof(mstudiovertex_t);
  3751. // skip new tangent data
  3752. pData_new = (byte*)ALIGN(pData_new, 16);
  3753. pTangent_new = (Vector4D*)pData_new;
  3754. pFileHdr_new->tangentDataStart = pData_new - pStart_new;
  3755. pData_new += numVertexes*sizeof(Vector4D);
  3756. pVertexBase_old = (byte*)pFileHdr_old + pFileHdr_old->vertexDataStart;
  3757. pTangentBase_old = (byte*)pFileHdr_old + pFileHdr_old->tangentDataStart;
  3758. // skip extra vertex data
  3759. if ( bExtraData )
  3760. {
  3761. pExtraDataBase_old = pTangentBase_old + numVertexes*sizeof( Vector4D );
  3762. pExtraHeader_old = (ExtraVertexAttributesHeader_t*)pExtraDataBase_old;
  3763. pExtraIndex_old = (ExtraVertexAttributeIndex_t*)(pExtraHeader_old + 1);
  3764. pExtraDataBase_new = pData_new;
  3765. pExtraHeader_new = (ExtraVertexAttributesHeader_t*)pExtraDataBase_new;
  3766. pExtraIndex_new = (ExtraVertexAttributeIndex_t*)(pExtraHeader_new + 1);
  3767. memcpy( pExtraHeader_new, pExtraHeader_old, sizeof( ExtraVertexAttributesHeader_t ) + sizeof( ExtraVertexAttributeIndex_t )*pExtraHeader_old->m_count );
  3768. pData_new += pExtraHeader_old->m_totalbytes;
  3769. }
  3770. // determine number of aggregate verts towards root lod
  3771. // loader can truncate read according to desired root lod
  3772. maxCount = -1;
  3773. for (n=pVtxHdr->numLODs-1; n>=0; n--)
  3774. {
  3775. mask = 1<<n;
  3776. for (p=0; p<numVertexes; p++)
  3777. {
  3778. if (mask & pVertexList[p].lodFlags)
  3779. {
  3780. if (maxCount < p)
  3781. maxCount = p;
  3782. }
  3783. }
  3784. pFileHdr_new->numLODVertexes[n] = maxCount+1;
  3785. }
  3786. for (n=pVtxHdr->numLODs; n<MAX_NUM_LODS; n++)
  3787. {
  3788. // ripple the last valid lod entry all the way down
  3789. pFileHdr_new->numLODVertexes[n] = pFileHdr_new->numLODVertexes[pVtxHdr->numLODs-1];
  3790. }
  3791. // build mesh relocation fixup table
  3792. if (numFixups)
  3793. {
  3794. numMeshes = 0;
  3795. numOutFixups = 0;
  3796. for (i=0; i<pStudioHdr->numbodyparts; i++)
  3797. {
  3798. pStudioBodyPart = pStudioHdr->pBodypart(i);
  3799. for (j=0; j<pStudioBodyPart->nummodels; j++)
  3800. {
  3801. pStudioModel = pStudioBodyPart->pModel(j);
  3802. for (k=0; k<pStudioModel->nummeshes; k++)
  3803. {
  3804. pStudioMesh = pStudioModel->pMesh(k);
  3805. if (!pStudioMesh->numvertices)
  3806. {
  3807. // not vertexes for this mesh, skip it
  3808. continue;
  3809. }
  3810. for (n=pVtxHdr->numLODs-1; n>=0; n--)
  3811. {
  3812. pLodMeshInfo = &pVertexPools[numMeshes+k].lodMeshInfo;
  3813. if (!pLodMeshInfo->numVertexes[n])
  3814. {
  3815. // no vertexes for this portion of the mesh at this lod, skip it
  3816. continue;
  3817. }
  3818. pFixupTable[numOutFixups].lod = n;
  3819. pFixupTable[numOutFixups].numVertexes = pLodMeshInfo->numVertexes[n];
  3820. pFixupTable[numOutFixups].sourceVertexID = pLodMeshInfo->offsets[n];
  3821. numOutFixups++;
  3822. }
  3823. }
  3824. numMeshes += pStudioModel->nummeshes;
  3825. }
  3826. }
  3827. if (numOutFixups != numFixups)
  3828. {
  3829. // logic sync error, final calc should match precalc, otherwise memory corruption
  3830. return false;
  3831. }
  3832. }
  3833. // generate offsets to vertexes
  3834. numFlat = 0;
  3835. pFlatVertexes = (mstudiovertex_t**)malloc(numVertexes*sizeof(mstudiovertex_t*));
  3836. pFlatTangents = (Vector4D**)malloc(numVertexes*sizeof(Vector4D*));
  3837. pFlatExtraData = bExtraData ? (byte**)malloc( numVertexes*sizeof( byte* )*pExtraHeader_old->m_count ) : 0;
  3838. for (i=0; i<pStudioHdr->numbodyparts; i++)
  3839. {
  3840. pStudioBodyPart = pStudioHdr->pBodypart(i);
  3841. for (j=0; j<pStudioBodyPart->nummodels; j++)
  3842. {
  3843. pStudioModel = pStudioBodyPart->pModel(j);
  3844. pVertex_old = (mstudiovertex_t*)&pVertexBase_old[pStudioModel->vertexindex];
  3845. pTangent_old = (Vector4D*)&pTangentBase_old[pStudioModel->tangentsindex];
  3846. for (k=0; k<pStudioModel->nummeshes; k++)
  3847. {
  3848. // get each mesh's vertexes
  3849. pStudioMesh = pStudioModel->pMesh(k);
  3850. for (n=0; n<pStudioMesh->numvertices; n++)
  3851. {
  3852. // old vertex pools are per model, separated per mesh by a start offset
  3853. // vertexes are then isolated subpools per mesh
  3854. // build the flat linear array of lookup pointers
  3855. pFlatVertexes[numFlat] = &pVertex_old[pStudioMesh->vertexoffset + n];
  3856. pFlatTangents[numFlat] = &pTangent_old[pStudioMesh->vertexoffset + n];
  3857. if ( bExtraData )
  3858. {
  3859. for ( int e = 0; e < pExtraHeader_old->m_count; ++e )
  3860. {
  3861. int offset = pExtraIndex_old[e].m_offset;
  3862. int bytesPerVertex = pExtraIndex_old[e].m_bytes;
  3863. pExtraData_old = pExtraDataBase_old + offset + (pStudioModel->vertexindex / sizeof( mstudiovertex_t ))*bytesPerVertex;
  3864. pFlatExtraData[e*numVertexes + numFlat] = &pExtraData_old[(pStudioMesh->vertexoffset + n)*bytesPerVertex];
  3865. }
  3866. }
  3867. numFlat++;
  3868. }
  3869. }
  3870. }
  3871. }
  3872. // write in lod sorted order
  3873. for (i=0; i<numVertexes; i++)
  3874. {
  3875. // iterate sorted order, remap old vert location to new vert location
  3876. oldIndex = pVertexList[i].vertexOffset + pVertexList[i].meshVertID;
  3877. memcpy(&pVertex_new[i], pFlatVertexes[oldIndex], sizeof(mstudiovertex_t));
  3878. memcpy(&pTangent_new[i], pFlatTangents[oldIndex], sizeof(Vector4D));
  3879. if ( bExtraData )
  3880. {
  3881. for ( int e = 0; e < pExtraHeader_old->m_count; ++e )
  3882. {
  3883. int offset = pExtraIndex_old[e].m_offset;
  3884. int bytesPerVertex = pExtraIndex_old[e].m_bytes;
  3885. pExtraData_new = pExtraDataBase_new + offset;
  3886. memcpy( &pExtraData_new[i*bytesPerVertex], pFlatExtraData[e*numVertexes + oldIndex], bytesPerVertex );
  3887. }
  3888. }
  3889. }
  3890. // pFileHdr_new->length = pData_new-pStart_new;
  3891. {
  3892. CP4AutoEditAddFile autop4( fileName );
  3893. SaveFile((char*)fileName, pStart_new, pData_new-pStart_new);
  3894. }
  3895. free(pStart_base);
  3896. free(pFlatVertexes);
  3897. free(pFlatTangents);
  3898. // success
  3899. return true;
  3900. }
  3901. //-----------------------------------------------------------------------------
  3902. // FixupVTXFile
  3903. //
  3904. // VTX files get their windings remapped.
  3905. //-----------------------------------------------------------------------------
  3906. bool FixupVTXFile(const char *fileName, const studiohdr_t *pStudioHdr, const vertexPool_t *pVertexPools, int numVertexPools, const usedVertex_t *pVertexList, int numVertexes)
  3907. {
  3908. OptimizedModel::FileHeader_t *pVtxHdr;
  3909. OptimizedModel::BodyPartHeader_t *pBodyPartHdr;
  3910. OptimizedModel::ModelHeader_t *pModelHdr;
  3911. OptimizedModel::ModelLODHeader_t *pModelLODHdr;
  3912. OptimizedModel::MeshHeader_t *pMeshHdr;
  3913. OptimizedModel::StripGroupHeader_t *pStripGroupHdr;
  3914. OptimizedModel::Vertex_t *pStripVertex;
  3915. int currLod;
  3916. int vertexOffset;
  3917. mstudiobodyparts_t *pStudioBodyPart;
  3918. mstudiomodel_t *pStudioModel;
  3919. int i,j,k,m,n;
  3920. int poolStart;
  3921. int VtxLen;
  3922. int newMeshVertID;
  3923. void *pVtxBuff;
  3924. VtxLen = LoadFile((char*)fileName, &pVtxBuff);
  3925. pVtxHdr = (OptimizedModel::FileHeader_t*)pVtxBuff;
  3926. // iterate all lod's windings
  3927. poolStart = 0;
  3928. for (i=0; i<pVtxHdr->numBodyParts; i++)
  3929. {
  3930. pBodyPartHdr = pVtxHdr->pBodyPart(i);
  3931. pStudioBodyPart = pStudioHdr->pBodypart(i);
  3932. for (j=0; j<pBodyPartHdr->numModels; j++)
  3933. {
  3934. pModelHdr = pBodyPartHdr->pModel(j);
  3935. pStudioModel = pStudioBodyPart->pModel(j);
  3936. // iterate all lods
  3937. for (currLod=0; currLod<pVtxHdr->numLODs; currLod++)
  3938. {
  3939. pModelLODHdr = pModelHdr->pLOD(currLod);
  3940. if (pModelLODHdr->numMeshes != pStudioModel->nummeshes)
  3941. return false;
  3942. for (k=0; k<pModelLODHdr->numMeshes; k++)
  3943. {
  3944. // track the expected relative offset into the flat vertexes
  3945. vertexOffset = 0;
  3946. for (m=0; m<poolStart+k; m++)
  3947. vertexOffset += pVertexPools[m].numVertexes;
  3948. pMeshHdr = pModelLODHdr->pMesh(k);
  3949. for (m=0; m<pMeshHdr->numStripGroups; m++)
  3950. {
  3951. pStripGroupHdr = pMeshHdr->pStripGroup(m);
  3952. for (n=0; n<pStripGroupHdr->numVerts; n++)
  3953. {
  3954. pStripVertex = pStripGroupHdr->pVertex(n);
  3955. // remap old mesh relative vertex index to absolute flat sorted list
  3956. newMeshVertID = pVertexPools[poolStart+k].pVertexMap[pStripVertex->origMeshVertID];
  3957. // map to expected final fixed vertex locations
  3958. // final fixed vertex location is performed by runtime loading code
  3959. newMeshVertID = pVertexList[newMeshVertID].finalMeshVertID;
  3960. // fixup to expected
  3961. pStripVertex->origMeshVertID = newMeshVertID;
  3962. }
  3963. }
  3964. }
  3965. }
  3966. poolStart += pStudioModel->nummeshes;
  3967. }
  3968. }
  3969. // pVtxHdr->length = VtxLen;
  3970. {
  3971. CP4AutoEditAddFile autop4( fileName );
  3972. SaveFile((char*)fileName, pVtxBuff, VtxLen);
  3973. }
  3974. free(pVtxBuff);
  3975. return true;
  3976. }
  3977. //-----------------------------------------------------------------------------
  3978. // FixupMDLFile
  3979. //
  3980. // MDL files get flexes/vertex/tangent data offsets fixed
  3981. //-----------------------------------------------------------------------------
  3982. bool FixupMDLFile(const char *fileName, studiohdr_t *pStudioHdr, const void *pVtxBuff, const vertexPool_t *pVertexPools, int numVertexPools, const usedVertex_t *pVertexList, int numVertexes)
  3983. {
  3984. OptimizedModel::FileHeader_t *pVtxHdr;
  3985. const lodMeshInfo_t *pLodMeshInfo;
  3986. mstudiobodyparts_t *pStudioBodyPart;
  3987. mstudiomodel_t *pStudioModel;
  3988. mstudiomesh_t *pStudioMesh;
  3989. mstudioflex_t *pStudioFlex;
  3990. mstudiovertanim_t *pStudioVertAnim;
  3991. int newMeshVertID;
  3992. int i;
  3993. int j;
  3994. int m;
  3995. int n;
  3996. int p;
  3997. int numLODs;
  3998. int numMeshes;
  3999. int total;
  4000. pVtxHdr = (OptimizedModel::FileHeader_t*)pVtxBuff;
  4001. numLODs = pVtxHdr->numLODs;
  4002. numMeshes = 0;
  4003. for (i=0; i<pStudioHdr->numbodyparts; i++)
  4004. {
  4005. pStudioBodyPart = pStudioHdr->pBodypart(i);
  4006. for (j=0; j<pStudioBodyPart->nummodels; j++)
  4007. {
  4008. pStudioModel = pStudioBodyPart->pModel(j);
  4009. for (m=0; m<pStudioModel->nummeshes; m++)
  4010. {
  4011. // get each mesh
  4012. pStudioMesh = pStudioModel->pMesh(m);
  4013. pLodMeshInfo = &pVertexPools[numMeshes+m].lodMeshInfo;
  4014. for (n=0; n<numLODs; n++)
  4015. {
  4016. // the root lod, contains all the lower detail lods verts
  4017. // tally the verts that are at each lod
  4018. total = 0;
  4019. for (p=n; p<numLODs; p++)
  4020. total += pLodMeshInfo->numVertexes[p];
  4021. // embed the fixup for loader
  4022. pStudioMesh->vertexdata.numLODVertexes[n] = total;
  4023. }
  4024. for (p=n; p<MAX_NUM_LODS; p++)
  4025. {
  4026. // duplicate last valid lod to end of list
  4027. pStudioMesh->vertexdata.numLODVertexes[p] = pStudioMesh->vertexdata.numLODVertexes[numLODs-1];
  4028. }
  4029. // fix the flexes
  4030. for (n=0; n<pStudioMesh->numflexes; n++)
  4031. {
  4032. pStudioFlex = pStudioMesh->pFlex(n);
  4033. byte *pvanim = pStudioFlex->pBaseVertanim();
  4034. int nVAnimSizeBytes = pStudioFlex->VertAnimSizeBytes();
  4035. for (p=0; p<pStudioFlex->numverts; p++, pvanim += nVAnimSizeBytes )
  4036. {
  4037. pStudioVertAnim = (mstudiovertanim_t*)( pvanim );
  4038. if ( pStudioVertAnim->index < 0 || pStudioVertAnim->index >= pStudioMesh->numvertices )
  4039. return false;
  4040. // remap old mesh relative vertex index to absolute flat sorted list
  4041. newMeshVertID = pVertexPools[numMeshes+m].pVertexMap[pStudioVertAnim->index];
  4042. // map to expected final fixed vertex locations
  4043. // final fixed vertex location is performed by runtime loading code
  4044. newMeshVertID = pVertexList[newMeshVertID].finalMeshVertID;
  4045. // fixup to expected
  4046. pStudioVertAnim->index = newMeshVertID;
  4047. }
  4048. }
  4049. }
  4050. numMeshes += pStudioModel->nummeshes;
  4051. }
  4052. }
  4053. // Reset any pointer values to zero before writing out final mdl.
  4054. // This allows better testing of the studiomdl tool -
  4055. // mdl files can be compared more easily from one run to another.
  4056. for (i = 0; i < pStudioHdr->numbodyparts; i++)
  4057. {
  4058. pStudioBodyPart = pStudioHdr->pBodypart(i);
  4059. for (j = 0; j < pStudioBodyPart->nummodels; j++)
  4060. {
  4061. pStudioModel = pStudioBodyPart->pModel(j);
  4062. for (m = 0; m < pStudioModel->nummeshes; m++)
  4063. {
  4064. pStudioMesh = pStudioModel->pMesh(m);
  4065. }
  4066. }
  4067. }
  4068. if (pStudioHdr->textureindex != 0)
  4069. {
  4070. for (int i = 0; i < pStudioHdr->numtextures; i++)
  4071. {
  4072. pStudioHdr->pTexture(i)->material = NULL;
  4073. }
  4074. }
  4075. // Clear vertex data
  4076. {
  4077. CP4AutoEditAddFile autop4( fileName );
  4078. SaveFile((char*)fileName, (void*)pStudioHdr, pStudioHdr->length);
  4079. }
  4080. // success
  4081. return true;
  4082. }
  4083. //-----------------------------------------------------------------------------
  4084. // FixupToSortedLODVertexes
  4085. //
  4086. // VVD files get vertexes fixed to a flat sorted order, ascending in lower detail lod usage
  4087. // VTX files get their windings remapped to the sort.
  4088. //-----------------------------------------------------------------------------
  4089. bool FixupToSortedLODVertexes(studiohdr_t *pStudioHdr)
  4090. {
  4091. char filename[260];
  4092. char tmpFileName[260];
  4093. void *pVtxBuff;
  4094. usedVertex_t *pVertexList;
  4095. vertexPool_t *pVertexPools;
  4096. int numVertexes;
  4097. int numVertexPools;
  4098. int VtxLen;
  4099. int i;
  4100. const char *vtxPrefixes[] = { ".dx90.vtx", ".dx80.vtx", ".sw.vtx" };
  4101. const int numPrefixes = ( g_gameinfo.bSupportsDX8 && !g_bFastBuild ) ? ARRAYSIZE( vtxPrefixes ) : 1;
  4102. const int idxPrefixLodUsage = ( g_gameinfo.bSupportsDX8 && !g_bFastBuild ) ? 1 : 0;
  4103. strcpy( filename, gamedir );
  4104. // if( *g_pPlatformName )
  4105. // {
  4106. // strcat( filename, "platform_" );
  4107. // strcat( filename, g_pPlatformName );
  4108. // strcat( filename, "/" );
  4109. // }
  4110. strcat( filename, "models/" );
  4111. strcat( filename, g_outname );
  4112. Q_StripExtension( filename, filename, sizeof( filename ) );
  4113. // determine lod usage per vertex
  4114. // all vtx files enumerate model's lod verts, but differ in their mesh makeup
  4115. // use xxx.dx90.vtx to establish which vertexes are used by each lod
  4116. strcpy( tmpFileName, filename );
  4117. strcat( tmpFileName, vtxPrefixes[ idxPrefixLodUsage ] );
  4118. VtxLen = LoadFile( tmpFileName, &pVtxBuff );
  4119. // build the sorted vertex tables
  4120. if (!BuildSortedVertexList(pStudioHdr, pVtxBuff, &pVertexPools, &numVertexPools, &pVertexList, &numVertexes))
  4121. {
  4122. // data sync error
  4123. return false;
  4124. }
  4125. // fixup ???.vvd
  4126. strcpy( tmpFileName, filename );
  4127. strcat( tmpFileName, ".vvd" );
  4128. if (!FixupVVDFile(tmpFileName, pStudioHdr, pVtxBuff, pVertexPools, numVertexPools, pVertexList, numVertexes))
  4129. {
  4130. // data error
  4131. return false;
  4132. }
  4133. for ( i = 0; i < numPrefixes; i++ )
  4134. {
  4135. // fixup ???.vtx
  4136. strcpy( tmpFileName, filename );
  4137. strcat( tmpFileName, vtxPrefixes[i] );
  4138. if (!FixupVTXFile(tmpFileName, pStudioHdr, pVertexPools, numVertexPools, pVertexList, numVertexes))
  4139. {
  4140. // data error
  4141. return false;
  4142. }
  4143. }
  4144. // fixup ???.mdl
  4145. strcpy( tmpFileName, filename );
  4146. strcat( tmpFileName, ".mdl" );
  4147. if (!FixupMDLFile(tmpFileName, pStudioHdr, pVtxBuff, pVertexPools, numVertexPools, pVertexList, numVertexes))
  4148. {
  4149. // data error
  4150. return false;
  4151. }
  4152. // free the tables
  4153. for (i=0; i<numVertexPools; i++)
  4154. {
  4155. if (pVertexPools[i].pVertexList)
  4156. free(pVertexPools[i].pVertexList);
  4157. if (pVertexPools[i].pVertexMap)
  4158. free(pVertexPools[i].pVertexMap);
  4159. }
  4160. if (numVertexPools)
  4161. free(pVertexPools);
  4162. free(pVtxBuff);
  4163. // success
  4164. return true;
  4165. }
  4166. byte IsByte( int val )
  4167. {
  4168. if (val < 0 || val > 0xFF)
  4169. {
  4170. MdlError("byte conversion out of range %d\n", val );
  4171. }
  4172. return val;
  4173. }
  4174. char IsChar( int val )
  4175. {
  4176. if (val < -0x80 || val > 0x7F)
  4177. {
  4178. MdlError("char conversion out of range %d\n", val );
  4179. }
  4180. return val;
  4181. }
  4182. int IsInt24( int val )
  4183. {
  4184. if (val < -0x800000 || val > 0x7FFFFF)
  4185. {
  4186. MdlError("int24 conversion out of range %d\n", val );
  4187. }
  4188. return val;
  4189. }
  4190. short IsShort( int val )
  4191. {
  4192. if (val < -0x8000 || val > 0x7FFF)
  4193. {
  4194. MdlError("short conversion out of range %d\n", val );
  4195. }
  4196. return val;
  4197. }
  4198. unsigned short IsUShort( int val )
  4199. {
  4200. if (val < 0 || val > 0xFFFF)
  4201. {
  4202. MdlError("ushort conversion out of range %d\n", val );
  4203. }
  4204. return val;
  4205. }
  4206. bool Clamp_MDL_LODS( const char *fileName, int rootLOD )
  4207. {
  4208. studiohdr_t *pStudioHdr;
  4209. int len;
  4210. len = LoadFile((char*)fileName, (void **)&pStudioHdr);
  4211. Studio_SetRootLOD( pStudioHdr, rootLOD );
  4212. #if 0
  4213. // shift down bone LOD masks
  4214. int iBone;
  4215. for ( iBone = 0; iBone < pStudioHdr->numbones; iBone++)
  4216. {
  4217. const mstudiobone_t *pBone = pStudioHdr->pBone( iBone );
  4218. int nLodID;
  4219. for ( nLodID = 0; nLodID < rootLOD; nLodID++)
  4220. {
  4221. int iLodMask = BONE_USED_BY_VERTEX_LOD0 << nLodID;
  4222. if (pBone->flags & (BONE_USED_BY_VERTEX_LOD0 << rootLOD))
  4223. {
  4224. pBone->flags = pBone->flags | iLodMask;
  4225. }
  4226. else
  4227. {
  4228. pBone->flags = pBone->flags & (~iLodMask);
  4229. }
  4230. }
  4231. }
  4232. #endif
  4233. {
  4234. CP4AutoEditAddFile autop4( fileName );
  4235. SaveFile( (char *)fileName, pStudioHdr, len );
  4236. }
  4237. return true;
  4238. }
  4239. bool Clamp_VVD_LODS( const char *fileName, int rootLOD, bool bExtraData )
  4240. {
  4241. vertexFileHeader_t *pTempVvdHdr;
  4242. int len;
  4243. len = LoadFile((char*)fileName, (void **)&pTempVvdHdr);
  4244. int newLength = Studio_VertexDataSize( pTempVvdHdr, rootLOD, true, bExtraData );
  4245. // printf("was %d now %d\n", len, newLength );
  4246. vertexFileHeader_t *pNewVvdHdr = (vertexFileHeader_t *)calloc( newLength, 1 );
  4247. Studio_LoadVertexes( pTempVvdHdr, pNewVvdHdr, rootLOD, true, bExtraData );
  4248. if (!g_quiet)
  4249. {
  4250. printf ("---------------------\n");
  4251. printf ("writing %s:\n", fileName);
  4252. printf( "vertices (%d vertices)\n", pNewVvdHdr->numLODVertexes[ 0 ] );
  4253. }
  4254. // pNewVvdHdr->length = newLength;
  4255. {
  4256. CP4AutoEditAddFile autop4( fileName );
  4257. SaveFile( (char *)fileName, pNewVvdHdr, newLength );
  4258. }
  4259. return true;
  4260. }
  4261. bool Clamp_VTX_LODS( const char *fileName, int rootLOD, studiohdr_t *pStudioHdr )
  4262. {
  4263. int i, j, k, m, n;
  4264. int nLodID;
  4265. int size;
  4266. OptimizedModel::FileHeader_t *pVtxHdr;
  4267. int len;
  4268. len = LoadFile((char*)fileName, (void **)&pVtxHdr);
  4269. OptimizedModel::FileHeader_t *pNewVtxHdr = (OptimizedModel::FileHeader_t *)calloc( FILEBUFFER, 1 );
  4270. byte *pData = (byte *)pNewVtxHdr;
  4271. pData += sizeof( OptimizedModel::FileHeader_t );
  4272. ALIGN4( pData );
  4273. // header
  4274. pNewVtxHdr->version = pVtxHdr->version;
  4275. pNewVtxHdr->vertCacheSize = pVtxHdr->vertCacheSize;
  4276. pNewVtxHdr->maxBonesPerStrip = pVtxHdr->maxBonesPerStrip;
  4277. pNewVtxHdr->maxBonesPerFace = pVtxHdr->maxBonesPerFace;
  4278. pNewVtxHdr->maxBonesPerVert = pVtxHdr->maxBonesPerVert;
  4279. pNewVtxHdr->checkSum = pVtxHdr->checkSum;
  4280. pNewVtxHdr->numLODs = pVtxHdr->numLODs;
  4281. // material replacement list
  4282. pNewVtxHdr->materialReplacementListOffset = (pData - (byte *)pNewVtxHdr);
  4283. pData += pVtxHdr->numLODs * sizeof( OptimizedModel::MaterialReplacementListHeader_t );
  4284. // ALIGN4( pData );
  4285. BeginStringTable( );
  4286. // allocate replacement list arrays
  4287. for ( nLodID = rootLOD; nLodID < pVtxHdr->numLODs; nLodID++ )
  4288. {
  4289. OptimizedModel::MaterialReplacementListHeader_t *pReplacementList = pVtxHdr->pMaterialReplacementList( nLodID );
  4290. OptimizedModel::MaterialReplacementListHeader_t *pNewReplacementList = pNewVtxHdr->pMaterialReplacementList( nLodID );
  4291. pNewReplacementList->numReplacements = pReplacementList->numReplacements;
  4292. pNewReplacementList->replacementOffset = (pData - (byte *)pNewReplacementList);
  4293. pData += pNewReplacementList->numReplacements * sizeof( OptimizedModel::MaterialReplacementHeader_t );
  4294. // ALIGN4( pData );
  4295. for (i = 0; i < pReplacementList->numReplacements; i++)
  4296. {
  4297. OptimizedModel::MaterialReplacementHeader_t *pReplacement = pReplacementList->pMaterialReplacement( i );
  4298. OptimizedModel::MaterialReplacementHeader_t *pNewReplacement = pNewReplacementList->pMaterialReplacement( i );
  4299. pNewReplacement->materialID = pReplacement->materialID;
  4300. AddToStringTable( pNewReplacement, &pNewReplacement->replacementMaterialNameOffset, pReplacement->pMaterialReplacementName() );
  4301. }
  4302. }
  4303. pData = WriteStringTable( pData );
  4304. // link previous LODs to higher LODs
  4305. for ( nLodID = 0; nLodID < rootLOD; nLodID++ )
  4306. {
  4307. OptimizedModel::MaterialReplacementListHeader_t *pRootReplacementList = pNewVtxHdr->pMaterialReplacementList( rootLOD );
  4308. OptimizedModel::MaterialReplacementListHeader_t *pNewReplacementList = pNewVtxHdr->pMaterialReplacementList( nLodID );
  4309. int delta = (byte *)pRootReplacementList - (byte *)pNewReplacementList;
  4310. pNewReplacementList->numReplacements = pRootReplacementList->numReplacements;
  4311. pNewReplacementList->replacementOffset = pRootReplacementList->replacementOffset + delta;
  4312. }
  4313. // body parts
  4314. pNewVtxHdr->numBodyParts = pStudioHdr->numbodyparts;
  4315. pNewVtxHdr->bodyPartOffset = (pData - (byte *)pNewVtxHdr);
  4316. pData += pNewVtxHdr->numBodyParts * sizeof( OptimizedModel::BodyPartHeader_t );
  4317. // ALIGN4( pData );
  4318. // Iterate over every body part...
  4319. for ( i = 0; i < pStudioHdr->numbodyparts; i++ )
  4320. {
  4321. mstudiobodyparts_t* pBodyPart = pStudioHdr->pBodypart(i);
  4322. OptimizedModel::BodyPartHeader_t* pVtxBodyPart = pVtxHdr->pBodyPart(i);
  4323. OptimizedModel::BodyPartHeader_t* pNewVtxBodyPart = pNewVtxHdr->pBodyPart(i);
  4324. pNewVtxBodyPart->numModels = pBodyPart->nummodels;
  4325. pNewVtxBodyPart->modelOffset = (pData - (byte *)pNewVtxBodyPart);
  4326. pData += pNewVtxBodyPart->numModels * sizeof( OptimizedModel::ModelHeader_t );
  4327. // ALIGN4( pData );
  4328. // Iterate over every submodel...
  4329. for (j = 0; j < pBodyPart->nummodels; ++j)
  4330. {
  4331. mstudiomodel_t* pModel = pBodyPart->pModel(j);
  4332. OptimizedModel::ModelHeader_t* pVtxModel = pVtxBodyPart->pModel(j);
  4333. OptimizedModel::ModelHeader_t* pNewVtxModel = pNewVtxBodyPart->pModel(j);
  4334. pNewVtxModel->numLODs = pVtxModel->numLODs;
  4335. pNewVtxModel->lodOffset = (pData - (byte *)pNewVtxModel);
  4336. pData += pNewVtxModel->numLODs * sizeof( OptimizedModel::ModelLODHeader_t );
  4337. ALIGN4( pData );
  4338. for ( nLodID = rootLOD; nLodID < pVtxModel->numLODs; nLodID++ )
  4339. {
  4340. OptimizedModel::ModelLODHeader_t *pVtxLOD = pVtxModel->pLOD( nLodID );
  4341. OptimizedModel::ModelLODHeader_t *pNewVtxLOD = pNewVtxModel->pLOD( nLodID );
  4342. pNewVtxLOD->numMeshes = pVtxLOD->numMeshes;
  4343. pNewVtxLOD->switchPoint = pVtxLOD->switchPoint;
  4344. pNewVtxLOD->meshOffset = (pData - (byte *)pNewVtxLOD);
  4345. pData += pNewVtxLOD->numMeshes * sizeof( OptimizedModel::MeshHeader_t );
  4346. ALIGN4( pData );
  4347. // Iterate over all the meshes....
  4348. for (k = 0; k < pModel->nummeshes; ++k)
  4349. {
  4350. Assert( pModel->nummeshes == pVtxLOD->numMeshes );
  4351. // mstudiomesh_t* pMesh = pModel->pMesh(k);
  4352. OptimizedModel::MeshHeader_t* pVtxMesh = pVtxLOD->pMesh(k);
  4353. OptimizedModel::MeshHeader_t* pNewVtxMesh = pNewVtxLOD->pMesh(k);
  4354. pNewVtxMesh->numStripGroups = pVtxMesh->numStripGroups;
  4355. pNewVtxMesh->flags = pVtxMesh->flags;
  4356. pNewVtxMesh->stripGroupHeaderOffset = (pData - (byte *)pNewVtxMesh);
  4357. pData += pNewVtxMesh->numStripGroups * sizeof( OptimizedModel::StripGroupHeader_t );
  4358. // printf("part %d : model %d : lod %d : mesh %d : strips %d : offset %d\n", i, j, nLodID, k, pVtxMesh->numStripGroups, pVtxMesh->stripGroupHeaderOffset );
  4359. for (m = 0; m < pVtxMesh->numStripGroups; m++)
  4360. {
  4361. OptimizedModel::StripGroupHeader_t *pStripGroup = pVtxMesh->pStripGroup( m );
  4362. OptimizedModel::StripGroupHeader_t *pNewStripGroup = pNewVtxMesh->pStripGroup( m );
  4363. // int delta = ((byte *)pStripGroup - (byte *)pVtxHdr) - ((byte *)pNewStripGroup - (byte *)pNewVtxHdr);
  4364. pNewStripGroup->numVerts = pStripGroup->numVerts;
  4365. pNewStripGroup->vertOffset = (pData - (byte *)pNewStripGroup);
  4366. size = pNewStripGroup->numVerts * sizeof( OptimizedModel::Vertex_t );
  4367. memcpy( pData, pStripGroup->pVertex(0), size );
  4368. pData += size;
  4369. pNewStripGroup->numIndices = pStripGroup->numIndices;
  4370. pNewStripGroup->indexOffset = (pData - (byte *)pNewStripGroup);
  4371. size = pNewStripGroup->numIndices * sizeof( unsigned short );
  4372. memcpy( pData, pStripGroup->pIndex(0), size );
  4373. pData += size;
  4374. pNewStripGroup->numStrips = pStripGroup->numStrips;
  4375. pNewStripGroup->stripOffset = (pData - (byte *)pNewStripGroup);
  4376. size = pNewStripGroup->numStrips * sizeof( OptimizedModel::StripHeader_t );
  4377. pData += size;
  4378. pNewStripGroup->flags = pStripGroup->flags;
  4379. /*
  4380. printf("\tnumVerts %d %d :\n", pStripGroup->numVerts, pStripGroup->vertOffset );
  4381. printf("\tnumIndices %d %d :\n", pStripGroup->numIndices, pStripGroup->indexOffset );
  4382. printf("\tnumStrips %d %d :\n", pStripGroup->numStrips, pStripGroup->stripOffset );
  4383. */
  4384. for (n = 0; n < pStripGroup->numStrips; n++)
  4385. {
  4386. OptimizedModel::StripHeader_t *pStrip = pStripGroup->pStrip( n );
  4387. OptimizedModel::StripHeader_t *pNewStrip = pNewStripGroup->pStrip( n );
  4388. pNewStrip->numIndices = pStrip->numIndices;
  4389. pNewStrip->indexOffset = pStrip->indexOffset;
  4390. pNewStrip->numVerts = pStrip->numVerts;
  4391. pNewStrip->vertOffset = pStrip->vertOffset;
  4392. pNewStrip->numBones = pStrip->numBones;
  4393. pNewStrip->flags = pStrip->flags;
  4394. pNewStrip->numBoneStateChanges = pStrip->numBoneStateChanges;
  4395. pNewStrip->boneStateChangeOffset = (pData - (byte *)pNewStrip);
  4396. size = pNewStrip->numBoneStateChanges * sizeof( OptimizedModel::BoneStateChangeHeader_t );
  4397. memcpy( pData, pStrip->pBoneStateChange(0), size );
  4398. pData += size;
  4399. /*
  4400. printf("\t\tnumIndices %d %d :\n", pNewStrip->numIndices, pNewStrip->indexOffset );
  4401. printf("\t\tnumVerts %d %d :\n", pNewStrip->numVerts, pNewStrip->vertOffset );
  4402. printf("\t\tnumBoneStateChanges %d %d :\n", pNewStrip->numBoneStateChanges, pNewStrip->boneStateChangeOffset );
  4403. */
  4404. // printf("(%d)\n", delta );
  4405. }
  4406. // printf("(%d)\n", delta );
  4407. }
  4408. }
  4409. }
  4410. }
  4411. }
  4412. // Iterate over every body part...
  4413. for ( i = 0; i < pStudioHdr->numbodyparts; i++ )
  4414. {
  4415. mstudiobodyparts_t* pBodyPart = pStudioHdr->pBodypart(i);
  4416. // Iterate over every submodel...
  4417. for (j = 0; j < pBodyPart->nummodels; ++j)
  4418. {
  4419. // link previous LODs to higher LODs
  4420. for ( nLodID = 0; nLodID < rootLOD; nLodID++ )
  4421. {
  4422. OptimizedModel::ModelLODHeader_t *pVtxLOD = pVtxHdr->pBodyPart(i)->pModel(j)->pLOD(nLodID);
  4423. OptimizedModel::ModelLODHeader_t *pRootVtxLOD = pNewVtxHdr->pBodyPart(i)->pModel(j)->pLOD(rootLOD);
  4424. OptimizedModel::ModelLODHeader_t *pNewVtxLOD = pNewVtxHdr->pBodyPart(i)->pModel(j)->pLOD(nLodID);
  4425. pNewVtxLOD->numMeshes = pRootVtxLOD->numMeshes;
  4426. pNewVtxLOD->switchPoint = pVtxLOD->switchPoint;
  4427. int delta = (byte *)pRootVtxLOD - (byte *)pNewVtxLOD;
  4428. pNewVtxLOD->meshOffset = pRootVtxLOD->meshOffset + delta;
  4429. }
  4430. }
  4431. }
  4432. int newLen = pData - (byte *)pNewVtxHdr;
  4433. // printf("len %d : %d\n", len, newLen );
  4434. // pNewVtxHdr->length = newLen;
  4435. if (!g_quiet)
  4436. {
  4437. printf ("writing %s:\n", fileName);
  4438. printf( "everything (%d bytes)\n", newLen );
  4439. }
  4440. {
  4441. CP4AutoEditAddFile autop4( fileName );
  4442. SaveFile( (char *)fileName, pNewVtxHdr, newLen );
  4443. }
  4444. free( pNewVtxHdr );
  4445. return true;
  4446. }
  4447. bool Clamp_RootLOD( studiohdr_t *phdr )
  4448. {
  4449. char filename[260];
  4450. char tmpFileName[260];
  4451. int i;
  4452. const char *vtxPrefixes[] = { ".dx90.vtx", ".dx80.vtx", ".sw.vtx" };
  4453. const int numPrefixes = ( g_gameinfo.bSupportsDX8 && !g_bFastBuild ) ? ARRAYSIZE( vtxPrefixes ) : 1;
  4454. bool bExtraData = (phdr->flags & STUDIOHDR_FLAGS_EXTRA_VERTEX_DATA) != 0;
  4455. int rootLOD = g_minLod;
  4456. if (rootLOD > g_ScriptLODs.Count() - 1)
  4457. {
  4458. rootLOD = g_ScriptLODs.Count() -1;
  4459. }
  4460. if (rootLOD == 0)
  4461. {
  4462. return true;
  4463. }
  4464. strcpy( filename, gamedir );
  4465. strcat( filename, "models/" );
  4466. strcat( filename, g_outname );
  4467. Q_StripExtension( filename, filename, sizeof( filename ) );
  4468. // shift the files so that g_minLod is the root LOD
  4469. strcpy( tmpFileName, filename );
  4470. strcat( tmpFileName, ".mdl" );
  4471. Clamp_MDL_LODS( tmpFileName, rootLOD );
  4472. strcpy( tmpFileName, filename );
  4473. strcat( tmpFileName, ".vvd" );
  4474. Clamp_VVD_LODS( tmpFileName, rootLOD, bExtraData );
  4475. for ( i = 0; i < numPrefixes; i++ )
  4476. {
  4477. // fixup ???.vtx
  4478. strcpy( tmpFileName, filename );
  4479. strcat( tmpFileName, vtxPrefixes[i] );
  4480. Clamp_VTX_LODS( tmpFileName, rootLOD, phdr );
  4481. }
  4482. return true;
  4483. }
  4484. //----------------------------------------------------------------------
  4485. // For a particular .qc, converts all studiomdl generated files to big-endian format.
  4486. //----------------------------------------------------------------------
  4487. void WriteSwappedFile( char *srcname, char *outname, int(*pfnSwapFunc)(void*, int, const void*, int) )
  4488. {
  4489. if ( FileExists( srcname ) )
  4490. {
  4491. if( !g_quiet )
  4492. {
  4493. printf( "---------------------\n" );
  4494. printf( "Generating Xbox360 file format for \"%s\":\n", srcname );
  4495. }
  4496. void *pFileBase = NULL;
  4497. int fileSize = LoadFile( srcname, &pFileBase );
  4498. int paddedSize = fileSize + BYTESWAP_ALIGNMENT_PADDING;
  4499. void *pOutBase = malloc( paddedSize );
  4500. int bytes = pfnSwapFunc( pOutBase, paddedSize, pFileBase, fileSize );
  4501. if ( bytes != 0 )
  4502. {
  4503. CP4AutoEditAddFile autop4( outname );
  4504. SaveFile( outname, pOutBase, bytes );
  4505. }
  4506. free(pOutBase);
  4507. free(pFileBase);
  4508. if ( bytes == 0 )
  4509. {
  4510. MdlError( "Aborted byteswap on '%s':\n", srcname );
  4511. }
  4512. }
  4513. }
  4514. //----------------------------------------------------------------------
  4515. // For a particular .qc, converts all studiomdl generated files to big-endian format.
  4516. //----------------------------------------------------------------------
  4517. void WriteAllSwappedFiles( const char *filename )
  4518. {
  4519. char srcname[ MAX_PATH ];
  4520. char outname[ MAX_PATH ];
  4521. extern IPhysicsCollision *physcollision;
  4522. if ( physcollision )
  4523. {
  4524. StudioByteSwap::SetCollisionInterface( physcollision );
  4525. }
  4526. // Convert PHY
  4527. Q_StripExtension( filename, srcname, sizeof( srcname ) );
  4528. Q_strncpy( outname, srcname, sizeof( outname ) );
  4529. Q_strcat( srcname, ".phy", sizeof( srcname ) );
  4530. Q_strcat( outname, ".360.phy", sizeof( outname ) );
  4531. WriteSwappedFile( srcname, outname, StudioByteSwap::ByteswapPHY );
  4532. // Convert VVD
  4533. Q_StripExtension( filename, srcname, sizeof( srcname ) );
  4534. Q_strncpy( outname, srcname, sizeof( outname ) );
  4535. Q_strcat( srcname, ".vvd", sizeof( srcname ) );
  4536. Q_strcat( outname, ".360.vvd", sizeof( outname ) );
  4537. WriteSwappedFile( srcname, outname, StudioByteSwap::ByteswapVVD );
  4538. // Convert VTX
  4539. Q_StripExtension( filename, srcname, sizeof( srcname ) );
  4540. Q_StripExtension( srcname, srcname, sizeof( srcname ) );
  4541. Q_strncpy( outname, srcname, sizeof( outname ) );
  4542. Q_strcat( srcname, ".dx90.vtx", sizeof( srcname ) );
  4543. Q_strcat( outname, ".360.vtx", sizeof( outname ) );
  4544. WriteSwappedFile( srcname, outname, StudioByteSwap::ByteswapVTX );
  4545. // Convert MDL
  4546. Q_StripExtension( filename, srcname, sizeof( srcname ) );
  4547. Q_strncpy( outname, srcname, sizeof( outname ) );
  4548. Q_strcat( srcname, ".mdl", sizeof( srcname ) );
  4549. Q_strcat( outname, ".360.mdl", sizeof( outname ) );
  4550. WriteSwappedFile( srcname, outname, StudioByteSwap::ByteswapMDL );
  4551. }