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.

1655 lines
49 KiB

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