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.

386 lines
8.1 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "filesystem.h"
  8. #include "viewangleanim.h"
  9. #include "keyvalues.h"
  10. #include "tier0/memdbgon.h"
  11. extern ConVar cl_pitchdown;
  12. extern ConVar cl_pitchup;
  13. // ConCommands useful for creating view animations
  14. CViewAngleAnimation *g_pTestAnimation = NULL;
  15. // create a view animation object to be used for creating an animation. parameter is flags
  16. CON_COMMAND( viewanim_create, "viewanim_create" )
  17. {
  18. if ( g_pTestAnimation )
  19. {
  20. delete g_pTestAnimation;
  21. g_pTestAnimation = NULL;
  22. }
  23. int flags = 0;
  24. if ( args.ArgC() > 1 )
  25. {
  26. flags = atoi( args[1] );
  27. }
  28. g_pTestAnimation = CREATE_ENTITY( CViewAngleAnimation, "viewangleanim" );
  29. if ( g_pTestAnimation )
  30. {
  31. g_pTestAnimation->Spawn();
  32. }
  33. }
  34. // run the test animation
  35. void TestViewAnim( void )
  36. {
  37. if ( g_pTestAnimation )
  38. {
  39. QAngle angles;
  40. engine->GetViewAngles( angles );
  41. g_pTestAnimation->RunAnimation( angles );
  42. }
  43. else
  44. Msg( "No view anim created\n" );
  45. }
  46. ConCommand viewanim_test( "viewanim_test", TestViewAnim, "test view animation" );
  47. // set view angles to (0,0,0)
  48. void ResetViewAngles( void )
  49. {
  50. // create a blank anim
  51. QAngle angles = vec3_angle;
  52. engine->SetViewAngles( angles );
  53. }
  54. ConCommand viewanim_reset( "viewanim_reset", ResetViewAngles, "reset view angles!", FCVAR_CHEAT );
  55. // add a key frame to the test animation. first parameter is the time taken to get to this keyframe
  56. CON_COMMAND_F( viewanim_addkeyframe, "", FCVAR_CHEAT )
  57. {
  58. if ( g_pTestAnimation )
  59. {
  60. QAngle vecTarget;
  61. engine->GetViewAngles( vecTarget );
  62. float flDelay = 0.2;
  63. if (args.ArgC() > 1)
  64. {
  65. flDelay = atof( args[1] );
  66. }
  67. int iFlags = 0;
  68. if (args.ArgC() > 1)
  69. {
  70. iFlags = atof( args[2] );
  71. }
  72. g_pTestAnimation->AddKeyFrame( new CViewAngleKeyFrame( vecTarget, flDelay, iFlags ) );
  73. }
  74. else
  75. Msg( "No view anim created, use viewanim_create" );
  76. }
  77. // save the current test anim, pass filename
  78. CON_COMMAND( viewanim_save, "Save current animation to file" )
  79. {
  80. if (args.ArgC() < 2)
  81. return;
  82. if ( g_pTestAnimation )
  83. {
  84. g_pTestAnimation->SaveAsAnimFile( args[1] );
  85. }
  86. else
  87. {
  88. Msg( "No view anim created\n" );
  89. }
  90. }
  91. // load a view animation file into the test anim
  92. CON_COMMAND( viewanim_load, "load animation from file" )
  93. {
  94. if (args.ArgC() < 2)
  95. return;
  96. if ( g_pTestAnimation )
  97. {
  98. g_pTestAnimation->LoadViewAnimFile( args[1] );
  99. }
  100. else
  101. Msg( "No view anim created\n" );
  102. }
  103. LINK_ENTITY_TO_CLASS_CLIENTONLY( viewangleanim, CViewAngleAnimation );
  104. CViewAngleAnimation::CViewAngleAnimation()
  105. {
  106. }
  107. CViewAngleAnimation::~CViewAngleAnimation()
  108. {
  109. DeleteKeyFrames();
  110. }
  111. void CViewAngleAnimation::Spawn( void )
  112. {
  113. m_iFlags = 0;
  114. QAngle angles;
  115. engine->GetViewAngles( angles );
  116. /*
  117. if ( m_iFlags & VIEWANIM_RELATIVE )
  118. {
  119. AddKeyFrame( new CViewAngleKeyFrame( vec3_angle, 0.0, 0 ) );
  120. // seed this so we can add keyframes and have them calc the delta properly
  121. m_vecBaseAngles = angles;
  122. }
  123. else
  124. {
  125. AddKeyFrame( new CViewAngleKeyFrame( angles, 0.0, 0 ) );
  126. }
  127. */
  128. m_bFinished = true; // don't run right away
  129. ClientEntityList().AddNonNetworkableEntity( this );
  130. SetNextClientThink( CLIENT_THINK_ALWAYS );
  131. }
  132. void CViewAngleAnimation::DeleteKeyFrames()
  133. {
  134. int i, c;
  135. c = m_KeyFrames.Count();
  136. for ( i = c - 1; i >= 0 ; --i )
  137. {
  138. delete m_KeyFrames[ i ];
  139. }
  140. m_KeyFrames.RemoveAll();
  141. }
  142. void CViewAngleAnimation::LoadViewAnimFile( const char *pKeyFrameFileName )
  143. {
  144. DeleteKeyFrames();
  145. // load keyvalues from this file and stuff them in as keyframes
  146. KeyValues *pData = new KeyValues( pKeyFrameFileName );
  147. if ( false == pData->LoadFromFile( filesystem, pKeyFrameFileName, "GAME" ) )
  148. {
  149. Warning( "CViewAngleAnimation::LoadViewAnimFile failed to load script %s\n", pKeyFrameFileName );
  150. pData->deleteThis();
  151. return;
  152. }
  153. QAngle angles;
  154. float flTime;
  155. int iFlags;
  156. KeyValues *pKey = pData->GetFirstSubKey();
  157. while ( pKey )
  158. {
  159. // angles
  160. const char *pszAngles = pKey->GetString( "angles", "0 0 0" );
  161. sscanf( pszAngles, "%f %f %f", &angles[0], &angles[1], &angles[2] );
  162. // time
  163. flTime = pKey->GetFloat( "time", 0.001 );
  164. // flags
  165. iFlags = pKey->GetInt( "flags", 0 );
  166. AddKeyFrame( new CViewAngleKeyFrame( angles, flTime, iFlags ) );
  167. pKey = pKey->GetNextKey();
  168. }
  169. pData->deleteThis();
  170. }
  171. void CViewAngleAnimation::SaveAsAnimFile( const char *pKeyFrameFileName )
  172. {
  173. // save all of our keyframes into the file
  174. KeyValues *pData = new KeyValues( pKeyFrameFileName );
  175. pData->SetInt( "flags", m_iFlags );
  176. KeyValues *pKey = new KeyValues( "keyframe" );
  177. int i;
  178. int c = m_KeyFrames.Count();
  179. char buf[64];
  180. for ( i=0;i<c;i++ )
  181. {
  182. pKey = pData->CreateNewKey();
  183. Q_snprintf( buf, sizeof(buf), "%f %f %f",
  184. m_KeyFrames[i]->m_vecAngles[0],
  185. m_KeyFrames[i]->m_vecAngles[1],
  186. m_KeyFrames[i]->m_vecAngles[2] );
  187. pKey->SetString( "angles", buf );
  188. pKey->SetFloat( "time", m_KeyFrames[i]->m_flTime );
  189. pKey->SetInt( "flags", m_KeyFrames[i]->m_iFlags );
  190. }
  191. pData->SaveToFile( filesystem, pKeyFrameFileName, NULL );
  192. pData->deleteThis();
  193. }
  194. void CViewAngleAnimation::AddKeyFrame( CViewAngleKeyFrame *pKeyFrame )
  195. {
  196. pKeyFrame->m_vecAngles -= m_vecBaseAngles;
  197. m_KeyFrames.AddToTail( pKeyFrame );
  198. }
  199. bool CViewAngleAnimation::IsFinished( void )
  200. {
  201. return m_bFinished;
  202. }
  203. void CViewAngleAnimation::RunAnimation( QAngle angles )
  204. {
  205. if ( m_KeyFrames.Count() == 0 )
  206. {
  207. Warning( "CViewAngleAnimation::RunAnimation called on an empty view animation\n" );
  208. return;
  209. }
  210. m_flAnimStartTime = gpGlobals->curtime;
  211. m_bFinished = false;
  212. m_vecBaseAngles = angles;
  213. m_iFlags = m_KeyFrames[0]->m_iFlags;
  214. if ( !( m_iFlags & VIEWANIM_RELATIVE ) )
  215. {
  216. m_KeyFrames[0]->m_vecAngles = angles;
  217. }
  218. }
  219. void CViewAngleAnimation::ClientThink()
  220. {
  221. if ( IsFinished() )
  222. return;
  223. float flCurrentTime = gpGlobals->curtime - m_flAnimStartTime;
  224. if ( flCurrentTime < 0 )
  225. flCurrentTime = 0.001;
  226. // find two nearest points
  227. int i, c;
  228. c = m_KeyFrames.Count();
  229. float flTime = 0;
  230. for ( i=0;i<c;i++ )
  231. {
  232. if ( flTime + m_KeyFrames[i]->m_flTime > flCurrentTime )
  233. {
  234. break;
  235. }
  236. flTime += m_KeyFrames[i]->m_flTime;
  237. }
  238. Assert( i > 0 );
  239. if ( i >= c )
  240. {
  241. if ( i > 0 )
  242. {
  243. // animation complete, set to end point
  244. SetAngles( m_KeyFrames[i-1]->m_vecAngles );
  245. }
  246. if ( m_pAnimCompleteCallback )
  247. {
  248. m_pAnimCompleteCallback();
  249. }
  250. m_bFinished = true;
  251. return;
  252. }
  253. if ( m_KeyFrames[i]->m_iFlags != m_iFlags )
  254. {
  255. if ( ( m_KeyFrames[i]->m_iFlags & VIEWANIM_RELATIVE ) && !( m_iFlags & VIEWANIM_RELATIVE ) )
  256. {
  257. // new relative position is current angles
  258. engine->GetViewAngles( m_vecBaseAngles );
  259. }
  260. // copy the rest over
  261. m_iFlags = m_KeyFrames[i]->m_iFlags;
  262. }
  263. // previous frame is m_KeyFrames[i-1];
  264. // next frame is m_KeyFrames[i];
  265. float flFraction = ( flCurrentTime - flTime ) / ( m_KeyFrames[i]->m_flTime );
  266. Vector v0, v1, v2, v3;
  267. if ( i-2 <= 0 )
  268. {
  269. QAngleToVector( m_KeyFrames[i-1]->m_vecAngles, v0 );
  270. }
  271. else
  272. {
  273. QAngleToVector( m_KeyFrames[i-2]->m_vecAngles, v0 );
  274. }
  275. QAngleToVector( m_KeyFrames[i-1]->m_vecAngles, v1 );
  276. QAngleToVector( m_KeyFrames[i]->m_vecAngles, v2 );
  277. if ( i+1 >= c )
  278. {
  279. QAngleToVector( m_KeyFrames[i]->m_vecAngles, v3 );
  280. }
  281. else
  282. {
  283. QAngleToVector( m_KeyFrames[i+1]->m_vecAngles, v3 );
  284. }
  285. Vector out;
  286. Catmull_Rom_Spline( v0, v1, v2, v3, flFraction, out );
  287. QAngle vecCalculatedAngles;
  288. QAngleToVector( out, vecCalculatedAngles );
  289. SetAngles( vecCalculatedAngles );
  290. }
  291. void CViewAngleAnimation::SetAngles( QAngle vecCalculatedAngles )
  292. {
  293. if ( m_iFlags & VIEWANIM_RELATIVE )
  294. vecCalculatedAngles += m_vecBaseAngles;
  295. QAngle vecViewAngle;
  296. engine->GetViewAngles( vecViewAngle );
  297. if ( !(FBitSet( m_iFlags, VIEWANIM_IGNORE_X ) ) )
  298. vecViewAngle[PITCH] = vecCalculatedAngles[PITCH];
  299. if ( !(FBitSet( m_iFlags, VIEWANIM_IGNORE_Y ) ) )
  300. vecViewAngle[YAW] = vecCalculatedAngles[YAW];
  301. if ( !(FBitSet( m_iFlags, VIEWANIM_IGNORE_Z ) ) )
  302. vecViewAngle[ROLL] = vecCalculatedAngles[ROLL];
  303. // clamp pitch
  304. vecViewAngle[PITCH] = clamp( vecViewAngle[PITCH], -cl_pitchup.GetFloat(), cl_pitchdown.GetFloat() );
  305. engine->SetViewAngles( vecViewAngle );
  306. }