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.

567 lines
14 KiB

  1. //========= Copyright � 1996-2005, 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_( CThreadTerminalMutex<CThreadFastMutex>, 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_( CThreadTerminalMutex<CThreadFastMutex>, 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_( CThreadTerminalMutex<CThreadFastMutex>, 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_( CThreadTerminalMutex<CThreadFastMutex>, 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_( CThreadTerminalMutex<CThreadFastMutex>, 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. // merge the bone use flags and pass up the chain
  301. int flags = (pStudioHdr->pBone( j )->flags | pBaseStudioHdr->pBone( k )->flags) & BONE_USED_MASK;
  302. int n = k;
  303. while (n != -1 && flags != pBaseStudioHdr->pBone( n )->flags)
  304. {
  305. ((mstudiobone_t *)pBaseStudioHdr->pBone( n ))->flags |= flags;
  306. n = pBaseStudioHdr->pBone( n )->parent;
  307. }
  308. }
  309. else
  310. {
  311. m_group[ group ].masterBone[ j ] = -1;
  312. }
  313. }
  314. }
  315. }
  316. //-----------------------------------------------------------------------------
  317. // Purpose:
  318. //-----------------------------------------------------------------------------
  319. void virtualmodel_t::AppendAttachments( int group, const studiohdr_t *pStudioHdr )
  320. {
  321. AUTO_LOCK_( CThreadTerminalMutex<CThreadFastMutex>, m_Lock );
  322. int numCheck = m_attachment.Count();
  323. CUtlVector< virtualgeneric_t > attachment;
  324. attachment = m_attachment;
  325. MEM_ALLOC_CREDIT();
  326. int j, k, n;
  327. m_group[ group ].masterAttachment.SetCount( pStudioHdr->numlocalattachments );
  328. for (j = 0; j < pStudioHdr->numlocalattachments; j++)
  329. {
  330. n = m_group[ group ].masterBone[ pStudioHdr->pLocalAttachment( j )->localbone ];
  331. // skip if the attachments bone doesn't exist in the root model
  332. if (n == -1)
  333. {
  334. continue;
  335. }
  336. char *s1 = pStudioHdr->pLocalAttachment( j )->pszName();
  337. for (k = 0; k < numCheck; k++)
  338. {
  339. char *s2 = m_group[ attachment[k].group ].GetStudioHdr()->pLocalAttachment( attachment[k].index )->pszName();
  340. if (stricmp( s1, s2 ) == 0)
  341. {
  342. break;
  343. }
  344. }
  345. // no duplication
  346. if (k == numCheck)
  347. {
  348. virtualgeneric_t tmp;
  349. tmp.group = group;
  350. tmp.index = j;
  351. k = attachment.AddToTail( tmp );
  352. }
  353. m_group[ group ].masterAttachment[ j ] = k;
  354. }
  355. m_attachment = attachment;
  356. }
  357. //-----------------------------------------------------------------------------
  358. // Purpose:
  359. //-----------------------------------------------------------------------------
  360. void virtualmodel_t::AppendPoseParameters( int group, const studiohdr_t *pStudioHdr )
  361. {
  362. AUTO_LOCK_( CThreadTerminalMutex<CThreadFastMutex>, m_Lock );
  363. int numCheck = m_pose.Count();
  364. CUtlVector< virtualgeneric_t > pose;
  365. pose = m_pose;
  366. MEM_ALLOC_CREDIT();
  367. int j, k;
  368. m_group[ group ].masterPose.SetCount( pStudioHdr->numlocalposeparameters );
  369. for (j = 0; j < pStudioHdr->numlocalposeparameters; j++)
  370. {
  371. char *s1 = pStudioHdr->pLocalPoseParameter( j )->pszName();
  372. for (k = 0; k < numCheck; k++)
  373. {
  374. char *s2 = m_group[ pose[k].group ].GetStudioHdr()->pLocalPoseParameter( pose[k].index )->pszName();
  375. if (stricmp( s1, s2 ) == 0)
  376. {
  377. break;
  378. }
  379. }
  380. if (k == numCheck)
  381. {
  382. // no duplication
  383. virtualgeneric_t tmp;
  384. tmp.group = group;
  385. tmp.index = j;
  386. k = pose.AddToTail( tmp );
  387. }
  388. else
  389. {
  390. // duplicate, reset start and end to fit full dynamic range
  391. mstudioposeparamdesc_t *pPose1 = pStudioHdr->pLocalPoseParameter( j );
  392. mstudioposeparamdesc_t *pPose2 = m_group[ pose[k].group ].GetStudioHdr()->pLocalPoseParameter( pose[k].index );
  393. float start = MIN( pPose2->end, MIN( pPose1->end, MIN( pPose2->start, pPose1->start ) ) );
  394. float end = MAX( pPose2->end, MAX( pPose1->end, MAX( pPose2->start, pPose1->start ) ) );
  395. pPose2->start = start;
  396. pPose2->end = end;
  397. }
  398. m_group[ group ].masterPose[ j ] = k;
  399. }
  400. m_pose = pose;
  401. }
  402. //-----------------------------------------------------------------------------
  403. // Purpose:
  404. //-----------------------------------------------------------------------------
  405. void virtualmodel_t::AppendNodes( int group, const studiohdr_t *pStudioHdr )
  406. {
  407. AUTO_LOCK_( CThreadTerminalMutex<CThreadFastMutex>, m_Lock );
  408. int numCheck = m_node.Count();
  409. CUtlVector< virtualgeneric_t > node;
  410. node = m_node;
  411. MEM_ALLOC_CREDIT();
  412. int j, k;
  413. m_group[ group ].masterNode.SetCount( pStudioHdr->numlocalnodes );
  414. for (j = 0; j < pStudioHdr->numlocalnodes; j++)
  415. {
  416. char *s1 = pStudioHdr->pszLocalNodeName( j );
  417. for (k = 0; k < numCheck; k++)
  418. {
  419. char *s2 = m_group[ node[k].group ].GetStudioHdr()->pszLocalNodeName( node[k].index );
  420. if (stricmp( s1, s2 ) == 0)
  421. {
  422. break;
  423. }
  424. }
  425. // no duplication
  426. if (k == numCheck)
  427. {
  428. virtualgeneric_t tmp;
  429. tmp.group = group;
  430. tmp.index = j;
  431. k = node.AddToTail( tmp );
  432. }
  433. m_group[ group ].masterNode[ j ] = k;
  434. }
  435. m_node = node;
  436. }
  437. //-----------------------------------------------------------------------------
  438. // Purpose:
  439. //-----------------------------------------------------------------------------
  440. void virtualmodel_t::AppendIKLocks( int group, const studiohdr_t *pStudioHdr )
  441. {
  442. AUTO_LOCK_( CThreadTerminalMutex<CThreadFastMutex>, m_Lock );
  443. int numCheck = m_iklock.Count();
  444. CUtlVector< virtualgeneric_t > iklock;
  445. iklock = m_iklock;
  446. int j, k;
  447. for (j = 0; j < pStudioHdr->numlocalikautoplaylocks; j++)
  448. {
  449. int chain1 = pStudioHdr->pLocalIKAutoplayLock( j )->chain;
  450. for (k = 0; k < numCheck; k++)
  451. {
  452. int chain2 = m_group[ iklock[k].group ].GetStudioHdr()->pLocalIKAutoplayLock( iklock[k].index )->chain;
  453. if (chain1 == chain2)
  454. {
  455. break;
  456. }
  457. }
  458. // no duplication
  459. if (k == numCheck)
  460. {
  461. MEM_ALLOC_CREDIT();
  462. virtualgeneric_t tmp;
  463. tmp.group = group;
  464. tmp.index = j;
  465. k = iklock.AddToTail( tmp );
  466. }
  467. }
  468. m_iklock = iklock;
  469. }