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.

345 lines
9.2 KiB

  1. //===== Copyright � 2005-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Helper methods + classes for file access
  4. //
  5. //===========================================================================//
  6. #include "tier3/choreoutils.h"
  7. #include "tier3/tier3.h"
  8. #include "SoundEmitterSystem/isoundemittersystembase.h"
  9. #include "studio.h"
  10. #include "../game/shared/choreoscene.h"
  11. #include "../game/shared/choreoevent.h"
  12. #include "tier1/keyvalues.h"
  13. #include "bone_setup.h"
  14. #include "soundchars.h"
  15. // NOTE: This has to be the last file included!
  16. #include "tier0/memdbgon.h"
  17. //-----------------------------------------------------------------------------
  18. // Find sequence by name
  19. //-----------------------------------------------------------------------------
  20. static int LookupSequence( CStudioHdr *pStudioHdr, const char *pSequenceName )
  21. {
  22. return pStudioHdr->LookupSequence( pSequenceName );
  23. }
  24. //-----------------------------------------------------------------------------
  25. // Returns sequence flags
  26. //-----------------------------------------------------------------------------
  27. static int GetSequenceFlags( CStudioHdr *pStudioHdr, int nSequence )
  28. {
  29. if ( !pStudioHdr || nSequence < 0 || nSequence >= pStudioHdr->GetNumSeq() )
  30. return 0;
  31. mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( nSequence );
  32. return seqdesc.flags;
  33. }
  34. //-----------------------------------------------------------------------------
  35. // Does a sequence loop?
  36. //-----------------------------------------------------------------------------
  37. static bool DoesSequenceLoop( CStudioHdr *pStudioHdr, int nSequence )
  38. {
  39. int nFlags = GetSequenceFlags( pStudioHdr, nSequence );
  40. bool bLooping = ( nFlags & STUDIO_LOOPING ) ? true : false;
  41. return bLooping;
  42. }
  43. //-----------------------------------------------------------------------------
  44. // Purpose:
  45. //-----------------------------------------------------------------------------
  46. bool AutoAddGestureKeys( CChoreoEvent *e, CStudioHdr *pStudioHdr, float *pPoseParameters, bool bCheckOnly )
  47. {
  48. int iSequence = LookupSequence( pStudioHdr, e->GetParameters() );
  49. if ( iSequence < 0 )
  50. return false;
  51. KeyValues *pSeqKeyValues = new KeyValues( "" );
  52. if ( !pSeqKeyValues->LoadFromBuffer( pStudioHdr->name(), Studio_GetKeyValueText( pStudioHdr, iSequence ) ) )
  53. {
  54. pSeqKeyValues->deleteThis();
  55. return false;
  56. }
  57. // Do we have a build point section?
  58. KeyValues *pKVAllFaceposer = pSeqKeyValues->FindKey("faceposer");
  59. if ( !pKVAllFaceposer )
  60. {
  61. pSeqKeyValues->deleteThis();
  62. return false;
  63. }
  64. int nMaxFrame = Studio_MaxFrame( pStudioHdr, iSequence, pPoseParameters ) - 1;
  65. // Start grabbing the sounds and slotting them in
  66. KeyValues *pkvFaceposer;
  67. char szStartLoop[CEventAbsoluteTag::MAX_EVENTTAG_LENGTH] = { "loop" };
  68. char szEndLoop[CEventAbsoluteTag::MAX_EVENTTAG_LENGTH] = { "end" };
  69. char szEntry[CEventAbsoluteTag::MAX_EVENTTAG_LENGTH] = { "apex" };
  70. char szExit[CEventAbsoluteTag::MAX_EVENTTAG_LENGTH] = { "end" };
  71. for ( pkvFaceposer = pKVAllFaceposer->GetFirstSubKey(); pkvFaceposer; pkvFaceposer = pkvFaceposer->GetNextKey() )
  72. {
  73. if ( !Q_stricmp( pkvFaceposer->GetName(), "startloop" ) )
  74. {
  75. Q_strncpy( szStartLoop, pkvFaceposer->GetString(), sizeof(szStartLoop) );
  76. continue;
  77. }
  78. if ( !Q_stricmp( pkvFaceposer->GetName(), "endloop" ) )
  79. {
  80. Q_strncpy( szEndLoop, pkvFaceposer->GetString(), sizeof(szEndLoop) );
  81. continue;
  82. }
  83. if ( !Q_stricmp( pkvFaceposer->GetName(), "entrytag" ) )
  84. {
  85. Q_strncpy( szEntry, pkvFaceposer->GetString(), sizeof(szEntry) );
  86. continue;
  87. }
  88. if ( !Q_stricmp( pkvFaceposer->GetName(), "exittag" ) )
  89. {
  90. Q_strncpy( szExit, pkvFaceposer->GetString(), sizeof(szExit) );
  91. continue;
  92. }
  93. if ( !Q_stricmp( pkvFaceposer->GetName(), "tags" ) )
  94. {
  95. if ( nMaxFrame <= 0 )
  96. continue;
  97. KeyValues *pkvTags;
  98. for ( pkvTags = pkvFaceposer->GetFirstSubKey(); pkvTags; pkvTags = pkvTags->GetNextKey() )
  99. {
  100. float flPercentage = (float)pkvTags->GetInt() / nMaxFrame;
  101. CEventAbsoluteTag *ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, pkvTags->GetName() );
  102. if (ptag)
  103. {
  104. // reposition tag
  105. ptag->SetPercentage( flPercentage );
  106. }
  107. else
  108. {
  109. e->AddAbsoluteTag( CChoreoEvent::ORIGINAL, pkvTags->GetName(), flPercentage );
  110. e->AddAbsoluteTag( CChoreoEvent::PLAYBACK, pkvTags->GetName(), flPercentage );
  111. }
  112. // lock the original tags so they can't be edited
  113. ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, pkvTags->GetName() );
  114. Assert( ptag );
  115. ptag->SetLocked( true );
  116. }
  117. e->VerifyTagOrder();
  118. e->PreventTagOverlap();
  119. continue;
  120. }
  121. }
  122. // FIXME: lookup linear tags in sequence data
  123. {
  124. CEventAbsoluteTag *ptag;
  125. ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, szStartLoop );
  126. if (ptag)
  127. {
  128. ptag->SetLinear( true );
  129. }
  130. ptag = e->FindAbsoluteTag( CChoreoEvent::PLAYBACK, szStartLoop );
  131. if (ptag)
  132. {
  133. ptag->SetLinear( true );
  134. }
  135. ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, szEndLoop );
  136. if (ptag)
  137. {
  138. ptag->SetLinear( true );
  139. }
  140. ptag = e->FindAbsoluteTag( CChoreoEvent::PLAYBACK, szEndLoop );
  141. if (ptag)
  142. {
  143. ptag->SetLinear( true );
  144. }
  145. ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, szEntry );
  146. if (ptag)
  147. {
  148. ptag->SetEntry( true );
  149. }
  150. ptag = e->FindAbsoluteTag( CChoreoEvent::PLAYBACK, szEntry );
  151. if (ptag)
  152. {
  153. ptag->SetEntry( true );
  154. }
  155. ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, szExit );
  156. if (ptag)
  157. {
  158. ptag->SetExit( true );
  159. }
  160. ptag = e->FindAbsoluteTag( CChoreoEvent::PLAYBACK, szExit );
  161. if (ptag)
  162. {
  163. ptag->SetExit( true );
  164. }
  165. }
  166. pSeqKeyValues->deleteThis();
  167. return true;
  168. }
  169. //-----------------------------------------------------------------------------
  170. // Purpose:
  171. //-----------------------------------------------------------------------------
  172. bool UpdateGestureLength( CChoreoEvent *e, CStudioHdr *pStudioHdr, float *pPoseParameters, bool bCheckOnly )
  173. {
  174. Assert( e );
  175. if ( !e )
  176. return false;
  177. if ( e->GetType() != CChoreoEvent::GESTURE )
  178. return false;
  179. int iSequence = LookupSequence( pStudioHdr, e->GetParameters() );
  180. if ( iSequence < 0 )
  181. return false;
  182. bool bChanged = false;
  183. float flSeqDuration = Studio_Duration( pStudioHdr, iSequence, pPoseParameters );
  184. float flCurDuration;
  185. e->GetGestureSequenceDuration( flCurDuration );
  186. if ( flSeqDuration != 0.0f && flSeqDuration != flCurDuration )
  187. {
  188. bChanged = true;
  189. if ( !bCheckOnly )
  190. {
  191. e->SetGestureSequenceDuration( flSeqDuration );
  192. }
  193. }
  194. return bChanged;
  195. }
  196. //-----------------------------------------------------------------------------
  197. // Purpose:
  198. //-----------------------------------------------------------------------------
  199. bool UpdateSequenceLength( CChoreoEvent *e, CStudioHdr *pStudioHdr, float *pPoseParameters, bool bCheckOnly, bool bVerbose )
  200. {
  201. Assert( e );
  202. if ( !e )
  203. return false;
  204. if ( e->GetType() != CChoreoEvent::SEQUENCE )
  205. {
  206. if ( bVerbose )
  207. {
  208. ConMsg( "UpdateSequenceLength: called on non-SEQUENCE event %s\n", e->GetName() );
  209. }
  210. return false;
  211. }
  212. int iSequence = LookupSequence( pStudioHdr, e->GetParameters() );
  213. if ( iSequence < 0 )
  214. return false;
  215. bool bChanged = false;
  216. bool bLooping = DoesSequenceLoop( pStudioHdr, iSequence );
  217. float flSeqDuration = Studio_Duration( pStudioHdr, iSequence, pPoseParameters );
  218. if ( bLooping )
  219. {
  220. if ( e->IsFixedLength() )
  221. {
  222. if ( bCheckOnly )
  223. return true;
  224. if ( bVerbose )
  225. {
  226. ConMsg( "UpdateSequenceLength: %s is looping, removing fixed length flag\n", e->GetName() );
  227. }
  228. bChanged = true;
  229. }
  230. e->SetFixedLength( false );
  231. if ( !e->HasEndTime() )
  232. {
  233. if ( bCheckOnly )
  234. return true;
  235. if ( bVerbose )
  236. {
  237. ConMsg( "CheckSequenceLength: %s is looping, setting default end time\n", e->GetName() );
  238. }
  239. e->SetEndTime( e->GetStartTime() + flSeqDuration );
  240. bChanged = true;
  241. }
  242. return bChanged;
  243. }
  244. if ( !e->IsFixedLength() )
  245. {
  246. if ( bCheckOnly )
  247. return true;
  248. if ( bVerbose )
  249. {
  250. ConMsg( "CheckSequenceLength: %s is fixed length, removing looping flag\n", e->GetName() );
  251. }
  252. bChanged = true;
  253. }
  254. e->SetFixedLength( true );
  255. if ( e->HasEndTime() )
  256. {
  257. float dt = e->GetDuration();
  258. if ( fabs( dt - flSeqDuration ) > 0.01f )
  259. {
  260. if ( bCheckOnly )
  261. return true;
  262. if ( bVerbose )
  263. {
  264. ConMsg( "CheckSequenceLength: %s has wrong duration, changing length from %f to %f seconds\n",
  265. e->GetName(), dt, flSeqDuration );
  266. }
  267. bChanged = true;
  268. }
  269. }
  270. else
  271. {
  272. if ( bCheckOnly )
  273. return true;
  274. if ( bVerbose )
  275. {
  276. ConMsg( "CheckSequenceLength: %s has wrong duration, changing length to %f seconds\n",
  277. e->GetName(), flSeqDuration );
  278. }
  279. bChanged = true;
  280. }
  281. if ( !bCheckOnly )
  282. {
  283. e->SetEndTime( e->GetStartTime() + flSeqDuration );
  284. }
  285. return bChanged;
  286. }
  287. //-----------------------------------------------------------------------------
  288. // Finds sound files associated with events
  289. //-----------------------------------------------------------------------------
  290. const char *GetSoundForEvent( CChoreoEvent *pEvent, CStudioHdr *pStudioHdr )
  291. {
  292. const char *pSoundName = pEvent->GetParameters();
  293. if ( Q_stristr( pSoundName, ".wav" ) )
  294. return PSkipSoundChars( pSoundName );
  295. const char *pFileName = g_pSoundEmitterSystem->GetWavFileForSound( pSoundName, ( pStudioHdr && pStudioHdr->IsValid() ) ? pStudioHdr->name() : NULL );
  296. return PSkipSoundChars( pFileName );
  297. }