Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

594 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include <limits.h>
  9. #include "studio.h"
  10. #include "tier1/utlmap.h"
  11. #include "tier1/utldict.h"
  12. #include "tier1/utlbuffer.h"
  13. #include "filesystem.h"
  14. #include "tier0/icommandline.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. extern IFileSystem * g_pFileSystem;
  18. //-----------------------------------------------------------------------------
  19. // Purpose:
  20. //-----------------------------------------------------------------------------
  21. // a string table to speed up searching for sequences in the current virtual model
  22. struct modellookup_t
  23. {
  24. CUtlDict<short,short> seqTable;
  25. CUtlDict<short,short> animTable;
  26. };
  27. static CUtlVector<modellookup_t> g_ModelLookup;
  28. static int g_ModelLookupIndex = -1;
  29. inline bool HasLookupTable()
  30. {
  31. return g_ModelLookupIndex >= 0 ? true : false;
  32. }
  33. inline CUtlDict<short,short> *GetSeqTable()
  34. {
  35. return &g_ModelLookup[g_ModelLookupIndex].seqTable;
  36. }
  37. inline CUtlDict<short,short> *GetAnimTable()
  38. {
  39. return &g_ModelLookup[g_ModelLookupIndex].animTable;
  40. }
  41. class CModelLookupContext
  42. {
  43. public:
  44. CModelLookupContext(int group, const studiohdr_t *pStudioHdr);
  45. ~CModelLookupContext();
  46. private:
  47. int m_lookupIndex;
  48. };
  49. CModelLookupContext::CModelLookupContext(int group, const studiohdr_t *pStudioHdr)
  50. {
  51. m_lookupIndex = -1;
  52. if ( group == 0 && pStudioHdr->numincludemodels )
  53. {
  54. m_lookupIndex = g_ModelLookup.AddToTail();
  55. g_ModelLookupIndex = g_ModelLookup.Count()-1;
  56. }
  57. }
  58. CModelLookupContext::~CModelLookupContext()
  59. {
  60. if ( m_lookupIndex >= 0 )
  61. {
  62. Assert(m_lookupIndex == (g_ModelLookup.Count()-1));
  63. g_ModelLookup.FastRemove(m_lookupIndex);
  64. g_ModelLookupIndex = g_ModelLookup.Count()-1;
  65. }
  66. }
  67. void virtualmodel_t::AppendModels( int group, const studiohdr_t *pStudioHdr )
  68. {
  69. AUTO_LOCK( m_Lock );
  70. // build a search table if necesary
  71. CModelLookupContext ctx(group, pStudioHdr);
  72. AppendSequences( group, pStudioHdr );
  73. AppendAnimations( group, pStudioHdr );
  74. AppendBonemap( group, pStudioHdr );
  75. AppendAttachments( group, pStudioHdr );
  76. AppendPoseParameters( group, pStudioHdr );
  77. AppendNodes( group, pStudioHdr );
  78. AppendIKLocks( group, pStudioHdr );
  79. struct HandleAndHeader_t
  80. {
  81. void *handle;
  82. const studiohdr_t *pHdr;
  83. };
  84. HandleAndHeader_t list[64];
  85. // determine quantity of valid include models in one pass only
  86. // temporarily cache results off, otherwise FindModel() causes ref counting problems
  87. int j;
  88. int nValidIncludes = 0;
  89. for (j = 0; j < pStudioHdr->numincludemodels; j++)
  90. {
  91. // find model (increases ref count)
  92. void *tmp = NULL;
  93. const studiohdr_t *pTmpHdr = pStudioHdr->FindModel( &tmp, pStudioHdr->pModelGroup( j )->pszName() );
  94. if ( pTmpHdr )
  95. {
  96. if ( nValidIncludes >= ARRAYSIZE( list ) )
  97. {
  98. // would cause stack overflow
  99. Assert( 0 );
  100. break;
  101. }
  102. list[nValidIncludes].handle = tmp;
  103. list[nValidIncludes].pHdr = pTmpHdr;
  104. nValidIncludes++;
  105. }
  106. }
  107. if ( nValidIncludes )
  108. {
  109. m_group.EnsureCapacity( m_group.Count() + nValidIncludes );
  110. for (j = 0; j < nValidIncludes; j++)
  111. {
  112. MEM_ALLOC_CREDIT();
  113. int group = m_group.AddToTail();
  114. m_group[group].cache = list[j].handle;
  115. AppendModels( group, list[j].pHdr );
  116. }
  117. }
  118. UpdateAutoplaySequences( pStudioHdr );
  119. }
  120. void virtualmodel_t::AppendSequences( int group, const studiohdr_t *pStudioHdr )
  121. {
  122. AUTO_LOCK( m_Lock );
  123. int numCheck = m_seq.Count();
  124. int j, k;
  125. MEM_ALLOC_CREDIT();
  126. CUtlVector< virtualsequence_t > seq;
  127. seq = m_seq;
  128. m_group[ group ].masterSeq.SetCount( pStudioHdr->numlocalseq );
  129. for (j = 0; j < pStudioHdr->numlocalseq; j++)
  130. {
  131. const mstudioseqdesc_t *seqdesc = pStudioHdr->pLocalSeqdesc( j );
  132. char *s1 = seqdesc->pszLabel();
  133. if ( HasLookupTable() )
  134. {
  135. k = numCheck;
  136. short index = GetSeqTable()->Find( s1 );
  137. if ( index != GetSeqTable()->InvalidIndex() )
  138. {
  139. k = GetSeqTable()->Element(index);
  140. }
  141. }
  142. else
  143. {
  144. for (k = 0; k < numCheck; k++)
  145. {
  146. const studiohdr_t *hdr = m_group[ seq[k].group ].GetStudioHdr();
  147. char *s2 = hdr->pLocalSeqdesc( seq[k].index )->pszLabel();
  148. if ( !stricmp( s1, s2 ) )
  149. {
  150. break;
  151. }
  152. }
  153. }
  154. // no duplication
  155. if (k == numCheck)
  156. {
  157. virtualsequence_t tmp;
  158. tmp.group = group;
  159. tmp.index = j;
  160. tmp.flags = seqdesc->flags;
  161. tmp.activity = seqdesc->activity;
  162. k = seq.AddToTail( tmp );
  163. }
  164. else if (m_group[ seq[k].group ].GetStudioHdr()->pLocalSeqdesc( seq[k].index )->flags & STUDIO_OVERRIDE)
  165. {
  166. // the one in memory is a forward declared sequence, override it
  167. virtualsequence_t tmp;
  168. tmp.group = group;
  169. tmp.index = j;
  170. tmp.flags = seqdesc->flags;
  171. tmp.activity = seqdesc->activity;
  172. seq[k] = tmp;
  173. }
  174. m_group[ group ].masterSeq[ j ] = k;
  175. }
  176. if ( HasLookupTable() )
  177. {
  178. for ( j = numCheck; j < seq.Count(); j++ )
  179. {
  180. const studiohdr_t *hdr = m_group[ seq[j].group ].GetStudioHdr();
  181. const char *s1 = hdr->pLocalSeqdesc( seq[j].index )->pszLabel();
  182. GetSeqTable()->Insert( s1, j );
  183. }
  184. }
  185. m_seq = seq;
  186. }
  187. void virtualmodel_t::UpdateAutoplaySequences( const studiohdr_t *pStudioHdr )
  188. {
  189. AUTO_LOCK( m_Lock );
  190. int autoplayCount = pStudioHdr->CountAutoplaySequences();
  191. m_autoplaySequences.SetCount( autoplayCount );
  192. pStudioHdr->CopyAutoplaySequences( m_autoplaySequences.Base(), autoplayCount );
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Purpose:
  196. //-----------------------------------------------------------------------------
  197. void virtualmodel_t::AppendAnimations( int group, const studiohdr_t *pStudioHdr )
  198. {
  199. AUTO_LOCK( m_Lock );
  200. int numCheck = m_anim.Count();
  201. CUtlVector< virtualgeneric_t > anim;
  202. anim = m_anim;
  203. MEM_ALLOC_CREDIT();
  204. int j, k;
  205. m_group[ group ].masterAnim.SetCount( pStudioHdr->numlocalanim );
  206. for (j = 0; j < pStudioHdr->numlocalanim; j++)
  207. {
  208. char *s1 = pStudioHdr->pLocalAnimdesc( j )->pszName();
  209. if ( HasLookupTable() )
  210. {
  211. k = numCheck;
  212. short index = GetAnimTable()->Find( s1 );
  213. if ( index != GetAnimTable()->InvalidIndex() )
  214. {
  215. k = GetAnimTable()->Element(index);
  216. }
  217. }
  218. else
  219. {
  220. for (k = 0; k < numCheck; k++)
  221. {
  222. char *s2 = m_group[ anim[k].group ].GetStudioHdr()->pLocalAnimdesc( anim[k].index )->pszName();
  223. if (stricmp( s1, s2 ) == 0)
  224. {
  225. break;
  226. }
  227. }
  228. }
  229. // no duplication
  230. if (k == numCheck)
  231. {
  232. virtualgeneric_t tmp;
  233. tmp.group = group;
  234. tmp.index = j;
  235. k = anim.AddToTail( tmp );
  236. }
  237. m_group[ group ].masterAnim[ j ] = k;
  238. }
  239. if ( HasLookupTable() )
  240. {
  241. for ( j = numCheck; j < anim.Count(); j++ )
  242. {
  243. const char *s1 = m_group[ anim[j].group ].GetStudioHdr()->pLocalAnimdesc( anim[j].index )->pszName();
  244. GetAnimTable()->Insert( s1, j );
  245. }
  246. }
  247. m_anim = anim;
  248. }
  249. //-----------------------------------------------------------------------------
  250. // Purpose:
  251. //-----------------------------------------------------------------------------
  252. void virtualmodel_t::AppendBonemap( int group, const studiohdr_t *pStudioHdr )
  253. {
  254. AUTO_LOCK( m_Lock );
  255. MEM_ALLOC_CREDIT();
  256. const studiohdr_t *pBaseStudioHdr = m_group[ 0 ].GetStudioHdr( );
  257. m_group[ group ].boneMap.SetCount( pBaseStudioHdr->numbones );
  258. m_group[ group ].masterBone.SetCount( pStudioHdr->numbones );
  259. int j, k;
  260. if (group == 0)
  261. {
  262. for (j = 0; j < pStudioHdr->numbones; j++)
  263. {
  264. m_group[ group ].boneMap[ j ] = j;
  265. m_group[ group ].masterBone[ j ] = j;
  266. }
  267. }
  268. else
  269. {
  270. for (j = 0; j < pBaseStudioHdr->numbones; j++)
  271. {
  272. m_group[ group ].boneMap[ j ] = -1;
  273. }
  274. for (j = 0; j < pStudioHdr->numbones; j++)
  275. {
  276. // NOTE: studiohdr has a bone table - using the table is ~5% faster than this for alyx.mdl on a P4/3.2GHz
  277. for (k = 0; k < pBaseStudioHdr->numbones; k++)
  278. {
  279. if (stricmp( pStudioHdr->pBone( j )->pszName(), pBaseStudioHdr->pBone( k )->pszName() ) == 0)
  280. {
  281. break;
  282. }
  283. }
  284. if (k < pBaseStudioHdr->numbones)
  285. {
  286. m_group[ group ].masterBone[ j ] = k;
  287. m_group[ group ].boneMap[ k ] = j;
  288. // FIXME: these runtime messages don't display in hlmv
  289. if ((pStudioHdr->pBone( j )->parent == -1) || (pBaseStudioHdr->pBone( k )->parent == -1))
  290. {
  291. if ((pStudioHdr->pBone( j )->parent != -1) || (pBaseStudioHdr->pBone( k )->parent != -1))
  292. {
  293. Warning( "%s/%s : missmatched parent bones on \"%s\"\n", pBaseStudioHdr->pszName(), pStudioHdr->pszName(), pStudioHdr->pBone( j )->pszName() );
  294. }
  295. }
  296. else if (m_group[ group ].masterBone[ pStudioHdr->pBone( j )->parent ] != m_group[ 0 ].masterBone[ pBaseStudioHdr->pBone( k )->parent ])
  297. {
  298. Warning( "%s/%s : missmatched parent bones on \"%s\"\n", pBaseStudioHdr->pszName(), pStudioHdr->pszName(), pStudioHdr->pBone( j )->pszName() );
  299. }
  300. }
  301. else
  302. {
  303. m_group[ group ].masterBone[ j ] = -1;
  304. }
  305. }
  306. }
  307. }
  308. //-----------------------------------------------------------------------------
  309. // Purpose:
  310. //-----------------------------------------------------------------------------
  311. void virtualmodel_t::AppendAttachments( int group, const studiohdr_t *pStudioHdr )
  312. {
  313. AUTO_LOCK( m_Lock );
  314. int numCheck = m_attachment.Count();
  315. CUtlVector< virtualgeneric_t > attachment;
  316. attachment = m_attachment;
  317. MEM_ALLOC_CREDIT();
  318. int j, k, n;
  319. m_group[ group ].masterAttachment.SetCount( pStudioHdr->numlocalattachments );
  320. for (j = 0; j < pStudioHdr->numlocalattachments; j++)
  321. {
  322. n = m_group[ group ].masterBone[ pStudioHdr->pLocalAttachment( j )->localbone ];
  323. // skip if the attachments bone doesn't exist in the root model
  324. if (n == -1)
  325. {
  326. continue;
  327. }
  328. char *s1 = pStudioHdr->pLocalAttachment( j )->pszName();
  329. for (k = 0; k < numCheck; k++)
  330. {
  331. char *s2 = m_group[ attachment[k].group ].GetStudioHdr()->pLocalAttachment( attachment[k].index )->pszName();
  332. if (stricmp( s1, s2 ) == 0)
  333. {
  334. break;
  335. }
  336. }
  337. // no duplication
  338. if (k == numCheck)
  339. {
  340. virtualgeneric_t tmp;
  341. tmp.group = group;
  342. tmp.index = j;
  343. k = attachment.AddToTail( tmp );
  344. // make sure bone flags are set so attachment calculates
  345. if ((m_group[ 0 ].GetStudioHdr()->pBone( n )->flags & BONE_USED_BY_ATTACHMENT) == 0)
  346. {
  347. while (n != -1)
  348. {
  349. m_group[ 0 ].GetStudioHdr()->pBone( n )->flags |= BONE_USED_BY_ATTACHMENT;
  350. if (m_group[ 0 ].GetStudioHdr()->pLinearBones())
  351. {
  352. *m_group[ 0 ].GetStudioHdr()->pLinearBones()->pflags(n) |= BONE_USED_BY_ATTACHMENT;
  353. }
  354. n = m_group[ 0 ].GetStudioHdr()->pBone( n )->parent;
  355. }
  356. continue;
  357. }
  358. }
  359. m_group[ group ].masterAttachment[ j ] = k;
  360. }
  361. m_attachment = attachment;
  362. }
  363. //-----------------------------------------------------------------------------
  364. // Purpose:
  365. //-----------------------------------------------------------------------------
  366. void virtualmodel_t::AppendPoseParameters( int group, const studiohdr_t *pStudioHdr )
  367. {
  368. AUTO_LOCK( m_Lock );
  369. int numCheck = m_pose.Count();
  370. CUtlVector< virtualgeneric_t > pose;
  371. pose = m_pose;
  372. MEM_ALLOC_CREDIT();
  373. int j, k;
  374. m_group[ group ].masterPose.SetCount( pStudioHdr->numlocalposeparameters );
  375. for (j = 0; j < pStudioHdr->numlocalposeparameters; j++)
  376. {
  377. char *s1 = pStudioHdr->pLocalPoseParameter( j )->pszName();
  378. for (k = 0; k < numCheck; k++)
  379. {
  380. char *s2 = m_group[ pose[k].group ].GetStudioHdr()->pLocalPoseParameter( pose[k].index )->pszName();
  381. if (stricmp( s1, s2 ) == 0)
  382. {
  383. break;
  384. }
  385. }
  386. if (k == numCheck)
  387. {
  388. // no duplication
  389. virtualgeneric_t tmp;
  390. tmp.group = group;
  391. tmp.index = j;
  392. k = pose.AddToTail( tmp );
  393. }
  394. else
  395. {
  396. // duplicate, reset start and end to fit full dynamic range
  397. mstudioposeparamdesc_t *pPose1 = pStudioHdr->pLocalPoseParameter( j );
  398. mstudioposeparamdesc_t *pPose2 = m_group[ pose[k].group ].GetStudioHdr()->pLocalPoseParameter( pose[k].index );
  399. float start = min( pPose2->end, min( pPose1->end, min( pPose2->start, pPose1->start ) ) );
  400. float end = max( pPose2->end, max( pPose1->end, max( pPose2->start, pPose1->start ) ) );
  401. pPose2->start = start;
  402. pPose2->end = end;
  403. }
  404. m_group[ group ].masterPose[ j ] = k;
  405. }
  406. m_pose = pose;
  407. }
  408. //-----------------------------------------------------------------------------
  409. // Purpose:
  410. //-----------------------------------------------------------------------------
  411. void virtualmodel_t::AppendNodes( int group, const studiohdr_t *pStudioHdr )
  412. {
  413. AUTO_LOCK( m_Lock );
  414. int numCheck = m_node.Count();
  415. CUtlVector< virtualgeneric_t > node;
  416. node = m_node;
  417. MEM_ALLOC_CREDIT();
  418. int j, k;
  419. m_group[ group ].masterNode.SetCount( pStudioHdr->numlocalnodes );
  420. for (j = 0; j < pStudioHdr->numlocalnodes; j++)
  421. {
  422. char *s1 = pStudioHdr->pszLocalNodeName( j );
  423. for (k = 0; k < numCheck; k++)
  424. {
  425. char *s2 = m_group[ node[k].group ].GetStudioHdr()->pszLocalNodeName( node[k].index );
  426. if (stricmp( s1, s2 ) == 0)
  427. {
  428. break;
  429. }
  430. }
  431. // no duplication
  432. if (k == numCheck)
  433. {
  434. virtualgeneric_t tmp;
  435. tmp.group = group;
  436. tmp.index = j;
  437. k = node.AddToTail( tmp );
  438. }
  439. m_group[ group ].masterNode[ j ] = k;
  440. }
  441. m_node = node;
  442. }
  443. //-----------------------------------------------------------------------------
  444. // Purpose:
  445. //-----------------------------------------------------------------------------
  446. void virtualmodel_t::AppendIKLocks( int group, const studiohdr_t *pStudioHdr )
  447. {
  448. AUTO_LOCK( m_Lock );
  449. int numCheck = m_iklock.Count();
  450. CUtlVector< virtualgeneric_t > iklock;
  451. iklock = m_iklock;
  452. int j, k;
  453. for (j = 0; j < pStudioHdr->numlocalikautoplaylocks; j++)
  454. {
  455. int chain1 = pStudioHdr->pLocalIKAutoplayLock( j )->chain;
  456. for (k = 0; k < numCheck; k++)
  457. {
  458. int chain2 = m_group[ iklock[k].group ].GetStudioHdr()->pLocalIKAutoplayLock( iklock[k].index )->chain;
  459. if (chain1 == chain2)
  460. {
  461. break;
  462. }
  463. }
  464. // no duplication
  465. if (k == numCheck)
  466. {
  467. MEM_ALLOC_CREDIT();
  468. virtualgeneric_t tmp;
  469. tmp.group = group;
  470. tmp.index = j;
  471. k = iklock.AddToTail( tmp );
  472. }
  473. }
  474. m_iklock = iklock;
  475. // copy knee directions for uninitialized knees
  476. if ( group != 0 )
  477. {
  478. studiohdr_t *pBaseHdr = (studiohdr_t *)m_group[ 0 ].GetStudioHdr();
  479. if ( pStudioHdr->numikchains == pBaseHdr->numikchains )
  480. {
  481. for (j = 0; j < pStudioHdr->numikchains; j++)
  482. {
  483. if ( pBaseHdr->pIKChain( j )->pLink(0)->kneeDir.LengthSqr() == 0.0f )
  484. {
  485. if ( pStudioHdr->pIKChain( j )->pLink(0)->kneeDir.LengthSqr() > 0.0f )
  486. {
  487. pBaseHdr->pIKChain( j )->pLink(0)->kneeDir = pStudioHdr->pIKChain( j )->pLink(0)->kneeDir;
  488. }
  489. }
  490. }
  491. }
  492. }
  493. }