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.

1845 lines
55 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #pragma warning( disable : 4244 ) // conversion from 'double' to 'float', possible loss of data
  7. #include <vgui/IScheme.h>
  8. #include <vgui/ISurface.h>
  9. #include <vgui/ISystem.h>
  10. #include <vgui/IVGui.h>
  11. #include <KeyValues.h>
  12. #include <vgui_controls/AnimationController.h>
  13. #include "filesystem.h"
  14. #include "filesystem_helpers.h"
  15. #include <stdio.h>
  16. #include <math.h>
  17. #include "mempool.h"
  18. #include "utldict.h"
  19. #include "mathlib/mathlib.h"
  20. #include "characterset.h"
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include <tier0/dbg.h>
  23. // for SRC
  24. #include <vstdlib/random.h>
  25. #include <tier0/memdbgon.h>
  26. using namespace vgui;
  27. static CUtlSymbolTable g_ScriptSymbols(0, 128, true);
  28. // singleton accessor for animation controller for use by the vgui controls
  29. namespace vgui
  30. {
  31. AnimationController *GetAnimationController()
  32. {
  33. static AnimationController *s_pAnimationController = new AnimationController(NULL);
  34. return s_pAnimationController;
  35. }
  36. }
  37. //-----------------------------------------------------------------------------
  38. // Purpose: Constructor
  39. //-----------------------------------------------------------------------------
  40. AnimationController::AnimationController(Panel *parent) : BaseClass(parent, NULL)
  41. {
  42. m_hSizePanel = 0;
  43. m_nScreenBounds[ 0 ] = m_nScreenBounds[ 1 ] = -1;
  44. m_nScreenBounds[ 2 ] = m_nScreenBounds[ 3 ] = -1;
  45. m_bAutoReloadScript = false;
  46. // always invisible
  47. SetVisible(false);
  48. SetProportional(true);
  49. // get the names of common types
  50. m_sPosition = g_ScriptSymbols.AddString("position");
  51. m_sSize = g_ScriptSymbols.AddString("size");
  52. m_sFgColor = g_ScriptSymbols.AddString("fgcolor");
  53. m_sBgColor = g_ScriptSymbols.AddString("bgcolor");
  54. m_sXPos = g_ScriptSymbols.AddString("xpos");
  55. m_sYPos = g_ScriptSymbols.AddString("ypos");
  56. m_sWide = g_ScriptSymbols.AddString("wide");
  57. m_sTall = g_ScriptSymbols.AddString("tall");
  58. m_sModelPos = g_ScriptSymbols.AddString( "model_pos" );
  59. m_flCurrentTime = 0.0f;
  60. }
  61. //-----------------------------------------------------------------------------
  62. // Purpose: Destructor
  63. //-----------------------------------------------------------------------------
  64. AnimationController::~AnimationController()
  65. {
  66. }
  67. //-----------------------------------------------------------------------------
  68. // Purpose: Sets which script file to use
  69. //-----------------------------------------------------------------------------
  70. bool AnimationController::SetScriptFile( VPANEL sizingPanel, const char *fileName, bool wipeAll /*=false*/ )
  71. {
  72. m_hSizePanel = sizingPanel;
  73. if ( wipeAll )
  74. {
  75. // clear the current script
  76. m_Sequences.RemoveAll();
  77. m_ScriptFileNames.RemoveAll();
  78. CancelAllAnimations();
  79. }
  80. // Store off this filename for reloading later on (if we don't have it already)
  81. UtlSymId_t sFilename = g_ScriptSymbols.AddString( fileName );
  82. if ( m_ScriptFileNames.Find( sFilename ) == m_ScriptFileNames.InvalidIndex() )
  83. {
  84. m_ScriptFileNames.AddToTail( sFilename );
  85. }
  86. UpdateScreenSize();
  87. // load the new script file
  88. return LoadScriptFile( fileName );
  89. }
  90. //-----------------------------------------------------------------------------
  91. // Purpose: reloads the currently set script file
  92. //-----------------------------------------------------------------------------
  93. void AnimationController::ReloadScriptFile()
  94. {
  95. // Clear all current sequences
  96. m_Sequences.RemoveAll();
  97. UpdateScreenSize();
  98. // Reload each file we've loaded
  99. for ( int i = 0; i < m_ScriptFileNames.Count(); i++ )
  100. {
  101. const char *lpszFilename = g_ScriptSymbols.String( m_ScriptFileNames[i] );
  102. if ( strlen( lpszFilename ) > 0)
  103. {
  104. if ( LoadScriptFile( lpszFilename ) == false )
  105. {
  106. Assert( 0 );
  107. }
  108. }
  109. }
  110. }
  111. //-----------------------------------------------------------------------------
  112. // Purpose: loads a script file from disk
  113. //-----------------------------------------------------------------------------
  114. bool AnimationController::LoadScriptFile(const char *fileName)
  115. {
  116. FileHandle_t f = g_pFullFileSystem->Open(fileName, "rt");
  117. if (!f)
  118. {
  119. Warning("Couldn't find script file %s\n", fileName);
  120. return false;
  121. }
  122. // read the whole thing into memory
  123. int size = g_pFullFileSystem->Size(f);
  124. // read into temporary memory block
  125. int nBufSize = size+1;
  126. if ( IsXbox() )
  127. {
  128. nBufSize = AlignValue( nBufSize, 512 );
  129. }
  130. char *pMem = (char *)malloc(nBufSize);
  131. int bytesRead = g_pFullFileSystem->ReadEx(pMem, nBufSize, size, f);
  132. Assert(bytesRead <= size);
  133. pMem[bytesRead] = 0;
  134. g_pFullFileSystem->Close(f);
  135. // parse
  136. bool success = ParseScriptFile(pMem, bytesRead);
  137. free(pMem);
  138. return success;
  139. }
  140. AnimationController::RelativeAlignmentLookup AnimationController::g_AlignmentLookup[] =
  141. {
  142. { AnimationController::a_northwest , "northwest" },
  143. { AnimationController::a_north , "north" },
  144. { AnimationController::a_northeast , "northeast" },
  145. { AnimationController::a_west , "west" },
  146. { AnimationController::a_center , "center" },
  147. { AnimationController::a_east , "east" },
  148. { AnimationController::a_southwest , "southwest" },
  149. { AnimationController::a_south , "south" },
  150. { AnimationController::a_southeast , "southeast" },
  151. { AnimationController::a_northwest , "nw" },
  152. { AnimationController::a_north , "n" },
  153. { AnimationController::a_northeast , "ne" },
  154. { AnimationController::a_west , "w" },
  155. { AnimationController::a_center , "c" },
  156. { AnimationController::a_east , "e" },
  157. { AnimationController::a_southwest , "sw" },
  158. { AnimationController::a_south , "s" },
  159. { AnimationController::a_southeast , "se" },
  160. };
  161. //-----------------------------------------------------------------------------
  162. // Purpose:
  163. //-----------------------------------------------------------------------------
  164. AnimationController::RelativeAlignment AnimationController::LookupAlignment( char const *token )
  165. {
  166. int c = ARRAYSIZE( g_AlignmentLookup );
  167. for ( int i = 0; i < c; i++ )
  168. {
  169. if ( !Q_stricmp( token, g_AlignmentLookup[ i ].name ) )
  170. {
  171. return g_AlignmentLookup[ i ].align;
  172. }
  173. }
  174. return AnimationController::a_northwest;
  175. }
  176. //-----------------------------------------------------------------------------
  177. // Purpose: Parse position including right edge and center adjustment out of a
  178. // token. This is relative to the screen
  179. //-----------------------------------------------------------------------------
  180. void AnimationController::SetupPosition( AnimCmdAnimate_t& cmd, float *output, char const *psz, int screendimension )
  181. {
  182. bool r = false, c = false;
  183. int pos;
  184. if ( psz[0] == '(' )
  185. {
  186. psz++;
  187. if ( Q_strstr( psz, ")" ) )
  188. {
  189. char sz[ 256 ];
  190. Q_strncpy( sz, psz, sizeof( sz ) );
  191. char *colon = Q_strstr( sz, ":" );
  192. if ( colon )
  193. {
  194. *colon = 0;
  195. RelativeAlignment ra = LookupAlignment( sz );
  196. colon++;
  197. char *panelName = colon;
  198. char *panelEnd = Q_strstr( panelName, ")" );
  199. if ( panelEnd )
  200. {
  201. *panelEnd = 0;
  202. if ( Q_strlen( panelName ) > 0 )
  203. {
  204. //
  205. cmd.align.relativePosition = true;
  206. cmd.align.alignPanel = g_ScriptSymbols.AddString(panelName);
  207. cmd.align.alignment = ra;
  208. }
  209. }
  210. }
  211. psz = Q_strstr( psz, ")" ) + 1;
  212. }
  213. }
  214. else if (psz[0] == 'r' || psz[0] == 'R')
  215. {
  216. r = true;
  217. psz++;
  218. }
  219. else if (psz[0] == 'c' || psz[0] == 'C')
  220. {
  221. c = true;
  222. psz++;
  223. }
  224. // get the number
  225. pos = atoi(psz);
  226. // scale the values
  227. if (IsProportional())
  228. {
  229. pos = vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), pos );
  230. }
  231. // adjust the positions
  232. if (r)
  233. {
  234. pos = screendimension - pos;
  235. }
  236. if (c)
  237. {
  238. pos = (screendimension / 2) + pos;
  239. }
  240. // set the value
  241. *output = static_cast<float>( pos );
  242. }
  243. //-----------------------------------------------------------------------------
  244. // Purpose: parses a script into sequences
  245. //-----------------------------------------------------------------------------
  246. bool AnimationController::ParseScriptFile(char *pMem, int length)
  247. {
  248. // get the scheme (for looking up color names)
  249. IScheme *scheme = vgui::scheme()->GetIScheme(GetScheme());
  250. // get our screen size (for left/right/center alignment)
  251. int screenWide = m_nScreenBounds[ 2 ];
  252. int screenTall = m_nScreenBounds[ 3 ];
  253. // start by getting the first token
  254. char token[512];
  255. pMem = ParseFile(pMem, token, NULL);
  256. while (token[0])
  257. {
  258. bool bAccepted = true;
  259. // should be 'event'
  260. if (stricmp(token, "event"))
  261. {
  262. Warning("Couldn't parse script file: expected 'event', found '%s'\n", token);
  263. return false;
  264. }
  265. // get the event name
  266. pMem = ParseFile(pMem, token, NULL);
  267. if (strlen(token) < 1)
  268. {
  269. Warning("Couldn't parse script file: expected <event name>, found nothing\n");
  270. return false;
  271. }
  272. int seqIndex;
  273. UtlSymId_t nameIndex = g_ScriptSymbols.AddString(token);
  274. // Create a new sequence
  275. seqIndex = m_Sequences.AddToTail();
  276. AnimSequence_t &seq = m_Sequences[seqIndex];
  277. seq.name = nameIndex;
  278. seq.duration = 0.0f;
  279. // get the open brace or a conditional
  280. pMem = ParseFile(pMem, token, NULL);
  281. if ( Q_stristr( token, "[$" ) )
  282. {
  283. bAccepted = EvaluateConditional( token );
  284. // now get the open brace
  285. pMem = ParseFile(pMem, token, NULL);
  286. }
  287. if (stricmp(token, "{"))
  288. {
  289. Warning("Couldn't parse script sequence '%s': expected '{', found '%s'\n", g_ScriptSymbols.String(seq.name), token);
  290. return false;
  291. }
  292. // walk the commands
  293. while (token[0])
  294. {
  295. // get the command type
  296. pMem = ParseFile(pMem, token, NULL);
  297. // skip out when we hit the end of the sequence
  298. if (token[0] == '}')
  299. break;
  300. // create a new command
  301. int cmdIndex = seq.cmdList.AddToTail();
  302. AnimCommand_t &animCmd = seq.cmdList[cmdIndex];
  303. memset(&animCmd, 0, sizeof(animCmd));
  304. if (!stricmp(token, "animate"))
  305. {
  306. animCmd.commandType = CMD_ANIMATE;
  307. // parse out the animation commands
  308. AnimCmdAnimate_t &cmdAnimate = animCmd.cmdData.animate;
  309. // panel to manipulate
  310. pMem = ParseFile(pMem, token, NULL);
  311. cmdAnimate.panel = g_ScriptSymbols.AddString(token);
  312. // variable to change
  313. pMem = ParseFile(pMem, token, NULL);
  314. cmdAnimate.variable = g_ScriptSymbols.AddString(token);
  315. // target value
  316. pMem = ParseFile(pMem, token, NULL);
  317. if (cmdAnimate.variable == m_sPosition)
  318. {
  319. // Get first token
  320. SetupPosition( cmdAnimate, &cmdAnimate.target.a, token, screenWide );
  321. // Get second token from "token"
  322. char token2[32];
  323. char *psz = ParseFile(token, token2, NULL);
  324. psz = ParseFile(psz, token2, NULL);
  325. psz = token2;
  326. // Position Y goes into ".b"
  327. SetupPosition( cmdAnimate, &cmdAnimate.target.b, psz, screenTall );
  328. }
  329. else if ( cmdAnimate.variable == m_sXPos )
  330. {
  331. // XPos and YPos both use target ".a"
  332. SetupPosition( cmdAnimate, &cmdAnimate.target.a, token, screenWide );
  333. }
  334. else if ( cmdAnimate.variable == m_sYPos )
  335. {
  336. // XPos and YPos both use target ".a"
  337. SetupPosition( cmdAnimate, &cmdAnimate.target.a, token, screenTall );
  338. }
  339. else
  340. {
  341. // parse the floating point values right out
  342. if (0 == sscanf(token, "%f %f %f %f", &cmdAnimate.target.a, &cmdAnimate.target.b, &cmdAnimate.target.c, &cmdAnimate.target.d))
  343. {
  344. //=============================================================================
  345. // HPE_BEGIN:
  346. // [pfreese] Improved handling colors not defined in scheme
  347. //=============================================================================
  348. // could be referencing a value in the scheme file, lookup
  349. Color default_invisible_black(0, 0, 0, 0);
  350. Color col = scheme->GetColor(token, default_invisible_black);
  351. // we don't have a way of seeing if the color is not declared in the scheme, so we use this
  352. // silly method of trying again with a different default to see if we get the fallback again
  353. if (col == default_invisible_black)
  354. {
  355. Color error_pink(255, 0, 255, 255); // make it extremely obvious if a scheme lookup fails
  356. col = scheme->GetColor(token, error_pink);
  357. // commented out for Soldier/Demo release...(getting spammed in console)
  358. // we'll try to figure this out after the update is out
  359. // if (col == error_pink)
  360. // {
  361. // Warning("Missing color in scheme: %s\n", token);
  362. // }
  363. }
  364. //=============================================================================
  365. // HPE_END
  366. //=============================================================================
  367. cmdAnimate.target.a = col[0];
  368. cmdAnimate.target.b = col[1];
  369. cmdAnimate.target.c = col[2];
  370. cmdAnimate.target.d = col[3];
  371. }
  372. }
  373. // fix up scale
  374. if (cmdAnimate.variable == m_sSize)
  375. {
  376. if (IsProportional())
  377. {
  378. cmdAnimate.target.a = static_cast<float>( vgui::scheme()->GetProportionalScaledValueEx(GetScheme(), cmdAnimate.target.a) );
  379. cmdAnimate.target.b = static_cast<float>( vgui::scheme()->GetProportionalScaledValueEx(GetScheme(), cmdAnimate.target.b) );
  380. }
  381. }
  382. else if (cmdAnimate.variable == m_sWide ||
  383. cmdAnimate.variable == m_sTall )
  384. {
  385. if (IsProportional())
  386. {
  387. // Wide and tall both use.a
  388. cmdAnimate.target.a = static_cast<float>( vgui::scheme()->GetProportionalScaledValueEx(GetScheme(), cmdAnimate.target.a) );
  389. }
  390. }
  391. // interpolation function
  392. pMem = ParseFile(pMem, token, NULL);
  393. if (!stricmp(token, "Accel"))
  394. {
  395. cmdAnimate.interpolationFunction = INTERPOLATOR_ACCEL;
  396. }
  397. else if (!stricmp(token, "Deaccel"))
  398. {
  399. cmdAnimate.interpolationFunction = INTERPOLATOR_DEACCEL;
  400. }
  401. else if ( !stricmp(token, "Spline"))
  402. {
  403. cmdAnimate.interpolationFunction = INTERPOLATOR_SIMPLESPLINE;
  404. }
  405. else if (!stricmp(token,"Pulse"))
  406. {
  407. cmdAnimate.interpolationFunction = INTERPOLATOR_PULSE;
  408. // frequencey
  409. pMem = ParseFile(pMem, token, NULL);
  410. cmdAnimate.interpolationParameter = (float)atof(token);
  411. }
  412. else if (!stricmp(token,"Bias"))
  413. {
  414. cmdAnimate.interpolationFunction = INTERPOLATOR_BIAS;
  415. // bias
  416. pMem = ParseFile(pMem, token, NULL);
  417. cmdAnimate.interpolationParameter = (float)atof(token);
  418. }
  419. else if (!stricmp(token,"Gain"))
  420. {
  421. cmdAnimate.interpolationFunction = INTERPOLATOR_GAIN;
  422. // bias
  423. pMem = ParseFile(pMem, token, NULL);
  424. cmdAnimate.interpolationParameter = (float)atof(token);
  425. }
  426. else if ( !stricmp( token, "Flicker"))
  427. {
  428. cmdAnimate.interpolationFunction = INTERPOLATOR_FLICKER;
  429. // noiseamount
  430. pMem = ParseFile(pMem, token, NULL);
  431. cmdAnimate.interpolationParameter = (float)atof(token);
  432. }
  433. else if (!stricmp(token, "Bounce"))
  434. {
  435. cmdAnimate.interpolationFunction = INTERPOLATOR_BOUNCE;
  436. }
  437. else
  438. {
  439. cmdAnimate.interpolationFunction = INTERPOLATOR_LINEAR;
  440. }
  441. // start time
  442. pMem = ParseFile(pMem, token, NULL);
  443. cmdAnimate.startTime = (float)atof(token);
  444. // duration
  445. pMem = ParseFile(pMem, token, NULL);
  446. cmdAnimate.duration = (float)atof(token);
  447. // check max duration
  448. if (cmdAnimate.startTime + cmdAnimate.duration > seq.duration)
  449. {
  450. seq.duration = cmdAnimate.startTime + cmdAnimate.duration;
  451. }
  452. }
  453. else if (!stricmp(token, "runevent"))
  454. {
  455. animCmd.commandType = CMD_RUNEVENT;
  456. pMem = ParseFile(pMem, token, NULL);
  457. animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token);
  458. pMem = ParseFile(pMem, token, NULL);
  459. animCmd.cmdData.runEvent.timeDelay = (float)atof(token);
  460. }
  461. else if (!stricmp(token, "runeventchild"))
  462. {
  463. animCmd.commandType = CMD_RUNEVENTCHILD;
  464. pMem = ParseFile(pMem, token, NULL);
  465. animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token);
  466. pMem = ParseFile(pMem, token, NULL);
  467. animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token);
  468. pMem = ParseFile(pMem, token, NULL);
  469. animCmd.cmdData.runEvent.timeDelay = (float)atof(token);
  470. }
  471. else if (!stricmp(token, "firecommand"))
  472. {
  473. animCmd.commandType = CMD_FIRECOMMAND;
  474. pMem = ParseFile(pMem, token, NULL);
  475. animCmd.cmdData.runEvent.timeDelay = (float)atof(token);
  476. pMem = ParseFile(pMem, token, NULL);
  477. animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token);
  478. }
  479. else if ( !stricmp(token, "playsound") )
  480. {
  481. animCmd.commandType = CMD_PLAYSOUND;
  482. pMem = ParseFile(pMem, token, NULL);
  483. animCmd.cmdData.runEvent.timeDelay = (float)atof(token);
  484. pMem = ParseFile(pMem, token, NULL);
  485. animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token);
  486. }
  487. else if (!stricmp(token, "setvisible"))
  488. {
  489. animCmd.commandType = CMD_SETVISIBLE;
  490. pMem = ParseFile(pMem, token, NULL);
  491. animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token);
  492. pMem = ParseFile(pMem, token, NULL);
  493. animCmd.cmdData.runEvent.variable2 = atoi(token);
  494. pMem = ParseFile(pMem, token, NULL);
  495. animCmd.cmdData.runEvent.timeDelay = (float)atof(token);
  496. }
  497. else if (!stricmp(token, "setinputenabled"))
  498. {
  499. animCmd.commandType = CMD_SETINPUTENABLED;
  500. pMem = ParseFile(pMem, token, NULL);
  501. animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token);
  502. pMem = ParseFile(pMem, token, NULL);
  503. animCmd.cmdData.runEvent.variable2 = atoi(token);
  504. pMem = ParseFile(pMem, token, NULL);
  505. animCmd.cmdData.runEvent.timeDelay = (float)atof(token);
  506. }
  507. else if (!stricmp(token, "stopevent"))
  508. {
  509. animCmd.commandType = CMD_STOPEVENT;
  510. pMem = ParseFile(pMem, token, NULL);
  511. animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token);
  512. pMem = ParseFile(pMem, token, NULL);
  513. animCmd.cmdData.runEvent.timeDelay = (float)atof(token);
  514. }
  515. else if (!stricmp(token, "StopPanelAnimations"))
  516. {
  517. animCmd.commandType = CMD_STOPPANELANIMATIONS;
  518. pMem = ParseFile(pMem, token, NULL);
  519. animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token);
  520. pMem = ParseFile(pMem, token, NULL);
  521. animCmd.cmdData.runEvent.timeDelay = (float)atof(token);
  522. }
  523. else if (!stricmp(token, "stopanimation"))
  524. {
  525. animCmd.commandType = CMD_STOPANIMATION;
  526. pMem = ParseFile(pMem, token, NULL);
  527. animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token);
  528. pMem = ParseFile(pMem, token, NULL);
  529. animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token);
  530. pMem = ParseFile(pMem, token, NULL);
  531. animCmd.cmdData.runEvent.timeDelay = (float)atof(token);
  532. }
  533. else if ( !stricmp( token, "SetFont" ))
  534. {
  535. animCmd.commandType = CMD_SETFONT;
  536. // Panel name
  537. pMem = ParseFile(pMem, token, NULL);
  538. animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token);
  539. // Font parameter
  540. pMem = ParseFile(pMem, token, NULL);
  541. animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token);
  542. // Font name from scheme
  543. pMem = ParseFile(pMem, token, NULL);
  544. animCmd.cmdData.runEvent.variable2 = g_ScriptSymbols.AddString(token);
  545. // Set time
  546. pMem = ParseFile(pMem, token, NULL);
  547. animCmd.cmdData.runEvent.timeDelay = (float)atof(token);
  548. }
  549. else if ( !stricmp( token, "SetTexture" ))
  550. {
  551. animCmd.commandType = CMD_SETTEXTURE;
  552. // Panel name
  553. pMem = ParseFile(pMem, token, NULL);
  554. animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token);
  555. // Texture Id
  556. pMem = ParseFile(pMem, token, NULL);
  557. animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token);
  558. // material name
  559. pMem = ParseFile(pMem, token, NULL);
  560. animCmd.cmdData.runEvent.variable2 = g_ScriptSymbols.AddString(token);
  561. // Set time
  562. pMem = ParseFile(pMem, token, NULL);
  563. animCmd.cmdData.runEvent.timeDelay = (float)atof(token);
  564. }
  565. else if ( !stricmp( token, "SetString" ))
  566. {
  567. animCmd.commandType = CMD_SETSTRING;
  568. // Panel name
  569. pMem = ParseFile(pMem, token, NULL);
  570. animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token);
  571. // String variable name
  572. pMem = ParseFile(pMem, token, NULL);
  573. animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token);
  574. // String value to set
  575. pMem = ParseFile(pMem, token, NULL);
  576. animCmd.cmdData.runEvent.variable2 = g_ScriptSymbols.AddString(token);
  577. // Set time
  578. pMem = ParseFile(pMem, token, NULL);
  579. animCmd.cmdData.runEvent.timeDelay = (float)atof(token);
  580. }
  581. else
  582. {
  583. Warning("Couldn't parse script sequence '%s': expected <anim command>, found '%s'\n", g_ScriptSymbols.String(seq.name), token);
  584. return false;
  585. }
  586. // Look ahead one token for a conditional
  587. char *peek = ParseFile(pMem, token, NULL);
  588. if ( Q_stristr( token, "[$" ) )
  589. {
  590. if ( !EvaluateConditional( token ) )
  591. {
  592. seq.cmdList.Remove( cmdIndex );
  593. }
  594. pMem = peek;
  595. }
  596. }
  597. if ( bAccepted )
  598. {
  599. // Attempt to find a collision in the sequences, replacing the old one if found
  600. int seqIterator;
  601. for ( seqIterator = 0; seqIterator < m_Sequences.Count()-1; seqIterator++ )
  602. {
  603. if ( m_Sequences[seqIterator].name == nameIndex )
  604. {
  605. // Get rid of it, we're overriding it
  606. m_Sequences.Remove( seqIndex );
  607. break;
  608. }
  609. }
  610. }
  611. else
  612. {
  613. // Dump the entire sequence
  614. m_Sequences.Remove( seqIndex );
  615. }
  616. // get the next token, if any
  617. pMem = ParseFile(pMem, token, NULL);
  618. }
  619. return true;
  620. }
  621. //-----------------------------------------------------------------------------
  622. // Purpose: checks all posted animation events, firing if time
  623. //-----------------------------------------------------------------------------
  624. void AnimationController::UpdatePostedMessages(bool bRunToCompletion)
  625. {
  626. CUtlVector<RanEvent_t> eventsRanThisFrame;
  627. // check all posted messages
  628. for (int i = 0; i < m_PostedMessages.Count(); i++)
  629. {
  630. PostedMessage_t &msgRef = m_PostedMessages[i];
  631. if ( !msgRef.canBeCancelled && bRunToCompletion )
  632. continue;
  633. if (m_flCurrentTime < msgRef.startTime && !bRunToCompletion)
  634. continue;
  635. // take a copy of th message
  636. PostedMessage_t msg = msgRef;
  637. // remove the event
  638. // do this before handling the message because the message queue may be messed with
  639. m_PostedMessages.Remove(i);
  640. // reset the count, start the whole queue again
  641. i = -1;
  642. if ( msg.parent.Get() == NULL )
  643. continue;
  644. // handle the event
  645. switch (msg.commandType)
  646. {
  647. case CMD_RUNEVENT:
  648. {
  649. RanEvent_t curEvent;
  650. curEvent.pParent = NULL;
  651. curEvent.event = msg.event;
  652. curEvent.pParent = msg.parent.Get();
  653. // run the event, but only if we haven't already run it this frame, for this parent
  654. if (!eventsRanThisFrame.HasElement(curEvent))
  655. {
  656. eventsRanThisFrame.AddToTail(curEvent);
  657. RunCmd_RunEvent(msg);
  658. }
  659. }
  660. break;
  661. case CMD_RUNEVENTCHILD:
  662. {
  663. RanEvent_t curEvent;
  664. curEvent.pParent = NULL;
  665. curEvent.event = msg.event;
  666. curEvent.pParent = msg.parent.Get()->FindChildByName( g_ScriptSymbols.String(msg.variable), true );
  667. msg.parent = curEvent.pParent;
  668. // run the event, but only if we haven't already run it this frame, for this parent
  669. if (!eventsRanThisFrame.HasElement(curEvent))
  670. {
  671. eventsRanThisFrame.AddToTail(curEvent);
  672. RunCmd_RunEvent(msg);
  673. }
  674. }
  675. break;
  676. case CMD_FIRECOMMAND:
  677. {
  678. msg.parent->OnCommand( g_ScriptSymbols.String(msg.variable) );
  679. }
  680. break;
  681. case CMD_PLAYSOUND:
  682. {
  683. vgui::surface()->PlaySound( g_ScriptSymbols.String(msg.variable) );
  684. }
  685. break;
  686. case CMD_SETVISIBLE:
  687. {
  688. Panel* pPanel = msg.parent.Get()->FindChildByName( g_ScriptSymbols.String(msg.variable), true );
  689. if ( pPanel )
  690. {
  691. pPanel->SetVisible( msg.variable2 == 1 );
  692. }
  693. }
  694. break;
  695. case CMD_SETINPUTENABLED:
  696. {
  697. Panel* pPanel = msg.parent.Get()->FindChildByName( g_ScriptSymbols.String(msg.variable), true );
  698. if ( pPanel )
  699. {
  700. pPanel->SetMouseInputEnabled( msg.variable2 == 1 );
  701. pPanel->SetKeyBoardInputEnabled( msg.variable2 == 1 );
  702. }
  703. }
  704. break;
  705. case CMD_STOPEVENT:
  706. RunCmd_StopEvent(msg);
  707. break;
  708. case CMD_STOPPANELANIMATIONS:
  709. RunCmd_StopPanelAnimations(msg);
  710. break;
  711. case CMD_STOPANIMATION:
  712. RunCmd_StopAnimation(msg);
  713. break;
  714. case CMD_SETFONT:
  715. RunCmd_SetFont(msg);
  716. break;
  717. case CMD_SETTEXTURE:
  718. RunCmd_SetTexture(msg);
  719. break;
  720. case CMD_SETSTRING:
  721. RunCmd_SetString( msg );
  722. break;
  723. }
  724. }
  725. }
  726. //-----------------------------------------------------------------------------
  727. // Purpose: runs the current animations
  728. //-----------------------------------------------------------------------------
  729. void AnimationController::UpdateActiveAnimations(bool bRunToCompletion)
  730. {
  731. // iterate all the currently active animations
  732. for (int i = 0; i < m_ActiveAnimations.Count(); i++)
  733. {
  734. ActiveAnimation_t &anim = m_ActiveAnimations[i];
  735. if ( !anim.canBeCancelled && bRunToCompletion )
  736. continue;
  737. // see if the anim is ready to start
  738. if (m_flCurrentTime < anim.startTime && !bRunToCompletion)
  739. continue;
  740. if (!anim.panel.Get())
  741. {
  742. // panel is gone, remove the animation
  743. m_ActiveAnimations.Remove(i);
  744. --i;
  745. continue;
  746. }
  747. if (!anim.started && !bRunToCompletion)
  748. {
  749. // start the animation from the current value
  750. anim.startValue = GetValue(anim, anim.panel, anim.variable);
  751. anim.started = true;
  752. // Msg( "Starting animation of %s => %.2f (seq: %s) (%s)\n", g_ScriptSymbols.String(anim.variable), anim.endValue.a, g_ScriptSymbols.String(anim.seqName), anim.panel->GetName());
  753. }
  754. // get the interpolated value
  755. Value_t val;
  756. if (m_flCurrentTime >= anim.endTime || bRunToCompletion)
  757. {
  758. // animation is done, use the last value
  759. val = anim.endValue;
  760. }
  761. else
  762. {
  763. // get the interpolated value
  764. val = GetInterpolatedValue(anim.interpolator, anim.interpolatorParam, m_flCurrentTime, anim.startTime, anim.endTime, anim.startValue, anim.endValue);
  765. }
  766. // apply the new value to the panel
  767. SetValue(anim, anim.panel, anim.variable, val);
  768. // Msg( "Animate value: %s => %.2f for panel '%s'\n", g_ScriptSymbols.String(anim.variable), val.a, anim.panel->GetName());
  769. // see if we can remove the animation
  770. if (m_flCurrentTime >= anim.endTime || bRunToCompletion)
  771. {
  772. m_ActiveAnimations.Remove(i);
  773. --i;
  774. }
  775. }
  776. }
  777. bool AnimationController::UpdateScreenSize()
  778. {
  779. // get our screen size (for left/right/center alignment)
  780. int screenWide, screenTall;
  781. int sx = 0, sy = 0;
  782. if ( m_hSizePanel != 0 )
  783. {
  784. ipanel()->GetSize( m_hSizePanel, screenWide, screenTall );
  785. ipanel()->GetPos( m_hSizePanel, sx, sy );
  786. }
  787. else
  788. {
  789. surface()->GetScreenSize(screenWide, screenTall);
  790. }
  791. bool changed = m_nScreenBounds[ 0 ] != sx ||
  792. m_nScreenBounds[ 1 ] != sy ||
  793. m_nScreenBounds[ 2 ] != screenWide ||
  794. m_nScreenBounds[ 3 ] != screenTall;
  795. m_nScreenBounds[ 0 ] = sx;
  796. m_nScreenBounds[ 1 ] = sy;
  797. m_nScreenBounds[ 2 ] = screenWide;
  798. m_nScreenBounds[ 3 ] = screenTall;
  799. return changed;
  800. }
  801. //-----------------------------------------------------------------------------
  802. // Purpose: runs a frame of animation
  803. //-----------------------------------------------------------------------------
  804. void AnimationController::UpdateAnimations( float currentTime )
  805. {
  806. m_flCurrentTime = currentTime;
  807. if ( UpdateScreenSize() && m_ScriptFileNames.Count() )
  808. {
  809. RunAllAnimationsToCompletion();
  810. ReloadScriptFile();
  811. }
  812. UpdatePostedMessages(false);
  813. UpdateActiveAnimations(false);
  814. }
  815. //-----------------------------------------------------------------------------
  816. // Purpose: plays all animations to completion instantly
  817. //-----------------------------------------------------------------------------
  818. void AnimationController::RunAllAnimationsToCompletion()
  819. {
  820. // Msg( "AnimationController::RunAllAnimationsToCompletion()\n" );
  821. UpdatePostedMessages(true);
  822. UpdateActiveAnimations(true);
  823. }
  824. //-----------------------------------------------------------------------------
  825. // Purpose: Stops all current animations
  826. //-----------------------------------------------------------------------------
  827. void AnimationController::CancelAllAnimations()
  828. {
  829. // Msg( "AnimationController::CancelAllAnimations()\n" );
  830. FOR_EACH_VEC_BACK( m_ActiveAnimations, i )
  831. {
  832. if ( m_ActiveAnimations[i].canBeCancelled )
  833. m_ActiveAnimations.Remove( i );
  834. }
  835. FOR_EACH_VEC_BACK(m_PostedMessages, i)
  836. {
  837. if (m_PostedMessages[i].canBeCancelled)
  838. m_PostedMessages.Remove(i);
  839. }
  840. }
  841. //-----------------------------------------------------------------------------
  842. // Purpose: produces an interpolated value
  843. //-----------------------------------------------------------------------------
  844. AnimationController::Value_t AnimationController::GetInterpolatedValue(int interpolator, float interpolatorParam, float currentTime, float startTime, float endTime, Value_t &startValue, Value_t &endValue)
  845. {
  846. // calculate how far we are into the animation
  847. float pos = (currentTime - startTime) / (endTime - startTime);
  848. // adjust the percentage through by the interpolation function
  849. switch (interpolator)
  850. {
  851. case INTERPOLATOR_ACCEL:
  852. pos *= pos;
  853. break;
  854. case INTERPOLATOR_DEACCEL:
  855. pos = sqrtf(pos);
  856. break;
  857. case INTERPOLATOR_SIMPLESPLINE:
  858. pos = SimpleSpline( pos );
  859. break;
  860. case INTERPOLATOR_PULSE:
  861. // Make sure we end at 1.0, so use cosine
  862. pos = 0.5f + 0.5f * ( cos( pos * 2.0f * M_PI * interpolatorParam ) );
  863. break;
  864. case INTERPOLATOR_BIAS:
  865. pos = Bias( pos, interpolatorParam );
  866. break;
  867. case INTERPOLATOR_GAIN:
  868. pos = Gain( pos, interpolatorParam );
  869. break;
  870. case INTERPOLATOR_FLICKER:
  871. if ( RandomFloat( 0.0f, 1.0f ) < interpolatorParam )
  872. {
  873. pos = 1.0f;
  874. }
  875. else
  876. {
  877. pos = 0.0f;
  878. }
  879. break;
  880. case INTERPOLATOR_BOUNCE:
  881. {
  882. // fall from startValue to endValue, bouncing a few times and settling out at endValue
  883. const float hit1 = 0.33f;
  884. const float hit2 = 0.67f;
  885. const float hit3 = 1.0f;
  886. if ( pos < hit1 )
  887. {
  888. pos = 1.0f - sin( M_PI * pos / hit1 );
  889. }
  890. else if ( pos < hit2 )
  891. {
  892. pos = 0.5f + 0.5f * ( 1.0f - sin( M_PI * ( pos - hit1 ) / ( hit2 - hit1 ) ) );
  893. }
  894. else
  895. {
  896. pos = 0.8f + 0.2f * ( 1.0f - sin( M_PI * ( pos - hit2 ) / ( hit3 - hit2 ) ) );
  897. }
  898. break;
  899. }
  900. case INTERPOLATOR_LINEAR:
  901. default:
  902. break;
  903. }
  904. // calculate the value
  905. Value_t val;
  906. val.a = ((endValue.a - startValue.a) * pos) + startValue.a;
  907. val.b = ((endValue.b - startValue.b) * pos) + startValue.b;
  908. val.c = ((endValue.c - startValue.c) * pos) + startValue.c;
  909. val.d = ((endValue.d - startValue.d) * pos) + startValue.d;
  910. return val;
  911. }
  912. //-----------------------------------------------------------------------------
  913. // Purpose: sets that the script file should be reloaded each time a script is ran
  914. // used for development
  915. //-----------------------------------------------------------------------------
  916. void AnimationController::SetAutoReloadScript(bool state)
  917. {
  918. m_bAutoReloadScript = state;
  919. }
  920. //-----------------------------------------------------------------------------
  921. // Purpose: starts an animation sequence script
  922. //-----------------------------------------------------------------------------
  923. bool AnimationController::StartAnimationSequence(const char *sequenceName, bool bCanBeCancelled )
  924. {
  925. // We support calling an animation on elements that are not the calling
  926. // panel's children. Use the base parent to start the search.
  927. return StartAnimationSequence( GetParent(), sequenceName, bCanBeCancelled );
  928. }
  929. //-----------------------------------------------------------------------------
  930. // Purpose: starts an animation sequence script
  931. //-----------------------------------------------------------------------------
  932. bool AnimationController::StartAnimationSequence(Panel *pWithinParent, const char *sequenceName, bool bCanBeCancelled )
  933. {
  934. Assert( pWithinParent );
  935. if (m_bAutoReloadScript)
  936. {
  937. // Reload the script files
  938. ReloadScriptFile();
  939. }
  940. // lookup the symbol for the name
  941. UtlSymId_t seqName = g_ScriptSymbols.Find(sequenceName);
  942. if (seqName == UTL_INVAL_SYMBOL)
  943. return false;
  944. // Msg("Starting animation sequence %s\n", sequenceName);
  945. // remove the existing command from the queue
  946. RemoveQueuedAnimationCommands(seqName, pWithinParent);
  947. // look through for the sequence
  948. int i;
  949. for (i = 0; i < m_Sequences.Count(); i++)
  950. {
  951. if (m_Sequences[i].name == seqName)
  952. break;
  953. }
  954. if (i >= m_Sequences.Count())
  955. return false;
  956. // execute the sequence
  957. for (int cmdIndex = 0; cmdIndex < m_Sequences[i].cmdList.Count(); cmdIndex++)
  958. {
  959. ExecAnimationCommand(seqName, m_Sequences[i].cmdList[cmdIndex], pWithinParent, bCanBeCancelled);
  960. }
  961. return true;
  962. }
  963. //-----------------------------------------------------------------------------
  964. // Purpose: stops an animation sequence script
  965. //-----------------------------------------------------------------------------
  966. bool AnimationController::StopAnimationSequence( Panel *pWithinParent, const char *sequenceName )
  967. {
  968. Assert( pWithinParent );
  969. // lookup the symbol for the name
  970. UtlSymId_t seqName = g_ScriptSymbols.Find( sequenceName );
  971. if (seqName == UTL_INVAL_SYMBOL)
  972. return false;
  973. // remove the existing command from the queue
  974. RemoveQueuedAnimationCommands( seqName, pWithinParent );
  975. return true;
  976. }
  977. //-----------------------------------------------------------------------------
  978. // Purpose: Runs a custom command from code, not from a script file
  979. //-----------------------------------------------------------------------------
  980. void AnimationController::CancelAnimationsForPanel( Panel *pWithinParent )
  981. {
  982. // Msg("Removing queued anims for sequence %s\n", g_ScriptSymbols.String(seqName));
  983. // remove messages posted by this sequence
  984. // if pWithinParent is specified, remove only messages under that parent
  985. {
  986. for (int i = 0; i < m_PostedMessages.Count(); i++)
  987. {
  988. if ( m_PostedMessages[i].parent == pWithinParent )
  989. {
  990. m_PostedMessages.Remove(i);
  991. --i;
  992. }
  993. }
  994. }
  995. // remove all animations
  996. // if pWithinParent is specified, remove only animations under that parent
  997. for (int i = 0; i < m_ActiveAnimations.Count(); i++)
  998. {
  999. Panel *animPanel = m_ActiveAnimations[i].panel;
  1000. if ( !animPanel )
  1001. continue;
  1002. Panel *foundPanel = pWithinParent->FindChildByName(animPanel->GetName(),true);
  1003. if ( foundPanel != animPanel )
  1004. continue;
  1005. m_ActiveAnimations.Remove(i);
  1006. --i;
  1007. }
  1008. }
  1009. //-----------------------------------------------------------------------------
  1010. // Purpose: Runs a custom command from code, not from a script file
  1011. //-----------------------------------------------------------------------------
  1012. void AnimationController::RunAnimationCommand(vgui::Panel *panel, const char *variable, float targetValue, float startDelaySeconds, float duration, Interpolators_e interpolator, float animParameter /* = 0 */ )
  1013. {
  1014. // clear any previous animations of this variable
  1015. UtlSymId_t var = g_ScriptSymbols.AddString(variable);
  1016. RemoveQueuedAnimationByType(panel, var, UTL_INVAL_SYMBOL);
  1017. // build a new animation
  1018. AnimCmdAnimate_t animateCmd;
  1019. memset(&animateCmd, 0, sizeof(animateCmd));
  1020. animateCmd.panel = 0;
  1021. animateCmd.variable = var;
  1022. animateCmd.target.a = targetValue;
  1023. animateCmd.interpolationFunction = interpolator;
  1024. animateCmd.interpolationParameter = animParameter;
  1025. animateCmd.startTime = startDelaySeconds;
  1026. animateCmd.duration = duration;
  1027. // start immediately
  1028. StartCmd_Animate(panel, 0, animateCmd, true);
  1029. }
  1030. //-----------------------------------------------------------------------------
  1031. // Purpose: Runs a custom command from code, not from a script file
  1032. //-----------------------------------------------------------------------------
  1033. void AnimationController::RunAnimationCommand(vgui::Panel *panel, const char *variable, Color targetValue, float startDelaySeconds, float duration, Interpolators_e interpolator, float animParameter /* = 0 */ )
  1034. {
  1035. // clear any previous animations of this variable
  1036. UtlSymId_t var = g_ScriptSymbols.AddString(variable);
  1037. RemoveQueuedAnimationByType(panel, var, UTL_INVAL_SYMBOL);
  1038. // build a new animation
  1039. AnimCmdAnimate_t animateCmd;
  1040. memset(&animateCmd, 0, sizeof(animateCmd));
  1041. animateCmd.panel = 0;
  1042. animateCmd.variable = var;
  1043. animateCmd.target.a = targetValue[0];
  1044. animateCmd.target.b = targetValue[1];
  1045. animateCmd.target.c = targetValue[2];
  1046. animateCmd.target.d = targetValue[3];
  1047. animateCmd.interpolationFunction = interpolator;
  1048. animateCmd.interpolationParameter = animParameter;
  1049. animateCmd.startTime = startDelaySeconds;
  1050. animateCmd.duration = duration;
  1051. // start immediately
  1052. StartCmd_Animate(panel, 0, animateCmd, true);
  1053. }
  1054. //-----------------------------------------------------------------------------
  1055. // Purpose: gets the length of an animation sequence, in seconds
  1056. //-----------------------------------------------------------------------------
  1057. float AnimationController::GetAnimationSequenceLength(const char *sequenceName)
  1058. {
  1059. // lookup the symbol for the name
  1060. UtlSymId_t seqName = g_ScriptSymbols.Find(sequenceName);
  1061. if (seqName == UTL_INVAL_SYMBOL)
  1062. return 0.0f;
  1063. // look through for the sequence
  1064. int i;
  1065. for (i = 0; i < m_Sequences.Count(); i++)
  1066. {
  1067. if (m_Sequences[i].name == seqName)
  1068. break;
  1069. }
  1070. if (i >= m_Sequences.Count())
  1071. return 0.0f;
  1072. // sequence found
  1073. return m_Sequences[i].duration;
  1074. }
  1075. //-----------------------------------------------------------------------------
  1076. // Purpose: removes an existing set of commands from the queue
  1077. //-----------------------------------------------------------------------------
  1078. void AnimationController::RemoveQueuedAnimationCommands(UtlSymId_t seqName, Panel *pWithinParent)
  1079. {
  1080. // Msg("Removing queued anims for sequence %s\n", g_ScriptSymbols.String(seqName));
  1081. // remove messages posted by this sequence
  1082. // if pWithinParent is specified, remove only messages under that parent
  1083. {for (int i = 0; i < m_PostedMessages.Count(); i++)
  1084. {
  1085. if ( ( m_PostedMessages[i].seqName == seqName ) &&
  1086. ( !pWithinParent || ( m_PostedMessages[i].parent == pWithinParent ) ) )
  1087. {
  1088. m_PostedMessages.Remove(i);
  1089. --i;
  1090. }
  1091. }}
  1092. // remove all animations
  1093. // if pWithinParent is specified, remove only animations under that parent
  1094. for (int i = 0; i < m_ActiveAnimations.Count(); i++)
  1095. {
  1096. if ( m_ActiveAnimations[i].seqName != seqName )
  1097. continue;
  1098. // panel this anim is on, m_ActiveAnimations[i].panel
  1099. if ( pWithinParent )
  1100. {
  1101. Panel *animPanel = m_ActiveAnimations[i].panel;
  1102. if ( !animPanel )
  1103. continue;
  1104. Panel *foundPanel = pWithinParent->FindChildByName(animPanel->GetName(),true);
  1105. if ( foundPanel != animPanel )
  1106. continue;
  1107. }
  1108. m_ActiveAnimations.Remove(i);
  1109. --i;
  1110. }
  1111. }
  1112. //-----------------------------------------------------------------------------
  1113. // Purpose: removes the specified queued animation
  1114. //-----------------------------------------------------------------------------
  1115. void AnimationController::RemoveQueuedAnimationByType(vgui::Panel *panel, UtlSymId_t variable, UtlSymId_t sequenceToIgnore)
  1116. {
  1117. for (int i = 0; i < m_ActiveAnimations.Count(); i++)
  1118. {
  1119. if (m_ActiveAnimations[i].panel == panel && m_ActiveAnimations[i].variable == variable && m_ActiveAnimations[i].seqName != sequenceToIgnore)
  1120. {
  1121. // Msg("Removing queued anim %s::%s::%s\n", g_ScriptSymbols.String(m_ActiveAnimations[i].seqName), panel->GetName(), g_ScriptSymbols.String(variable));
  1122. m_ActiveAnimations.Remove(i);
  1123. break;
  1124. }
  1125. }
  1126. }
  1127. //-----------------------------------------------------------------------------
  1128. // Purpose: runs a single line of the script
  1129. //-----------------------------------------------------------------------------
  1130. void AnimationController::ExecAnimationCommand(UtlSymId_t seqName, AnimCommand_t &animCommand, Panel *pWithinParent, bool bCanBeCancelled)
  1131. {
  1132. if (animCommand.commandType == CMD_ANIMATE)
  1133. {
  1134. StartCmd_Animate(seqName, animCommand.cmdData.animate, pWithinParent, bCanBeCancelled);
  1135. }
  1136. else
  1137. {
  1138. // post the command to happen at the specified time
  1139. PostedMessage_t &msg = m_PostedMessages[m_PostedMessages.AddToTail()];
  1140. msg.seqName = seqName;
  1141. msg.commandType = animCommand.commandType;
  1142. msg.event = animCommand.cmdData.runEvent.event;
  1143. msg.variable = animCommand.cmdData.runEvent.variable;
  1144. msg.variable2 = animCommand.cmdData.runEvent.variable2;
  1145. msg.startTime = m_flCurrentTime + animCommand.cmdData.runEvent.timeDelay;
  1146. msg.parent = pWithinParent;
  1147. msg.canBeCancelled = bCanBeCancelled;
  1148. }
  1149. }
  1150. //-----------------------------------------------------------------------------
  1151. // Purpose: starts a variable animation
  1152. //-----------------------------------------------------------------------------
  1153. void AnimationController::StartCmd_Animate(UtlSymId_t seqName, AnimCmdAnimate_t &cmd, Panel *pWithinParent, bool bCanBeCancelled)
  1154. {
  1155. Assert( pWithinParent );
  1156. if ( !pWithinParent )
  1157. return;
  1158. // make sure the child exists
  1159. Panel *panel = pWithinParent->FindChildByName(g_ScriptSymbols.String(cmd.panel),true);
  1160. if ( !panel )
  1161. {
  1162. // Check the parent
  1163. Panel *parent = GetParent();
  1164. if ( !Q_stricmp( parent->GetName(), g_ScriptSymbols.String(cmd.panel) ) )
  1165. {
  1166. panel = parent;
  1167. }
  1168. }
  1169. if (!panel)
  1170. return;
  1171. StartCmd_Animate(panel, seqName, cmd, bCanBeCancelled);
  1172. }
  1173. //-----------------------------------------------------------------------------
  1174. // Purpose: Starts an animation command for the specified panel
  1175. //-----------------------------------------------------------------------------
  1176. void AnimationController::StartCmd_Animate(Panel *panel, UtlSymId_t seqName, AnimCmdAnimate_t &cmd, bool bCanBeCancelled)
  1177. {
  1178. // build a command to add to the animation queue
  1179. ActiveAnimation_t &anim = m_ActiveAnimations[m_ActiveAnimations.AddToTail()];
  1180. anim.panel = panel;
  1181. anim.seqName = seqName;
  1182. anim.variable = cmd.variable;
  1183. anim.interpolator = cmd.interpolationFunction;
  1184. anim.interpolatorParam = cmd.interpolationParameter;
  1185. // timings
  1186. anim.startTime = m_flCurrentTime + cmd.startTime;
  1187. anim.endTime = anim.startTime + cmd.duration;
  1188. // values
  1189. anim.started = false;
  1190. anim.endValue = cmd.target;
  1191. anim.canBeCancelled = bCanBeCancelled;
  1192. anim.align = cmd.align;
  1193. }
  1194. //-----------------------------------------------------------------------------
  1195. // Purpose: a posted message to run another event
  1196. //-----------------------------------------------------------------------------
  1197. void AnimationController::RunCmd_RunEvent(PostedMessage_t &msg)
  1198. {
  1199. StartAnimationSequence(msg.parent.Get(), g_ScriptSymbols.String(msg.event), msg.canBeCancelled);
  1200. }
  1201. //-----------------------------------------------------------------------------
  1202. // Purpose: a posted message to stop another event
  1203. //-----------------------------------------------------------------------------
  1204. void AnimationController::RunCmd_StopEvent(PostedMessage_t &msg)
  1205. {
  1206. RemoveQueuedAnimationCommands(msg.event, msg.parent);
  1207. }
  1208. //-----------------------------------------------------------------------------
  1209. // Purpose: a posted message to stop all animations relevant to a specified panel
  1210. //-----------------------------------------------------------------------------
  1211. void AnimationController::RunCmd_StopPanelAnimations(PostedMessage_t &msg)
  1212. {
  1213. Panel *panel = FindSiblingByName(g_ScriptSymbols.String(msg.event));
  1214. Assert(panel != NULL);
  1215. if (!panel)
  1216. return;
  1217. // loop through all the active animations cancelling any that
  1218. // are operating on said panel, except for the event specified
  1219. for (int i = 0; i < m_ActiveAnimations.Count(); i++)
  1220. {
  1221. if (m_ActiveAnimations[i].panel == panel && m_ActiveAnimations[i].seqName != msg.seqName)
  1222. {
  1223. m_ActiveAnimations.Remove(i);
  1224. --i;
  1225. }
  1226. }
  1227. }
  1228. //-----------------------------------------------------------------------------
  1229. // Purpose: a posted message to stop animations of a specific type
  1230. //-----------------------------------------------------------------------------
  1231. void AnimationController::RunCmd_StopAnimation(PostedMessage_t &msg)
  1232. {
  1233. Panel *panel = FindSiblingByName(g_ScriptSymbols.String(msg.event));
  1234. Assert(panel != NULL);
  1235. if (!panel)
  1236. return;
  1237. RemoveQueuedAnimationByType(panel, msg.variable, msg.seqName);
  1238. }
  1239. //-----------------------------------------------------------------------------
  1240. // Purpose:
  1241. //-----------------------------------------------------------------------------
  1242. void AnimationController::RunCmd_SetFont( PostedMessage_t &msg )
  1243. {
  1244. Panel *parent = msg.parent.Get();
  1245. if ( !parent )
  1246. {
  1247. parent = GetParent();
  1248. }
  1249. Panel *panel = parent->FindChildByName(g_ScriptSymbols.String(msg.event), true);
  1250. Assert(panel != NULL);
  1251. if (!panel)
  1252. return;
  1253. KeyValues *inputData = new KeyValues(g_ScriptSymbols.String(msg.variable));
  1254. inputData->SetString(g_ScriptSymbols.String(msg.variable), g_ScriptSymbols.String(msg.variable2));
  1255. if (!panel->SetInfo(inputData))
  1256. {
  1257. // Assert(!("Unhandlable var in AnimationController::SetValue())"));
  1258. }
  1259. inputData->deleteThis();
  1260. }
  1261. //-----------------------------------------------------------------------------
  1262. // Purpose:
  1263. //-----------------------------------------------------------------------------
  1264. void AnimationController::RunCmd_SetTexture( PostedMessage_t &msg )
  1265. {
  1266. Panel *panel = FindSiblingByName(g_ScriptSymbols.String(msg.event));
  1267. Assert(panel != NULL);
  1268. if (!panel)
  1269. return;
  1270. KeyValues *inputData = new KeyValues(g_ScriptSymbols.String(msg.variable));
  1271. inputData->SetString(g_ScriptSymbols.String(msg.variable), g_ScriptSymbols.String(msg.variable2));
  1272. if (!panel->SetInfo(inputData))
  1273. {
  1274. // Assert(!("Unhandlable var in AnimationController::SetValue())"));
  1275. }
  1276. inputData->deleteThis();
  1277. }
  1278. //-----------------------------------------------------------------------------
  1279. // Purpose:
  1280. //-----------------------------------------------------------------------------
  1281. void AnimationController::RunCmd_SetString( PostedMessage_t &msg )
  1282. {
  1283. Panel *panel = FindSiblingByName(g_ScriptSymbols.String(msg.event));
  1284. Assert(panel != NULL);
  1285. if (!panel)
  1286. return;
  1287. KeyValues *inputData = new KeyValues(g_ScriptSymbols.String(msg.variable));
  1288. inputData->SetString(g_ScriptSymbols.String(msg.variable), g_ScriptSymbols.String(msg.variable2));
  1289. if (!panel->SetInfo(inputData))
  1290. {
  1291. // Assert(!("Unhandlable var in AnimationController::SetValue())"));
  1292. }
  1293. inputData->deleteThis();
  1294. }
  1295. //-----------------------------------------------------------------------------
  1296. // Purpose:
  1297. //-----------------------------------------------------------------------------
  1298. int AnimationController::GetRelativeOffset( AnimAlign_t& align, bool xcoord )
  1299. {
  1300. if ( !align.relativePosition )
  1301. return 0;
  1302. Panel *panel = GetParent()->FindChildByName(g_ScriptSymbols.String(align.alignPanel), true);
  1303. if ( !panel )
  1304. return 0;
  1305. int x, y, w, h;
  1306. panel->GetBounds( x, y, w, h );
  1307. int offset =0;
  1308. switch ( align.alignment )
  1309. {
  1310. default:
  1311. case a_northwest:
  1312. offset = xcoord ? x : y;
  1313. break;
  1314. case a_north:
  1315. offset = xcoord ? ( x + w ) / 2 : y;
  1316. break;
  1317. case a_northeast:
  1318. offset = xcoord ? ( x + w ) : y;
  1319. break;
  1320. case a_west:
  1321. offset = xcoord ? x : ( y + h ) / 2;
  1322. break;
  1323. case a_center:
  1324. offset = xcoord ? ( x + w ) / 2 : ( y + h ) / 2;
  1325. break;
  1326. case a_east:
  1327. offset = xcoord ? ( x + w ) : ( y + h ) / 2;
  1328. break;
  1329. case a_southwest:
  1330. offset = xcoord ? x : ( y + h );
  1331. break;
  1332. case a_south:
  1333. offset = xcoord ? ( x + w ) / 2 : ( y + h );
  1334. break;
  1335. case a_southeast:
  1336. offset = xcoord ? ( x + w ) : ( y + h );
  1337. break;
  1338. }
  1339. return offset;
  1340. }
  1341. //-----------------------------------------------------------------------------
  1342. // Purpose: Gets the specified value from a panel
  1343. //-----------------------------------------------------------------------------
  1344. AnimationController::Value_t AnimationController::GetValue(ActiveAnimation_t& anim, Panel *panel, UtlSymId_t var)
  1345. {
  1346. Value_t val = { 0, 0, 0, 0 };
  1347. if (var == m_sPosition)
  1348. {
  1349. int x, y;
  1350. panel->GetPos(x, y);
  1351. val.a = (float)(x - GetRelativeOffset( anim.align, true ) );
  1352. val.b = (float)(y - GetRelativeOffset( anim.align, false ) );
  1353. }
  1354. else if (var == m_sSize)
  1355. {
  1356. int w, t;
  1357. panel->GetSize(w, t);
  1358. val.a = (float)w;
  1359. val.b = (float)t;
  1360. }
  1361. else if (var == m_sFgColor)
  1362. {
  1363. Color col = panel->GetFgColor();
  1364. val.a = col[0];
  1365. val.b = col[1];
  1366. val.c = col[2];
  1367. val.d = col[3];
  1368. }
  1369. else if (var == m_sBgColor)
  1370. {
  1371. Color col = panel->GetBgColor();
  1372. val.a = col[0];
  1373. val.b = col[1];
  1374. val.c = col[2];
  1375. val.d = col[3];
  1376. }
  1377. else if ( var == m_sXPos )
  1378. {
  1379. int x, y;
  1380. panel->GetPos(x, y);
  1381. val.a = (float)( x - GetRelativeOffset( anim.align, true ) );
  1382. }
  1383. else if ( var == m_sYPos )
  1384. {
  1385. int x, y;
  1386. panel->GetPos(x, y);
  1387. val.a = (float)( y - GetRelativeOffset( anim.align, false ) );
  1388. }
  1389. else if ( var == m_sWide )
  1390. {
  1391. int w, h;
  1392. panel->GetSize(w, h);
  1393. val.a = (float)w;
  1394. }
  1395. else if ( var == m_sTall )
  1396. {
  1397. int w, h;
  1398. panel->GetSize(w, h);
  1399. val.a = (float)h;
  1400. }
  1401. else
  1402. {
  1403. KeyValues *outputData = new KeyValues(g_ScriptSymbols.String(var));
  1404. if (panel->RequestInfo(outputData))
  1405. {
  1406. // find the var and lookup it's type
  1407. KeyValues *kv = outputData->FindKey(g_ScriptSymbols.String(var));
  1408. if (kv && kv->GetDataType() == KeyValues::TYPE_FLOAT)
  1409. {
  1410. val.a = kv->GetFloat();
  1411. val.b = 0.0f;
  1412. val.c = 0.0f;
  1413. val.d = 0.0f;
  1414. }
  1415. else if (kv && kv->GetDataType() == KeyValues::TYPE_COLOR)
  1416. {
  1417. Color col = kv->GetColor();
  1418. val.a = col[0];
  1419. val.b = col[1];
  1420. val.c = col[2];
  1421. val.d = col[3];
  1422. }
  1423. }
  1424. else
  1425. {
  1426. // Assert(!("Unhandlable var in AnimationController::GetValue())"));
  1427. }
  1428. outputData->deleteThis();
  1429. }
  1430. return val;
  1431. }
  1432. //-----------------------------------------------------------------------------
  1433. // Purpose: Sets a value in a panel
  1434. //-----------------------------------------------------------------------------
  1435. void AnimationController::SetValue(ActiveAnimation_t& anim, Panel *panel, UtlSymId_t var, Value_t &value)
  1436. {
  1437. if (var == m_sPosition)
  1438. {
  1439. int x = (int)value.a + GetRelativeOffset( anim.align, true );
  1440. int y = (int)value.b + GetRelativeOffset( anim.align, false );
  1441. panel->SetPos(x, y);
  1442. }
  1443. else if (var == m_sSize)
  1444. {
  1445. panel->SetSize((int)value.a, (int)value.b);
  1446. }
  1447. else if (var == m_sFgColor)
  1448. {
  1449. Color col = panel->GetFgColor();
  1450. col[0] = (unsigned char)value.a;
  1451. col[1] = (unsigned char)value.b;
  1452. col[2] = (unsigned char)value.c;
  1453. col[3] = (unsigned char)value.d;
  1454. panel->SetFgColor(col);
  1455. }
  1456. else if (var == m_sBgColor)
  1457. {
  1458. Color col = panel->GetBgColor();
  1459. col[0] = (unsigned char)value.a;
  1460. col[1] = (unsigned char)value.b;
  1461. col[2] = (unsigned char)value.c;
  1462. col[3] = (unsigned char)value.d;
  1463. panel->SetBgColor(col);
  1464. }
  1465. else if (var == m_sXPos)
  1466. {
  1467. int newx = (int)value.a + GetRelativeOffset( anim.align, true );
  1468. int x, y;
  1469. panel->GetPos( x, y );
  1470. x = newx;
  1471. panel->SetPos(x, y);
  1472. }
  1473. else if (var == m_sYPos)
  1474. {
  1475. int newy = (int)value.a + GetRelativeOffset( anim.align, false );
  1476. int x, y;
  1477. panel->GetPos( x, y );
  1478. y = newy;
  1479. panel->SetPos(x, y);
  1480. }
  1481. else if (var == m_sWide)
  1482. {
  1483. int neww = (int)value.a;
  1484. int w, h;
  1485. panel->GetSize( w, h );
  1486. w = neww;
  1487. panel->SetSize(w, h);
  1488. }
  1489. else if (var == m_sTall)
  1490. {
  1491. int newh = (int)value.a;
  1492. int w, h;
  1493. panel->GetSize( w, h );
  1494. h = newh;
  1495. panel->SetSize(w, h);
  1496. }
  1497. else
  1498. {
  1499. KeyValues *inputData = new KeyValues(g_ScriptSymbols.String(var));
  1500. // set the custom value
  1501. if (value.b == 0.0f && value.c == 0.0f && value.d == 0.0f)
  1502. {
  1503. // only the first value is non-zero, so probably just a float value
  1504. inputData->SetFloat(g_ScriptSymbols.String(var), value.a);
  1505. }
  1506. else
  1507. {
  1508. // multivalue, set the color
  1509. Color col((unsigned char)value.a, (unsigned char)value.b, (unsigned char)value.c, (unsigned char)value.d);
  1510. inputData->SetColor(g_ScriptSymbols.String(var), col);
  1511. }
  1512. if (!panel->SetInfo(inputData))
  1513. {
  1514. // Assert(!("Unhandlable var in AnimationController::SetValue())"));
  1515. }
  1516. inputData->deleteThis();
  1517. }
  1518. }
  1519. // Hooks between panels and animation controller system
  1520. class CPanelAnimationDictionary
  1521. {
  1522. public:
  1523. CPanelAnimationDictionary() : m_PanelAnimationMapPool( 32 )
  1524. {
  1525. }
  1526. ~CPanelAnimationDictionary()
  1527. {
  1528. m_PanelAnimationMapPool.Clear();
  1529. }
  1530. PanelAnimationMap *FindOrAddPanelAnimationMap( char const *className );
  1531. PanelAnimationMap *FindPanelAnimationMap( char const *className );
  1532. void PanelAnimationDumpVars( char const *className );
  1533. private:
  1534. struct PanelAnimationMapDictionaryEntry
  1535. {
  1536. PanelAnimationMap *map;
  1537. };
  1538. char const *StripNamespace( char const *className );
  1539. void PanelAnimationDumpMap( PanelAnimationMap *map, bool recursive );
  1540. CClassMemoryPool< PanelAnimationMap > m_PanelAnimationMapPool;
  1541. CUtlDict< PanelAnimationMapDictionaryEntry, int > m_AnimationMaps;
  1542. };
  1543. char const *CPanelAnimationDictionary::StripNamespace( char const *className )
  1544. {
  1545. if ( !Q_strnicmp( className, "vgui::", 6 ) )
  1546. {
  1547. return className + 6;
  1548. }
  1549. return className;
  1550. }
  1551. //-----------------------------------------------------------------------------
  1552. // Purpose: Find but don't add mapping
  1553. //-----------------------------------------------------------------------------
  1554. PanelAnimationMap *CPanelAnimationDictionary::FindPanelAnimationMap( char const *className )
  1555. {
  1556. int lookup = m_AnimationMaps.Find( StripNamespace( className ) );
  1557. if ( lookup != m_AnimationMaps.InvalidIndex() )
  1558. {
  1559. return m_AnimationMaps[ lookup ].map;
  1560. }
  1561. return NULL;
  1562. }
  1563. //-----------------------------------------------------------------------------
  1564. // Purpose:
  1565. //-----------------------------------------------------------------------------
  1566. PanelAnimationMap *CPanelAnimationDictionary::FindOrAddPanelAnimationMap( char const *className )
  1567. {
  1568. PanelAnimationMap *map = FindPanelAnimationMap( className );
  1569. if ( map )
  1570. return map;
  1571. Panel::InitPropertyConverters();
  1572. PanelAnimationMapDictionaryEntry entry;
  1573. entry.map = (PanelAnimationMap *)m_PanelAnimationMapPool.Alloc();
  1574. m_AnimationMaps.Insert( StripNamespace( className ), entry );
  1575. return entry.map;
  1576. }
  1577. //-----------------------------------------------------------------------------
  1578. // Purpose:
  1579. //-----------------------------------------------------------------------------
  1580. void CPanelAnimationDictionary::PanelAnimationDumpMap( PanelAnimationMap *map, bool recursive )
  1581. {
  1582. if ( map->pfnClassName )
  1583. {
  1584. Msg( "%s\n", (*map->pfnClassName)() );
  1585. }
  1586. int c = map->entries.Count();
  1587. for ( int i = 0; i < c; i++ )
  1588. {
  1589. PanelAnimationMapEntry *e = &map->entries[ i ];
  1590. Msg( " %s %s\n", e->type(), e->name() );
  1591. }
  1592. if ( recursive && map->baseMap )
  1593. {
  1594. PanelAnimationDumpMap( map->baseMap, recursive );
  1595. }
  1596. }
  1597. //-----------------------------------------------------------------------------
  1598. // Purpose:
  1599. //-----------------------------------------------------------------------------
  1600. void CPanelAnimationDictionary::PanelAnimationDumpVars( char const *className )
  1601. {
  1602. if ( className == NULL )
  1603. {
  1604. for ( int i = 0; i < (int)m_AnimationMaps.Count(); i++ )
  1605. {
  1606. PanelAnimationDumpMap( m_AnimationMaps[ i ].map, false );
  1607. }
  1608. }
  1609. else
  1610. {
  1611. PanelAnimationMap *map = FindPanelAnimationMap( className );
  1612. if ( map )
  1613. {
  1614. PanelAnimationDumpMap( map, true );
  1615. }
  1616. else
  1617. {
  1618. Msg( "No such Panel Animation class %s\n", className );
  1619. }
  1620. }
  1621. }
  1622. //-----------------------------------------------------------------------------
  1623. // Purpose: singleton accessor
  1624. //-----------------------------------------------------------------------------
  1625. CPanelAnimationDictionary& GetPanelAnimationDictionary()
  1626. {
  1627. static CPanelAnimationDictionary dictionary;
  1628. return dictionary;
  1629. }
  1630. //-----------------------------------------------------------------------------
  1631. // Purpose:
  1632. //-----------------------------------------------------------------------------
  1633. PanelAnimationMap *FindOrAddPanelAnimationMap( char const *className )
  1634. {
  1635. return GetPanelAnimationDictionary().FindOrAddPanelAnimationMap( className );
  1636. }
  1637. //-----------------------------------------------------------------------------
  1638. // Purpose: Find but don't add mapping
  1639. //-----------------------------------------------------------------------------
  1640. PanelAnimationMap *FindPanelAnimationMap( char const *className )
  1641. {
  1642. return GetPanelAnimationDictionary().FindPanelAnimationMap( className );
  1643. }
  1644. //-----------------------------------------------------------------------------
  1645. // Purpose:
  1646. //-----------------------------------------------------------------------------
  1647. void PanelAnimationDumpVars( char const *className )
  1648. {
  1649. GetPanelAnimationDictionary().PanelAnimationDumpVars( className );
  1650. }