From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/vgui2/vgui_controls/AnimationController.cpp | 3300 ++++++++++---------- 1 file changed, 1650 insertions(+), 1650 deletions(-) (limited to 'mp/src/vgui2/vgui_controls/AnimationController.cpp') diff --git a/mp/src/vgui2/vgui_controls/AnimationController.cpp b/mp/src/vgui2/vgui_controls/AnimationController.cpp index a618231c..76a35250 100644 --- a/mp/src/vgui2/vgui_controls/AnimationController.cpp +++ b/mp/src/vgui2/vgui_controls/AnimationController.cpp @@ -1,1651 +1,1651 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//=============================================================================// -#pragma warning( disable : 4244 ) // conversion from 'double' to 'float', possible loss of data - -#include -#include -#include -#include -#include -#include -#include "filesystem.h" -#include "filesystem_helpers.h" - -#include -#include -#include "mempool.h" -#include "utldict.h" -#include "mathlib/mathlib.h" -#include "characterset.h" - -// memdbgon must be the last include file in a .cpp file!!! -#include -// for SRC -#include -#include - -using namespace vgui; - -static CUtlSymbolTable g_ScriptSymbols(0, 128, true); - -// singleton accessor for animation controller for use by the vgui controls -namespace vgui -{ -AnimationController *GetAnimationController() -{ - static AnimationController *s_pAnimationController = new AnimationController(NULL); - return s_pAnimationController; -} -} - -//----------------------------------------------------------------------------- -// Purpose: Constructor -//----------------------------------------------------------------------------- -AnimationController::AnimationController(Panel *parent) : BaseClass(parent, NULL) -{ - m_hSizePanel = 0; - m_nScreenBounds[ 0 ] = m_nScreenBounds[ 1 ] = -1; - m_nScreenBounds[ 2 ] = m_nScreenBounds[ 3 ] = -1; - - m_bAutoReloadScript = false; - - // always invisible - SetVisible(false); - - SetProportional(true); - - // get the names of common types - m_sPosition = g_ScriptSymbols.AddString("position"); - m_sSize = g_ScriptSymbols.AddString("size"); - m_sFgColor = g_ScriptSymbols.AddString("fgcolor"); - m_sBgColor = g_ScriptSymbols.AddString("bgcolor"); - - m_sXPos = g_ScriptSymbols.AddString("xpos"); - m_sYPos = g_ScriptSymbols.AddString("ypos"); - m_sWide = g_ScriptSymbols.AddString("wide"); - m_sTall = g_ScriptSymbols.AddString("tall"); - - m_flCurrentTime = 0.0f; -} - -//----------------------------------------------------------------------------- -// Purpose: Destructor -//----------------------------------------------------------------------------- -AnimationController::~AnimationController() -{ -} - -//----------------------------------------------------------------------------- -// Purpose: Sets which script file to use -//----------------------------------------------------------------------------- -bool AnimationController::SetScriptFile( VPANEL sizingPanel, const char *fileName, bool wipeAll /*=false*/ ) -{ - m_hSizePanel = sizingPanel; - - if ( wipeAll ) - { - // clear the current script - m_Sequences.RemoveAll(); - m_ScriptFileNames.RemoveAll(); - - CancelAllAnimations(); - } - - // Store off this filename for reloading later on (if we don't have it already) - UtlSymId_t sFilename = g_ScriptSymbols.AddString( fileName ); - if ( m_ScriptFileNames.Find( sFilename ) == m_ScriptFileNames.InvalidIndex() ) - { - m_ScriptFileNames.AddToTail( sFilename ); - } - - UpdateScreenSize(); - - // load the new script file - return LoadScriptFile( fileName ); -} - -//----------------------------------------------------------------------------- -// Purpose: reloads the currently set script file -//----------------------------------------------------------------------------- -void AnimationController::ReloadScriptFile() -{ - // Clear all current sequences - m_Sequences.RemoveAll(); - - UpdateScreenSize(); - - // Reload each file we've loaded - for ( int i = 0; i < m_ScriptFileNames.Count(); i++ ) - { - const char *lpszFilename = g_ScriptSymbols.String( m_ScriptFileNames[i] ); - if ( strlen( lpszFilename ) > 0) - { - if ( LoadScriptFile( lpszFilename ) == false ) - { - Assert( 0 ); - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: loads a script file from disk -//----------------------------------------------------------------------------- -bool AnimationController::LoadScriptFile(const char *fileName) -{ - FileHandle_t f = g_pFullFileSystem->Open(fileName, "rt"); - if (!f) - { - Warning("Couldn't find script file %s\n", fileName); - return false; - } - - // read the whole thing into memory - int size = g_pFullFileSystem->Size(f); - // read into temporary memory block - int nBufSize = size+1; - if ( IsXbox() ) - { - nBufSize = AlignValue( nBufSize, 512 ); - } - char *pMem = (char *)malloc(nBufSize); - int bytesRead = g_pFullFileSystem->ReadEx(pMem, nBufSize, size, f); - Assert(bytesRead <= size); - pMem[bytesRead] = 0; - g_pFullFileSystem->Close(f); - // parse - bool success = ParseScriptFile(pMem, bytesRead); - free(pMem); - return success; -} - -AnimationController::RelativeAlignmentLookup AnimationController::g_AlignmentLookup[] = -{ - { AnimationController::a_northwest , "northwest" }, - { AnimationController::a_north , "north" }, - { AnimationController::a_northeast , "northeast" }, - { AnimationController::a_west , "west" }, - { AnimationController::a_center , "center" }, - { AnimationController::a_east , "east" }, - { AnimationController::a_southwest , "southwest" }, - { AnimationController::a_south , "south" }, - { AnimationController::a_southeast , "southeast" }, - - { AnimationController::a_northwest , "nw" }, - { AnimationController::a_north , "n" }, - { AnimationController::a_northeast , "ne" }, - { AnimationController::a_west , "w" }, - { AnimationController::a_center , "c" }, - { AnimationController::a_east , "e" }, - { AnimationController::a_southwest , "sw" }, - { AnimationController::a_south , "s" }, - { AnimationController::a_southeast , "se" }, -}; - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -AnimationController::RelativeAlignment AnimationController::LookupAlignment( char const *token ) -{ - int c = ARRAYSIZE( g_AlignmentLookup ); - - for ( int i = 0; i < c; i++ ) - { - if ( !Q_stricmp( token, g_AlignmentLookup[ i ].name ) ) - { - return g_AlignmentLookup[ i ].align; - } - } - - return AnimationController::a_northwest; -} - -//----------------------------------------------------------------------------- -// Purpose: Parse position including right edge and center adjustment out of a -// token. This is relative to the screen -//----------------------------------------------------------------------------- -void AnimationController::SetupPosition( AnimCmdAnimate_t& cmd, float *output, char const *psz, int screendimension ) -{ - bool r = false, c = false; - int pos; - if ( psz[0] == '(' ) - { - psz++; - - if ( Q_strstr( psz, ")" ) ) - { - char sz[ 256 ]; - Q_strncpy( sz, psz, sizeof( sz ) ); - - char *colon = Q_strstr( sz, ":" ); - if ( colon ) - { - *colon = 0; - - RelativeAlignment ra = LookupAlignment( sz ); - - colon++; - - char *panelName = colon; - char *panelEnd = Q_strstr( panelName, ")" ); - if ( panelEnd ) - { - *panelEnd = 0; - - if ( Q_strlen( panelName ) > 0 ) - { - // - cmd.align.relativePosition = true; - cmd.align.alignPanel = g_ScriptSymbols.AddString(panelName); - cmd.align.alignment = ra; - } - } - } - - psz = Q_strstr( psz, ")" ) + 1; - } - } - else if (psz[0] == 'r' || psz[0] == 'R') - { - r = true; - psz++; - } - else if (psz[0] == 'c' || psz[0] == 'C') - { - c = true; - psz++; - } - - // get the number - pos = atoi(psz); - - // scale the values - if (IsProportional()) - { - pos = vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), pos ); - } - - // adjust the positions - if (r) - { - pos = screendimension - pos; - } - if (c) - { - pos = (screendimension / 2) + pos; - } - - // set the value - *output = static_cast( pos ); -} - - -//----------------------------------------------------------------------------- -// Purpose: parses a script into sequences -//----------------------------------------------------------------------------- -bool AnimationController::ParseScriptFile(char *pMem, int length) -{ - // get the scheme (for looking up color names) - IScheme *scheme = vgui::scheme()->GetIScheme(GetScheme()); - - // get our screen size (for left/right/center alignment) - int screenWide = m_nScreenBounds[ 2 ]; - int screenTall = m_nScreenBounds[ 3 ]; - - // start by getting the first token - char token[512]; - pMem = ParseFile(pMem, token, NULL); - while (token[0]) - { - bool bAccepted = true; - - // should be 'event' - if (stricmp(token, "event")) - { - Warning("Couldn't parse script file: expected 'event', found '%s'\n", token); - return false; - } - - // get the event name - pMem = ParseFile(pMem, token, NULL); - if (strlen(token) < 1) - { - Warning("Couldn't parse script file: expected , found nothing\n"); - return false; - } - - int seqIndex; - UtlSymId_t nameIndex = g_ScriptSymbols.AddString(token); - - // Create a new sequence - seqIndex = m_Sequences.AddToTail(); - AnimSequence_t &seq = m_Sequences[seqIndex]; - seq.name = nameIndex; - seq.duration = 0.0f; - - // get the open brace or a conditional - pMem = ParseFile(pMem, token, NULL); - if ( Q_stristr( token, "[$" ) ) - { - bAccepted = EvaluateConditional( token ); - - // now get the open brace - pMem = ParseFile(pMem, token, NULL); - } - - if (stricmp(token, "{")) - { - Warning("Couldn't parse script sequence '%s': expected '{', found '%s'\n", g_ScriptSymbols.String(seq.name), token); - return false; - } - - // walk the commands - while (token && token[0]) - { - // get the command type - pMem = ParseFile(pMem, token, NULL); - - // skip out when we hit the end of the sequence - if (token[0] == '}') - break; - - // create a new command - int cmdIndex = seq.cmdList.AddToTail(); - AnimCommand_t &animCmd = seq.cmdList[cmdIndex]; - memset(&animCmd, 0, sizeof(animCmd)); - if (!stricmp(token, "animate")) - { - animCmd.commandType = CMD_ANIMATE; - // parse out the animation commands - AnimCmdAnimate_t &cmdAnimate = animCmd.cmdData.animate; - // panel to manipulate - pMem = ParseFile(pMem, token, NULL); - cmdAnimate.panel = g_ScriptSymbols.AddString(token); - // variable to change - pMem = ParseFile(pMem, token, NULL); - cmdAnimate.variable = g_ScriptSymbols.AddString(token); - // target value - pMem = ParseFile(pMem, token, NULL); - if (cmdAnimate.variable == m_sPosition) - { - // Get first token - SetupPosition( cmdAnimate, &cmdAnimate.target.a, token, screenWide ); - - // Get second token from "token" - char token2[32]; - char *psz = ParseFile(token, token2, NULL); - psz = ParseFile(psz, token2, NULL); - psz = token2; - - // Position Y goes into ".b" - SetupPosition( cmdAnimate, &cmdAnimate.target.b, psz, screenTall ); - } - else if ( cmdAnimate.variable == m_sXPos ) - { - // XPos and YPos both use target ".a" - SetupPosition( cmdAnimate, &cmdAnimate.target.a, token, screenWide ); - } - else if ( cmdAnimate.variable == m_sYPos ) - { - // XPos and YPos both use target ".a" - SetupPosition( cmdAnimate, &cmdAnimate.target.a, token, screenTall ); - } - else - { - // parse the floating point values right out - if (0 == sscanf(token, "%f %f %f %f", &cmdAnimate.target.a, &cmdAnimate.target.b, &cmdAnimate.target.c, &cmdAnimate.target.d)) - { - //============================================================================= - // HPE_BEGIN: - // [pfreese] Improved handling colors not defined in scheme - //============================================================================= - - // could be referencing a value in the scheme file, lookup - Color default_invisible_black(0, 0, 0, 0); - Color col = scheme->GetColor(token, default_invisible_black); - - // we don't have a way of seeing if the color is not declared in the scheme, so we use this - // silly method of trying again with a different default to see if we get the fallback again - if (col == default_invisible_black) - { - Color error_pink(255, 0, 255, 255); // make it extremely obvious if a scheme lookup fails - col = scheme->GetColor(token, error_pink); - - // commented out for Soldier/Demo release...(getting spammed in console) - // we'll try to figure this out after the update is out -// if (col == error_pink) -// { -// Warning("Missing color in scheme: %s\n", token); -// } - } - - //============================================================================= - // HPE_END - //============================================================================= - - cmdAnimate.target.a = col[0]; - cmdAnimate.target.b = col[1]; - cmdAnimate.target.c = col[2]; - cmdAnimate.target.d = col[3]; - } - } - - // fix up scale - if (cmdAnimate.variable == m_sSize) - { - if (IsProportional()) - { - cmdAnimate.target.a = static_cast( vgui::scheme()->GetProportionalScaledValueEx(GetScheme(), cmdAnimate.target.a) ); - cmdAnimate.target.b = static_cast( vgui::scheme()->GetProportionalScaledValueEx(GetScheme(), cmdAnimate.target.b) ); - } - } - else if (cmdAnimate.variable == m_sWide || - cmdAnimate.variable == m_sTall ) - { - if (IsProportional()) - { - // Wide and tall both use.a - cmdAnimate.target.a = static_cast( vgui::scheme()->GetProportionalScaledValueEx(GetScheme(), cmdAnimate.target.a) ); - } - } - - // interpolation function - pMem = ParseFile(pMem, token, NULL); - if (!stricmp(token, "Accel")) - { - cmdAnimate.interpolationFunction = INTERPOLATOR_ACCEL; - } - else if (!stricmp(token, "Deaccel")) - { - cmdAnimate.interpolationFunction = INTERPOLATOR_DEACCEL; - } - else if ( !stricmp(token, "Spline")) - { - cmdAnimate.interpolationFunction = INTERPOLATOR_SIMPLESPLINE; - } - else if (!stricmp(token,"Pulse")) - { - cmdAnimate.interpolationFunction = INTERPOLATOR_PULSE; - // frequencey - pMem = ParseFile(pMem, token, NULL); - cmdAnimate.interpolationParameter = (float)atof(token); - } - else if ( !stricmp( token, "Flicker")) - { - cmdAnimate.interpolationFunction = INTERPOLATOR_FLICKER; - // noiseamount - pMem = ParseFile(pMem, token, NULL); - cmdAnimate.interpolationParameter = (float)atof(token); - } - else if (!stricmp(token, "Bounce")) - { - cmdAnimate.interpolationFunction = INTERPOLATOR_BOUNCE; - } - else - { - cmdAnimate.interpolationFunction = INTERPOLATOR_LINEAR; - } - // start time - pMem = ParseFile(pMem, token, NULL); - cmdAnimate.startTime = (float)atof(token); - // duration - pMem = ParseFile(pMem, token, NULL); - cmdAnimate.duration = (float)atof(token); - // check max duration - if (cmdAnimate.startTime + cmdAnimate.duration > seq.duration) - { - seq.duration = cmdAnimate.startTime + cmdAnimate.duration; - } - } - else if (!stricmp(token, "runevent")) - { - animCmd.commandType = CMD_RUNEVENT; - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token); - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.timeDelay = (float)atof(token); - } - else if (!stricmp(token, "stopevent")) - { - animCmd.commandType = CMD_STOPEVENT; - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token); - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.timeDelay = (float)atof(token); - } - else if (!stricmp(token, "StopPanelAnimations")) - { - animCmd.commandType = CMD_STOPPANELANIMATIONS; - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token); - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.timeDelay = (float)atof(token); - } - else if (!stricmp(token, "stopanimation")) - { - animCmd.commandType = CMD_STOPANIMATION; - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token); - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token); - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.timeDelay = (float)atof(token); - } - else if ( !stricmp( token, "SetFont" )) - { - animCmd.commandType = CMD_SETFONT; - // Panel name - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token); - // Font parameter - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token); - // Font name from scheme - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.variable2 = g_ScriptSymbols.AddString(token); - - // Set time - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.timeDelay = (float)atof(token); - } - else if ( !stricmp( token, "SetTexture" )) - { - animCmd.commandType = CMD_SETTEXTURE; - // Panel name - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token); - // Texture Id - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token); - // material name - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.variable2 = g_ScriptSymbols.AddString(token); - - // Set time - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.timeDelay = (float)atof(token); - } - else if ( !stricmp( token, "SetString" )) - { - animCmd.commandType = CMD_SETSTRING; - // Panel name - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token); - // String variable name - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token); - // String value to set - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.variable2 = g_ScriptSymbols.AddString(token); - - // Set time - pMem = ParseFile(pMem, token, NULL); - animCmd.cmdData.runEvent.timeDelay = (float)atof(token); - } - else - { - Warning("Couldn't parse script sequence '%s': expected , found '%s'\n", g_ScriptSymbols.String(seq.name), token); - return false; - } - - // Look ahead one token for a conditional - char *peek = ParseFile(pMem, token, NULL); - if ( Q_stristr( token, "[$" ) ) - { - if ( !EvaluateConditional( token ) ) - { - seq.cmdList.Remove( cmdIndex ); - } - pMem = peek; - } - } - - if ( bAccepted ) - { - // Attempt to find a collision in the sequences, replacing the old one if found - int seqIterator; - for ( seqIterator = 0; seqIterator < m_Sequences.Count()-1; seqIterator++ ) - { - if ( m_Sequences[seqIterator].name == nameIndex ) - { - // Get rid of it, we're overriding it - m_Sequences.Remove( seqIndex ); - break; - } - } - } - else - { - // Dump the entire sequence - m_Sequences.Remove( seqIndex ); - } - - // get the next token, if any - pMem = ParseFile(pMem, token, NULL); - } - - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: checks all posted animation events, firing if time -//----------------------------------------------------------------------------- -void AnimationController::UpdatePostedMessages(bool bRunToCompletion) -{ - CUtlVector eventsRanThisFrame; - - // check all posted messages - for (int i = 0; i < m_PostedMessages.Count(); i++) - { - PostedMessage_t &msgRef = m_PostedMessages[i]; - if (m_flCurrentTime < msgRef.startTime && !bRunToCompletion) - continue; - - // take a copy of th message - PostedMessage_t msg = msgRef; - - // remove the event - // do this before handling the message because the message queue may be messed with - m_PostedMessages.Remove(i); - // reset the count, start the whole queue again - i = -1; - - // handle the event - switch (msg.commandType) - { - case CMD_RUNEVENT: - { - RanEvent_t curEvent; - curEvent.event = msg.event; - curEvent.pParent = msg.parent.Get(); - - // run the event, but only if we haven't already run it this frame, for this parent - if (!eventsRanThisFrame.HasElement(curEvent)) - { - eventsRanThisFrame.AddToTail(curEvent); - RunCmd_RunEvent(msg); - } - } - break; - case CMD_STOPEVENT: - RunCmd_StopEvent(msg); - break; - case CMD_STOPPANELANIMATIONS: - RunCmd_StopPanelAnimations(msg); - break; - case CMD_STOPANIMATION: - RunCmd_StopAnimation(msg); - break; - case CMD_SETFONT: - RunCmd_SetFont(msg); - break; - case CMD_SETTEXTURE: - RunCmd_SetTexture(msg); - break; - case CMD_SETSTRING: - RunCmd_SetString( msg ); - break; - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: runs the current animations -//----------------------------------------------------------------------------- -void AnimationController::UpdateActiveAnimations(bool bRunToCompletion) -{ - // iterate all the currently active animations - for (int i = 0; i < m_ActiveAnimations.Count(); i++) - { - ActiveAnimation_t &anim = m_ActiveAnimations[i]; - - // see if the anim is ready to start - if (m_flCurrentTime < anim.startTime && !bRunToCompletion) - continue; - - if (!anim.panel.Get()) - { - // panel is gone, remove the animation - m_ActiveAnimations.Remove(i); - --i; - continue; - } - - if (!anim.started && !bRunToCompletion) - { - // start the animation from the current value - anim.startValue = GetValue(anim, anim.panel, anim.variable); - anim.started = true; - - // 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()); - } - - // get the interpolated value - Value_t val; - if (m_flCurrentTime >= anim.endTime || bRunToCompletion) - { - // animation is done, use the last value - val = anim.endValue; - } - else - { - // get the interpolated value - val = GetInterpolatedValue(anim.interpolator, anim.interpolatorParam, m_flCurrentTime, anim.startTime, anim.endTime, anim.startValue, anim.endValue); - } - - // apply the new value to the panel - SetValue(anim, anim.panel, anim.variable, val); - - // Msg( "Animate value: %s => %.2f for panel '%s'\n", g_ScriptSymbols.String(anim.variable), val.a, anim.panel->GetName()); - - // see if we can remove the animation - if (m_flCurrentTime >= anim.endTime || bRunToCompletion) - { - m_ActiveAnimations.Remove(i); - --i; - } - } -} - -bool AnimationController::UpdateScreenSize() -{ - // get our screen size (for left/right/center alignment) - int screenWide, screenTall; - int sx = 0, sy = 0; - if ( m_hSizePanel != 0 ) - { - ipanel()->GetSize( m_hSizePanel, screenWide, screenTall ); - ipanel()->GetPos( m_hSizePanel, sx, sy ); - } - else - { - surface()->GetScreenSize(screenWide, screenTall); - } - - bool changed = m_nScreenBounds[ 0 ] != sx || - m_nScreenBounds[ 1 ] != sy || - m_nScreenBounds[ 2 ] != screenWide || - m_nScreenBounds[ 3 ] != screenTall; - - m_nScreenBounds[ 0 ] = sx; - m_nScreenBounds[ 1 ] = sy; - m_nScreenBounds[ 2 ] = screenWide; - m_nScreenBounds[ 3 ] = screenTall; - - return changed; -} -//----------------------------------------------------------------------------- -// Purpose: runs a frame of animation -//----------------------------------------------------------------------------- -void AnimationController::UpdateAnimations( float currentTime ) -{ - m_flCurrentTime = currentTime; - - if ( UpdateScreenSize() && m_ScriptFileNames.Count() ) - { - RunAllAnimationsToCompletion(); - ReloadScriptFile(); - } - - UpdatePostedMessages(false); - UpdateActiveAnimations(false); -} - -//----------------------------------------------------------------------------- -// Purpose: plays all animations to completion instantly -//----------------------------------------------------------------------------- -void AnimationController::RunAllAnimationsToCompletion() -{ - // Msg( "AnimationController::RunAllAnimationsToCompletion()\n" ); - UpdatePostedMessages(true); - UpdateActiveAnimations(true); -} - -//----------------------------------------------------------------------------- -// Purpose: Stops all current animations -//----------------------------------------------------------------------------- -void AnimationController::CancelAllAnimations() -{ - // Msg( "AnimationController::CancelAllAnimations()\n" ); - - m_ActiveAnimations.RemoveAll(); - m_PostedMessages.RemoveAll(); -} - -//----------------------------------------------------------------------------- -// Purpose: produces an interpolated value -//----------------------------------------------------------------------------- -AnimationController::Value_t AnimationController::GetInterpolatedValue(int interpolator, float interpolatorParam, float currentTime, float startTime, float endTime, Value_t &startValue, Value_t &endValue) -{ - // calculate how far we are into the animation - float pos = (currentTime - startTime) / (endTime - startTime); - - // adjust the percentage through by the interpolation function - switch (interpolator) - { - case INTERPOLATOR_ACCEL: - pos *= pos; - break; - case INTERPOLATOR_DEACCEL: - pos = sqrtf(pos); - break; - case INTERPOLATOR_SIMPLESPLINE: - pos = SimpleSpline( pos ); - break; - case INTERPOLATOR_PULSE: - // Make sure we end at 1.0, so use cosine - pos = 0.5f + 0.5f * ( cos( pos * 2.0f * M_PI * interpolatorParam ) ); - break; - case INTERPOLATOR_FLICKER: - if ( RandomFloat( 0.0f, 1.0f ) < interpolatorParam ) - { - pos = 1.0f; - } - else - { - pos = 0.0f; - } - break; - case INTERPOLATOR_BOUNCE: - { - // fall from startValue to endValue, bouncing a few times and settling out at endValue - const float hit1 = 0.33f; - const float hit2 = 0.67f; - const float hit3 = 1.0f; - - if ( pos < hit1 ) - { - pos = 1.0f - sin( M_PI * pos / hit1 ); - } - else if ( pos < hit2 ) - { - pos = 0.5f + 0.5f * ( 1.0f - sin( M_PI * ( pos - hit1 ) / ( hit2 - hit1 ) ) ); - } - else - { - pos = 0.8f + 0.2f * ( 1.0f - sin( M_PI * ( pos - hit2 ) / ( hit3 - hit2 ) ) ); - } - break; - } - case INTERPOLATOR_LINEAR: - default: - break; - } - - // calculate the value - Value_t val; - val.a = ((endValue.a - startValue.a) * pos) + startValue.a; - val.b = ((endValue.b - startValue.b) * pos) + startValue.b; - val.c = ((endValue.c - startValue.c) * pos) + startValue.c; - val.d = ((endValue.d - startValue.d) * pos) + startValue.d; - return val; -} - -//----------------------------------------------------------------------------- -// Purpose: sets that the script file should be reloaded each time a script is ran -// used for development -//----------------------------------------------------------------------------- -void AnimationController::SetAutoReloadScript(bool state) -{ - m_bAutoReloadScript = state; -} - -//----------------------------------------------------------------------------- -// Purpose: starts an animation sequence script -//----------------------------------------------------------------------------- -bool AnimationController::StartAnimationSequence(const char *sequenceName) -{ - // We support calling an animation on elements that are not the calling - // panel's children. Use the base parent to start the search. - - return StartAnimationSequence( GetParent(), sequenceName ); -} - -//----------------------------------------------------------------------------- -// Purpose: starts an animation sequence script -//----------------------------------------------------------------------------- -bool AnimationController::StartAnimationSequence(Panel *pWithinParent, const char *sequenceName) -{ - Assert( pWithinParent ); - - if (m_bAutoReloadScript) - { - // Reload the script files - ReloadScriptFile(); - } - - // lookup the symbol for the name - UtlSymId_t seqName = g_ScriptSymbols.Find(sequenceName); - if (seqName == UTL_INVAL_SYMBOL) - return false; - - // Msg("Starting animation sequence %s\n", sequenceName); - - // remove the existing command from the queue - RemoveQueuedAnimationCommands(seqName, pWithinParent); - - // look through for the sequence - int i; - for (i = 0; i < m_Sequences.Count(); i++) - { - if (m_Sequences[i].name == seqName) - break; - } - if (i >= m_Sequences.Count()) - return false; - - // execute the sequence - for (int cmdIndex = 0; cmdIndex < m_Sequences[i].cmdList.Count(); cmdIndex++) - { - ExecAnimationCommand(seqName, m_Sequences[i].cmdList[cmdIndex], pWithinParent); - } - - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: Runs a custom command from code, not from a script file -//----------------------------------------------------------------------------- -void AnimationController::RunAnimationCommand(vgui::Panel *panel, const char *variable, float targetValue, float startDelaySeconds, float duration, Interpolators_e interpolator, float animParameter /* = 0 */ ) -{ - // clear any previous animations of this variable - UtlSymId_t var = g_ScriptSymbols.AddString(variable); - RemoveQueuedAnimationByType(panel, var, UTL_INVAL_SYMBOL); - - // build a new animation - AnimCmdAnimate_t animateCmd; - memset(&animateCmd, 0, sizeof(animateCmd)); - animateCmd.panel = 0; - animateCmd.variable = var; - animateCmd.target.a = targetValue; - animateCmd.interpolationFunction = interpolator; - animateCmd.interpolationParameter = animParameter; - animateCmd.startTime = startDelaySeconds; - animateCmd.duration = duration; - - // start immediately - StartCmd_Animate(panel, 0, animateCmd); -} - -//----------------------------------------------------------------------------- -// Purpose: Runs a custom command from code, not from a script file -//----------------------------------------------------------------------------- -void AnimationController::RunAnimationCommand(vgui::Panel *panel, const char *variable, Color targetValue, float startDelaySeconds, float duration, Interpolators_e interpolator, float animParameter /* = 0 */ ) -{ - // clear any previous animations of this variable - UtlSymId_t var = g_ScriptSymbols.AddString(variable); - RemoveQueuedAnimationByType(panel, var, UTL_INVAL_SYMBOL); - - // build a new animation - AnimCmdAnimate_t animateCmd; - memset(&animateCmd, 0, sizeof(animateCmd)); - animateCmd.panel = 0; - animateCmd.variable = var; - animateCmd.target.a = targetValue[0]; - animateCmd.target.b = targetValue[1]; - animateCmd.target.c = targetValue[2]; - animateCmd.target.d = targetValue[3]; - animateCmd.interpolationFunction = interpolator; - animateCmd.interpolationParameter = animParameter; - animateCmd.startTime = startDelaySeconds; - animateCmd.duration = duration; - - // start immediately - StartCmd_Animate(panel, 0, animateCmd); -} - -//----------------------------------------------------------------------------- -// Purpose: gets the length of an animation sequence, in seconds -//----------------------------------------------------------------------------- -float AnimationController::GetAnimationSequenceLength(const char *sequenceName) -{ - // lookup the symbol for the name - UtlSymId_t seqName = g_ScriptSymbols.Find(sequenceName); - if (seqName == UTL_INVAL_SYMBOL) - return 0.0f; - - // look through for the sequence - int i; - for (i = 0; i < m_Sequences.Count(); i++) - { - if (m_Sequences[i].name == seqName) - break; - } - if (i >= m_Sequences.Count()) - return 0.0f; - - // sequence found - return m_Sequences[i].duration; -} - -//----------------------------------------------------------------------------- -// Purpose: removes an existing set of commands from the queue -//----------------------------------------------------------------------------- -void AnimationController::RemoveQueuedAnimationCommands(UtlSymId_t seqName, Panel *pWithinParent) -{ - // Msg("Removing queued anims for sequence %s\n", g_ScriptSymbols.String(seqName)); - - // remove messages posted by this sequence - // if pWithinParent is specified, remove only messages under that parent - {for (int i = 0; i < m_PostedMessages.Count(); i++) - { - if ( ( m_PostedMessages[i].seqName == seqName ) && - ( !pWithinParent || ( m_PostedMessages[i].parent == pWithinParent ) ) ) - { - m_PostedMessages.Remove(i); - --i; - } - }} - - // remove all animations - // if pWithinParent is specified, remove only animations under that parent - for (int i = 0; i < m_ActiveAnimations.Count(); i++) - { - if ( m_ActiveAnimations[i].seqName != seqName ) - continue; - - // panel this anim is on, m_ActiveAnimations[i].panel - if ( pWithinParent ) - { - Panel *animPanel = m_ActiveAnimations[i].panel; - - if ( !animPanel ) - continue; - - Panel *foundPanel = pWithinParent->FindChildByName(animPanel->GetName(),true); - - if ( foundPanel != animPanel ) - continue; - } - - m_ActiveAnimations.Remove(i); - --i; - } -} - -//----------------------------------------------------------------------------- -// Purpose: removes the specified queued animation -//----------------------------------------------------------------------------- -void AnimationController::RemoveQueuedAnimationByType(vgui::Panel *panel, UtlSymId_t variable, UtlSymId_t sequenceToIgnore) -{ - for (int i = 0; i < m_ActiveAnimations.Count(); i++) - { - if (m_ActiveAnimations[i].panel == panel && m_ActiveAnimations[i].variable == variable && m_ActiveAnimations[i].seqName != sequenceToIgnore) - { - // Msg("Removing queued anim %s::%s::%s\n", g_ScriptSymbols.String(m_ActiveAnimations[i].seqName), panel->GetName(), g_ScriptSymbols.String(variable)); - m_ActiveAnimations.Remove(i); - break; - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: runs a single line of the script -//----------------------------------------------------------------------------- -void AnimationController::ExecAnimationCommand(UtlSymId_t seqName, AnimCommand_t &animCommand, Panel *pWithinParent) -{ - if (animCommand.commandType == CMD_ANIMATE) - { - StartCmd_Animate(seqName, animCommand.cmdData.animate, pWithinParent); - } - else - { - // post the command to happen at the specified time - PostedMessage_t &msg = m_PostedMessages[m_PostedMessages.AddToTail()]; - msg.seqName = seqName; - msg.commandType = animCommand.commandType; - msg.event = animCommand.cmdData.runEvent.event; - msg.variable = animCommand.cmdData.runEvent.variable; - msg.variable2 = animCommand.cmdData.runEvent.variable2; - msg.startTime = m_flCurrentTime + animCommand.cmdData.runEvent.timeDelay; - msg.parent = pWithinParent; - } -} - -//----------------------------------------------------------------------------- -// Purpose: starts a variable animation -//----------------------------------------------------------------------------- -void AnimationController::StartCmd_Animate(UtlSymId_t seqName, AnimCmdAnimate_t &cmd, Panel *pWithinParent) -{ - Assert( pWithinParent ); - if ( !pWithinParent ) - return; - - // make sure the child exists - Panel *panel = pWithinParent->FindChildByName(g_ScriptSymbols.String(cmd.panel),true); - if ( !panel ) - { - // Check the parent - Panel *parent = GetParent(); - if ( !Q_stricmp( parent->GetName(), g_ScriptSymbols.String(cmd.panel) ) ) - { - panel = parent; - } - } - if (!panel) - return; - - StartCmd_Animate(panel, seqName, cmd); -} - -//----------------------------------------------------------------------------- -// Purpose: Starts an animation command for the specified panel -//----------------------------------------------------------------------------- -void AnimationController::StartCmd_Animate(Panel *panel, UtlSymId_t seqName, AnimCmdAnimate_t &cmd) -{ - // build a command to add to the animation queue - ActiveAnimation_t &anim = m_ActiveAnimations[m_ActiveAnimations.AddToTail()]; - anim.panel = panel; - anim.seqName = seqName; - anim.variable = cmd.variable; - anim.interpolator = cmd.interpolationFunction; - anim.interpolatorParam = cmd.interpolationParameter; - // timings - anim.startTime = m_flCurrentTime + cmd.startTime; - anim.endTime = anim.startTime + cmd.duration; - // values - anim.started = false; - anim.endValue = cmd.target; - - anim.align = cmd.align; -} - -//----------------------------------------------------------------------------- -// Purpose: a posted message to run another event -//----------------------------------------------------------------------------- -void AnimationController::RunCmd_RunEvent(PostedMessage_t &msg) -{ - StartAnimationSequence(msg.parent.Get(), g_ScriptSymbols.String(msg.event)); -} - -//----------------------------------------------------------------------------- -// Purpose: a posted message to stop another event -//----------------------------------------------------------------------------- -void AnimationController::RunCmd_StopEvent(PostedMessage_t &msg) -{ - RemoveQueuedAnimationCommands(msg.event, msg.parent); -} - -//----------------------------------------------------------------------------- -// Purpose: a posted message to stop all animations relevant to a specified panel -//----------------------------------------------------------------------------- -void AnimationController::RunCmd_StopPanelAnimations(PostedMessage_t &msg) -{ - Panel *panel = FindSiblingByName(g_ScriptSymbols.String(msg.event)); - Assert(panel != NULL); - if (!panel) - return; - - // loop through all the active animations cancelling any that - // are operating on said panel, except for the event specified - for (int i = 0; i < m_ActiveAnimations.Count(); i++) - { - if (m_ActiveAnimations[i].panel == panel && m_ActiveAnimations[i].seqName != msg.seqName) - { - m_ActiveAnimations.Remove(i); - --i; - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: a posted message to stop animations of a specific type -//----------------------------------------------------------------------------- -void AnimationController::RunCmd_StopAnimation(PostedMessage_t &msg) -{ - Panel *panel = FindSiblingByName(g_ScriptSymbols.String(msg.event)); - Assert(panel != NULL); - if (!panel) - return; - - RemoveQueuedAnimationByType(panel, msg.variable, msg.seqName); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void AnimationController::RunCmd_SetFont( PostedMessage_t &msg ) -{ - Panel *parent = msg.parent.Get(); - - if ( !parent ) - { - parent = GetParent(); - } - - Panel *panel = parent->FindChildByName(g_ScriptSymbols.String(msg.event), true); - Assert(panel != NULL); - if (!panel) - return; - - KeyValues *inputData = new KeyValues(g_ScriptSymbols.String(msg.variable)); - inputData->SetString(g_ScriptSymbols.String(msg.variable), g_ScriptSymbols.String(msg.variable2)); - if (!panel->SetInfo(inputData)) - { - // Assert(!("Unhandlable var in AnimationController::SetValue())")); - } - inputData->deleteThis(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void AnimationController::RunCmd_SetTexture( PostedMessage_t &msg ) -{ - Panel *panel = FindSiblingByName(g_ScriptSymbols.String(msg.event)); - Assert(panel != NULL); - if (!panel) - return; - - KeyValues *inputData = new KeyValues(g_ScriptSymbols.String(msg.variable)); - inputData->SetString(g_ScriptSymbols.String(msg.variable), g_ScriptSymbols.String(msg.variable2)); - if (!panel->SetInfo(inputData)) - { - // Assert(!("Unhandlable var in AnimationController::SetValue())")); - } - inputData->deleteThis(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void AnimationController::RunCmd_SetString( PostedMessage_t &msg ) -{ - Panel *panel = FindSiblingByName(g_ScriptSymbols.String(msg.event)); - Assert(panel != NULL); - if (!panel) - return; - - KeyValues *inputData = new KeyValues(g_ScriptSymbols.String(msg.variable)); - inputData->SetString(g_ScriptSymbols.String(msg.variable), g_ScriptSymbols.String(msg.variable2)); - if (!panel->SetInfo(inputData)) - { - // Assert(!("Unhandlable var in AnimationController::SetValue())")); - } - inputData->deleteThis(); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -int AnimationController::GetRelativeOffset( AnimAlign_t& align, bool xcoord ) -{ - if ( !align.relativePosition ) - return 0; - - Panel *panel = GetParent()->FindChildByName(g_ScriptSymbols.String(align.alignPanel), true); - if ( !panel ) - return 0; - - int x, y, w, h; - panel->GetBounds( x, y, w, h ); - - int offset =0; - switch ( align.alignment ) - { - default: - case a_northwest: - offset = xcoord ? x : y; - break; - case a_north: - offset = xcoord ? ( x + w ) / 2 : y; - break; - case a_northeast: - offset = xcoord ? ( x + w ) : y; - break; - case a_west: - offset = xcoord ? x : ( y + h ) / 2; - break; - case a_center: - offset = xcoord ? ( x + w ) / 2 : ( y + h ) / 2; - break; - case a_east: - offset = xcoord ? ( x + w ) : ( y + h ) / 2; - break; - case a_southwest: - offset = xcoord ? x : ( y + h ); - break; - case a_south: - offset = xcoord ? ( x + w ) / 2 : ( y + h ); - break; - case a_southeast: - offset = xcoord ? ( x + w ) : ( y + h ); - break; - } - - return offset; -} - -//----------------------------------------------------------------------------- -// Purpose: Gets the specified value from a panel -//----------------------------------------------------------------------------- -AnimationController::Value_t AnimationController::GetValue(ActiveAnimation_t& anim, Panel *panel, UtlSymId_t var) -{ - Value_t val = { 0, 0, 0, 0 }; - if (var == m_sPosition) - { - int x, y; - panel->GetPos(x, y); - val.a = (float)(x - GetRelativeOffset( anim.align, true ) ); - val.b = (float)(y - GetRelativeOffset( anim.align, false ) ); - } - else if (var == m_sSize) - { - int w, t; - panel->GetSize(w, t); - val.a = (float)w; - val.b = (float)t; - } - else if (var == m_sFgColor) - { - Color col = panel->GetFgColor(); - val.a = col[0]; - val.b = col[1]; - val.c = col[2]; - val.d = col[3]; - } - else if (var == m_sBgColor) - { - Color col = panel->GetBgColor(); - val.a = col[0]; - val.b = col[1]; - val.c = col[2]; - val.d = col[3]; - } - else if ( var == m_sXPos ) - { - int x, y; - panel->GetPos(x, y); - val.a = (float)( x - GetRelativeOffset( anim.align, true ) ); - } - else if ( var == m_sYPos ) - { - int x, y; - panel->GetPos(x, y); - val.a = (float)( y - GetRelativeOffset( anim.align, false ) ); - } - else if ( var == m_sWide ) - { - int w, h; - panel->GetSize(w, h); - val.a = (float)w; - } - else if ( var == m_sTall ) - { - int w, h; - panel->GetSize(w, h); - val.a = (float)h; - } - else - { - KeyValues *outputData = new KeyValues(g_ScriptSymbols.String(var)); - if (panel->RequestInfo(outputData)) - { - // find the var and lookup it's type - KeyValues *kv = outputData->FindKey(g_ScriptSymbols.String(var)); - if (kv && kv->GetDataType() == KeyValues::TYPE_FLOAT) - { - val.a = kv->GetFloat(); - val.b = 0.0f; - val.c = 0.0f; - val.d = 0.0f; - } - else if (kv && kv->GetDataType() == KeyValues::TYPE_COLOR) - { - Color col = kv->GetColor(); - val.a = col[0]; - val.b = col[1]; - val.c = col[2]; - val.d = col[3]; - } - } - else - { - // Assert(!("Unhandlable var in AnimationController::GetValue())")); - } - outputData->deleteThis(); - } - return val; -} - -//----------------------------------------------------------------------------- -// Purpose: Sets a value in a panel -//----------------------------------------------------------------------------- -void AnimationController::SetValue(ActiveAnimation_t& anim, Panel *panel, UtlSymId_t var, Value_t &value) -{ - if (var == m_sPosition) - { - int x = (int)value.a + GetRelativeOffset( anim.align, true ); - int y = (int)value.b + GetRelativeOffset( anim.align, false ); - panel->SetPos(x, y); - } - else if (var == m_sSize) - { - panel->SetSize((int)value.a, (int)value.b); - } - else if (var == m_sFgColor) - { - Color col = panel->GetFgColor(); - col[0] = (unsigned char)value.a; - col[1] = (unsigned char)value.b; - col[2] = (unsigned char)value.c; - col[3] = (unsigned char)value.d; - panel->SetFgColor(col); - } - else if (var == m_sBgColor) - { - Color col = panel->GetBgColor(); - col[0] = (unsigned char)value.a; - col[1] = (unsigned char)value.b; - col[2] = (unsigned char)value.c; - col[3] = (unsigned char)value.d; - panel->SetBgColor(col); - } - else if (var == m_sXPos) - { - int newx = (int)value.a + GetRelativeOffset( anim.align, true ); - int x, y; - panel->GetPos( x, y ); - x = newx; - panel->SetPos(x, y); - } - else if (var == m_sYPos) - { - int newy = (int)value.a + GetRelativeOffset( anim.align, false ); - int x, y; - panel->GetPos( x, y ); - y = newy; - panel->SetPos(x, y); - } - else if (var == m_sWide) - { - int neww = (int)value.a; - int w, h; - panel->GetSize( w, h ); - w = neww; - panel->SetSize(w, h); - } - else if (var == m_sTall) - { - int newh = (int)value.a; - int w, h; - panel->GetSize( w, h ); - h = newh; - panel->SetSize(w, h); - } - else - { - KeyValues *inputData = new KeyValues(g_ScriptSymbols.String(var)); - // set the custom value - if (value.b == 0.0f && value.c == 0.0f && value.d == 0.0f) - { - // only the first value is non-zero, so probably just a float value - inputData->SetFloat(g_ScriptSymbols.String(var), value.a); - } - else - { - // multivalue, set the color - Color col((unsigned char)value.a, (unsigned char)value.b, (unsigned char)value.c, (unsigned char)value.d); - inputData->SetColor(g_ScriptSymbols.String(var), col); - } - if (!panel->SetInfo(inputData)) - { - // Assert(!("Unhandlable var in AnimationController::SetValue())")); - } - inputData->deleteThis(); - } -} -// Hooks between panels and animation controller system - -class CPanelAnimationDictionary -{ -public: - CPanelAnimationDictionary() : m_PanelAnimationMapPool( 32 ) - { - } - - ~CPanelAnimationDictionary() - { - m_PanelAnimationMapPool.Clear(); - } - - PanelAnimationMap *FindOrAddPanelAnimationMap( char const *className ); - PanelAnimationMap *FindPanelAnimationMap( char const *className ); - void PanelAnimationDumpVars( char const *className ); -private: - - struct PanelAnimationMapDictionaryEntry - { - PanelAnimationMap *map; - }; - - char const *StripNamespace( char const *className ); - void PanelAnimationDumpMap( PanelAnimationMap *map, bool recursive ); - - CClassMemoryPool< PanelAnimationMap > m_PanelAnimationMapPool; - CUtlDict< PanelAnimationMapDictionaryEntry, int > m_AnimationMaps; -}; - - -char const *CPanelAnimationDictionary::StripNamespace( char const *className ) -{ - if ( !Q_strnicmp( className, "vgui::", 6 ) ) - { - return className + 6; - } - return className; -} - -//----------------------------------------------------------------------------- -// Purpose: Find but don't add mapping -//----------------------------------------------------------------------------- -PanelAnimationMap *CPanelAnimationDictionary::FindPanelAnimationMap( char const *className ) -{ - int lookup = m_AnimationMaps.Find( StripNamespace( className ) ); - if ( lookup != m_AnimationMaps.InvalidIndex() ) - { - return m_AnimationMaps[ lookup ].map; - } - return NULL; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -PanelAnimationMap *CPanelAnimationDictionary::FindOrAddPanelAnimationMap( char const *className ) -{ - PanelAnimationMap *map = FindPanelAnimationMap( className ); - if ( map ) - return map; - - Panel::InitPropertyConverters(); - - PanelAnimationMapDictionaryEntry entry; - entry.map = (PanelAnimationMap *)m_PanelAnimationMapPool.Alloc(); - m_AnimationMaps.Insert( StripNamespace( className ), entry ); - return entry.map; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPanelAnimationDictionary::PanelAnimationDumpMap( PanelAnimationMap *map, bool recursive ) -{ - if ( map->pfnClassName ) - { - Msg( "%s\n", (*map->pfnClassName)() ); - } - int c = map->entries.Count(); - for ( int i = 0; i < c; i++ ) - { - PanelAnimationMapEntry *e = &map->entries[ i ]; - Msg( " %s %s\n", e->type(), e->name() ); - } - - if ( recursive && map->baseMap ) - { - PanelAnimationDumpMap( map->baseMap, recursive ); - } -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CPanelAnimationDictionary::PanelAnimationDumpVars( char const *className ) -{ - if ( className == NULL ) - { - for ( int i = 0; i < (int)m_AnimationMaps.Count(); i++ ) - { - PanelAnimationDumpMap( m_AnimationMaps[ i ].map, false ); - } - } - else - { - PanelAnimationMap *map = FindPanelAnimationMap( className ); - if ( map ) - { - PanelAnimationDumpMap( map, true ); - } - else - { - Msg( "No such Panel Animation class %s\n", className ); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: singleton accessor -//----------------------------------------------------------------------------- -CPanelAnimationDictionary& GetPanelAnimationDictionary() -{ - static CPanelAnimationDictionary dictionary; - return dictionary; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -PanelAnimationMap *FindOrAddPanelAnimationMap( char const *className ) -{ - return GetPanelAnimationDictionary().FindOrAddPanelAnimationMap( className ); -} - -//----------------------------------------------------------------------------- -// Purpose: Find but don't add mapping -//----------------------------------------------------------------------------- -PanelAnimationMap *FindPanelAnimationMap( char const *className ) -{ - return GetPanelAnimationDictionary().FindPanelAnimationMap( className ); -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void PanelAnimationDumpVars( char const *className ) -{ - GetPanelAnimationDictionary().PanelAnimationDumpVars( className ); +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// +#pragma warning( disable : 4244 ) // conversion from 'double' to 'float', possible loss of data + +#include +#include +#include +#include +#include +#include +#include "filesystem.h" +#include "filesystem_helpers.h" + +#include +#include +#include "mempool.h" +#include "utldict.h" +#include "mathlib/mathlib.h" +#include "characterset.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include +// for SRC +#include +#include + +using namespace vgui; + +static CUtlSymbolTable g_ScriptSymbols(0, 128, true); + +// singleton accessor for animation controller for use by the vgui controls +namespace vgui +{ +AnimationController *GetAnimationController() +{ + static AnimationController *s_pAnimationController = new AnimationController(NULL); + return s_pAnimationController; +} +} + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +AnimationController::AnimationController(Panel *parent) : BaseClass(parent, NULL) +{ + m_hSizePanel = 0; + m_nScreenBounds[ 0 ] = m_nScreenBounds[ 1 ] = -1; + m_nScreenBounds[ 2 ] = m_nScreenBounds[ 3 ] = -1; + + m_bAutoReloadScript = false; + + // always invisible + SetVisible(false); + + SetProportional(true); + + // get the names of common types + m_sPosition = g_ScriptSymbols.AddString("position"); + m_sSize = g_ScriptSymbols.AddString("size"); + m_sFgColor = g_ScriptSymbols.AddString("fgcolor"); + m_sBgColor = g_ScriptSymbols.AddString("bgcolor"); + + m_sXPos = g_ScriptSymbols.AddString("xpos"); + m_sYPos = g_ScriptSymbols.AddString("ypos"); + m_sWide = g_ScriptSymbols.AddString("wide"); + m_sTall = g_ScriptSymbols.AddString("tall"); + + m_flCurrentTime = 0.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +AnimationController::~AnimationController() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Sets which script file to use +//----------------------------------------------------------------------------- +bool AnimationController::SetScriptFile( VPANEL sizingPanel, const char *fileName, bool wipeAll /*=false*/ ) +{ + m_hSizePanel = sizingPanel; + + if ( wipeAll ) + { + // clear the current script + m_Sequences.RemoveAll(); + m_ScriptFileNames.RemoveAll(); + + CancelAllAnimations(); + } + + // Store off this filename for reloading later on (if we don't have it already) + UtlSymId_t sFilename = g_ScriptSymbols.AddString( fileName ); + if ( m_ScriptFileNames.Find( sFilename ) == m_ScriptFileNames.InvalidIndex() ) + { + m_ScriptFileNames.AddToTail( sFilename ); + } + + UpdateScreenSize(); + + // load the new script file + return LoadScriptFile( fileName ); +} + +//----------------------------------------------------------------------------- +// Purpose: reloads the currently set script file +//----------------------------------------------------------------------------- +void AnimationController::ReloadScriptFile() +{ + // Clear all current sequences + m_Sequences.RemoveAll(); + + UpdateScreenSize(); + + // Reload each file we've loaded + for ( int i = 0; i < m_ScriptFileNames.Count(); i++ ) + { + const char *lpszFilename = g_ScriptSymbols.String( m_ScriptFileNames[i] ); + if ( strlen( lpszFilename ) > 0) + { + if ( LoadScriptFile( lpszFilename ) == false ) + { + Assert( 0 ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: loads a script file from disk +//----------------------------------------------------------------------------- +bool AnimationController::LoadScriptFile(const char *fileName) +{ + FileHandle_t f = g_pFullFileSystem->Open(fileName, "rt"); + if (!f) + { + Warning("Couldn't find script file %s\n", fileName); + return false; + } + + // read the whole thing into memory + int size = g_pFullFileSystem->Size(f); + // read into temporary memory block + int nBufSize = size+1; + if ( IsXbox() ) + { + nBufSize = AlignValue( nBufSize, 512 ); + } + char *pMem = (char *)malloc(nBufSize); + int bytesRead = g_pFullFileSystem->ReadEx(pMem, nBufSize, size, f); + Assert(bytesRead <= size); + pMem[bytesRead] = 0; + g_pFullFileSystem->Close(f); + // parse + bool success = ParseScriptFile(pMem, bytesRead); + free(pMem); + return success; +} + +AnimationController::RelativeAlignmentLookup AnimationController::g_AlignmentLookup[] = +{ + { AnimationController::a_northwest , "northwest" }, + { AnimationController::a_north , "north" }, + { AnimationController::a_northeast , "northeast" }, + { AnimationController::a_west , "west" }, + { AnimationController::a_center , "center" }, + { AnimationController::a_east , "east" }, + { AnimationController::a_southwest , "southwest" }, + { AnimationController::a_south , "south" }, + { AnimationController::a_southeast , "southeast" }, + + { AnimationController::a_northwest , "nw" }, + { AnimationController::a_north , "n" }, + { AnimationController::a_northeast , "ne" }, + { AnimationController::a_west , "w" }, + { AnimationController::a_center , "c" }, + { AnimationController::a_east , "e" }, + { AnimationController::a_southwest , "sw" }, + { AnimationController::a_south , "s" }, + { AnimationController::a_southeast , "se" }, +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +AnimationController::RelativeAlignment AnimationController::LookupAlignment( char const *token ) +{ + int c = ARRAYSIZE( g_AlignmentLookup ); + + for ( int i = 0; i < c; i++ ) + { + if ( !Q_stricmp( token, g_AlignmentLookup[ i ].name ) ) + { + return g_AlignmentLookup[ i ].align; + } + } + + return AnimationController::a_northwest; +} + +//----------------------------------------------------------------------------- +// Purpose: Parse position including right edge and center adjustment out of a +// token. This is relative to the screen +//----------------------------------------------------------------------------- +void AnimationController::SetupPosition( AnimCmdAnimate_t& cmd, float *output, char const *psz, int screendimension ) +{ + bool r = false, c = false; + int pos; + if ( psz[0] == '(' ) + { + psz++; + + if ( Q_strstr( psz, ")" ) ) + { + char sz[ 256 ]; + Q_strncpy( sz, psz, sizeof( sz ) ); + + char *colon = Q_strstr( sz, ":" ); + if ( colon ) + { + *colon = 0; + + RelativeAlignment ra = LookupAlignment( sz ); + + colon++; + + char *panelName = colon; + char *panelEnd = Q_strstr( panelName, ")" ); + if ( panelEnd ) + { + *panelEnd = 0; + + if ( Q_strlen( panelName ) > 0 ) + { + // + cmd.align.relativePosition = true; + cmd.align.alignPanel = g_ScriptSymbols.AddString(panelName); + cmd.align.alignment = ra; + } + } + } + + psz = Q_strstr( psz, ")" ) + 1; + } + } + else if (psz[0] == 'r' || psz[0] == 'R') + { + r = true; + psz++; + } + else if (psz[0] == 'c' || psz[0] == 'C') + { + c = true; + psz++; + } + + // get the number + pos = atoi(psz); + + // scale the values + if (IsProportional()) + { + pos = vgui::scheme()->GetProportionalScaledValueEx( GetScheme(), pos ); + } + + // adjust the positions + if (r) + { + pos = screendimension - pos; + } + if (c) + { + pos = (screendimension / 2) + pos; + } + + // set the value + *output = static_cast( pos ); +} + + +//----------------------------------------------------------------------------- +// Purpose: parses a script into sequences +//----------------------------------------------------------------------------- +bool AnimationController::ParseScriptFile(char *pMem, int length) +{ + // get the scheme (for looking up color names) + IScheme *scheme = vgui::scheme()->GetIScheme(GetScheme()); + + // get our screen size (for left/right/center alignment) + int screenWide = m_nScreenBounds[ 2 ]; + int screenTall = m_nScreenBounds[ 3 ]; + + // start by getting the first token + char token[512]; + pMem = ParseFile(pMem, token, NULL); + while (token[0]) + { + bool bAccepted = true; + + // should be 'event' + if (stricmp(token, "event")) + { + Warning("Couldn't parse script file: expected 'event', found '%s'\n", token); + return false; + } + + // get the event name + pMem = ParseFile(pMem, token, NULL); + if (strlen(token) < 1) + { + Warning("Couldn't parse script file: expected , found nothing\n"); + return false; + } + + int seqIndex; + UtlSymId_t nameIndex = g_ScriptSymbols.AddString(token); + + // Create a new sequence + seqIndex = m_Sequences.AddToTail(); + AnimSequence_t &seq = m_Sequences[seqIndex]; + seq.name = nameIndex; + seq.duration = 0.0f; + + // get the open brace or a conditional + pMem = ParseFile(pMem, token, NULL); + if ( Q_stristr( token, "[$" ) ) + { + bAccepted = EvaluateConditional( token ); + + // now get the open brace + pMem = ParseFile(pMem, token, NULL); + } + + if (stricmp(token, "{")) + { + Warning("Couldn't parse script sequence '%s': expected '{', found '%s'\n", g_ScriptSymbols.String(seq.name), token); + return false; + } + + // walk the commands + while (token && token[0]) + { + // get the command type + pMem = ParseFile(pMem, token, NULL); + + // skip out when we hit the end of the sequence + if (token[0] == '}') + break; + + // create a new command + int cmdIndex = seq.cmdList.AddToTail(); + AnimCommand_t &animCmd = seq.cmdList[cmdIndex]; + memset(&animCmd, 0, sizeof(animCmd)); + if (!stricmp(token, "animate")) + { + animCmd.commandType = CMD_ANIMATE; + // parse out the animation commands + AnimCmdAnimate_t &cmdAnimate = animCmd.cmdData.animate; + // panel to manipulate + pMem = ParseFile(pMem, token, NULL); + cmdAnimate.panel = g_ScriptSymbols.AddString(token); + // variable to change + pMem = ParseFile(pMem, token, NULL); + cmdAnimate.variable = g_ScriptSymbols.AddString(token); + // target value + pMem = ParseFile(pMem, token, NULL); + if (cmdAnimate.variable == m_sPosition) + { + // Get first token + SetupPosition( cmdAnimate, &cmdAnimate.target.a, token, screenWide ); + + // Get second token from "token" + char token2[32]; + char *psz = ParseFile(token, token2, NULL); + psz = ParseFile(psz, token2, NULL); + psz = token2; + + // Position Y goes into ".b" + SetupPosition( cmdAnimate, &cmdAnimate.target.b, psz, screenTall ); + } + else if ( cmdAnimate.variable == m_sXPos ) + { + // XPos and YPos both use target ".a" + SetupPosition( cmdAnimate, &cmdAnimate.target.a, token, screenWide ); + } + else if ( cmdAnimate.variable == m_sYPos ) + { + // XPos and YPos both use target ".a" + SetupPosition( cmdAnimate, &cmdAnimate.target.a, token, screenTall ); + } + else + { + // parse the floating point values right out + if (0 == sscanf(token, "%f %f %f %f", &cmdAnimate.target.a, &cmdAnimate.target.b, &cmdAnimate.target.c, &cmdAnimate.target.d)) + { + //============================================================================= + // HPE_BEGIN: + // [pfreese] Improved handling colors not defined in scheme + //============================================================================= + + // could be referencing a value in the scheme file, lookup + Color default_invisible_black(0, 0, 0, 0); + Color col = scheme->GetColor(token, default_invisible_black); + + // we don't have a way of seeing if the color is not declared in the scheme, so we use this + // silly method of trying again with a different default to see if we get the fallback again + if (col == default_invisible_black) + { + Color error_pink(255, 0, 255, 255); // make it extremely obvious if a scheme lookup fails + col = scheme->GetColor(token, error_pink); + + // commented out for Soldier/Demo release...(getting spammed in console) + // we'll try to figure this out after the update is out +// if (col == error_pink) +// { +// Warning("Missing color in scheme: %s\n", token); +// } + } + + //============================================================================= + // HPE_END + //============================================================================= + + cmdAnimate.target.a = col[0]; + cmdAnimate.target.b = col[1]; + cmdAnimate.target.c = col[2]; + cmdAnimate.target.d = col[3]; + } + } + + // fix up scale + if (cmdAnimate.variable == m_sSize) + { + if (IsProportional()) + { + cmdAnimate.target.a = static_cast( vgui::scheme()->GetProportionalScaledValueEx(GetScheme(), cmdAnimate.target.a) ); + cmdAnimate.target.b = static_cast( vgui::scheme()->GetProportionalScaledValueEx(GetScheme(), cmdAnimate.target.b) ); + } + } + else if (cmdAnimate.variable == m_sWide || + cmdAnimate.variable == m_sTall ) + { + if (IsProportional()) + { + // Wide and tall both use.a + cmdAnimate.target.a = static_cast( vgui::scheme()->GetProportionalScaledValueEx(GetScheme(), cmdAnimate.target.a) ); + } + } + + // interpolation function + pMem = ParseFile(pMem, token, NULL); + if (!stricmp(token, "Accel")) + { + cmdAnimate.interpolationFunction = INTERPOLATOR_ACCEL; + } + else if (!stricmp(token, "Deaccel")) + { + cmdAnimate.interpolationFunction = INTERPOLATOR_DEACCEL; + } + else if ( !stricmp(token, "Spline")) + { + cmdAnimate.interpolationFunction = INTERPOLATOR_SIMPLESPLINE; + } + else if (!stricmp(token,"Pulse")) + { + cmdAnimate.interpolationFunction = INTERPOLATOR_PULSE; + // frequencey + pMem = ParseFile(pMem, token, NULL); + cmdAnimate.interpolationParameter = (float)atof(token); + } + else if ( !stricmp( token, "Flicker")) + { + cmdAnimate.interpolationFunction = INTERPOLATOR_FLICKER; + // noiseamount + pMem = ParseFile(pMem, token, NULL); + cmdAnimate.interpolationParameter = (float)atof(token); + } + else if (!stricmp(token, "Bounce")) + { + cmdAnimate.interpolationFunction = INTERPOLATOR_BOUNCE; + } + else + { + cmdAnimate.interpolationFunction = INTERPOLATOR_LINEAR; + } + // start time + pMem = ParseFile(pMem, token, NULL); + cmdAnimate.startTime = (float)atof(token); + // duration + pMem = ParseFile(pMem, token, NULL); + cmdAnimate.duration = (float)atof(token); + // check max duration + if (cmdAnimate.startTime + cmdAnimate.duration > seq.duration) + { + seq.duration = cmdAnimate.startTime + cmdAnimate.duration; + } + } + else if (!stricmp(token, "runevent")) + { + animCmd.commandType = CMD_RUNEVENT; + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token); + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.timeDelay = (float)atof(token); + } + else if (!stricmp(token, "stopevent")) + { + animCmd.commandType = CMD_STOPEVENT; + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token); + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.timeDelay = (float)atof(token); + } + else if (!stricmp(token, "StopPanelAnimations")) + { + animCmd.commandType = CMD_STOPPANELANIMATIONS; + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token); + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.timeDelay = (float)atof(token); + } + else if (!stricmp(token, "stopanimation")) + { + animCmd.commandType = CMD_STOPANIMATION; + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token); + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token); + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.timeDelay = (float)atof(token); + } + else if ( !stricmp( token, "SetFont" )) + { + animCmd.commandType = CMD_SETFONT; + // Panel name + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token); + // Font parameter + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token); + // Font name from scheme + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.variable2 = g_ScriptSymbols.AddString(token); + + // Set time + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.timeDelay = (float)atof(token); + } + else if ( !stricmp( token, "SetTexture" )) + { + animCmd.commandType = CMD_SETTEXTURE; + // Panel name + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token); + // Texture Id + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token); + // material name + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.variable2 = g_ScriptSymbols.AddString(token); + + // Set time + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.timeDelay = (float)atof(token); + } + else if ( !stricmp( token, "SetString" )) + { + animCmd.commandType = CMD_SETSTRING; + // Panel name + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.event = g_ScriptSymbols.AddString(token); + // String variable name + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.variable = g_ScriptSymbols.AddString(token); + // String value to set + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.variable2 = g_ScriptSymbols.AddString(token); + + // Set time + pMem = ParseFile(pMem, token, NULL); + animCmd.cmdData.runEvent.timeDelay = (float)atof(token); + } + else + { + Warning("Couldn't parse script sequence '%s': expected , found '%s'\n", g_ScriptSymbols.String(seq.name), token); + return false; + } + + // Look ahead one token for a conditional + char *peek = ParseFile(pMem, token, NULL); + if ( Q_stristr( token, "[$" ) ) + { + if ( !EvaluateConditional( token ) ) + { + seq.cmdList.Remove( cmdIndex ); + } + pMem = peek; + } + } + + if ( bAccepted ) + { + // Attempt to find a collision in the sequences, replacing the old one if found + int seqIterator; + for ( seqIterator = 0; seqIterator < m_Sequences.Count()-1; seqIterator++ ) + { + if ( m_Sequences[seqIterator].name == nameIndex ) + { + // Get rid of it, we're overriding it + m_Sequences.Remove( seqIndex ); + break; + } + } + } + else + { + // Dump the entire sequence + m_Sequences.Remove( seqIndex ); + } + + // get the next token, if any + pMem = ParseFile(pMem, token, NULL); + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: checks all posted animation events, firing if time +//----------------------------------------------------------------------------- +void AnimationController::UpdatePostedMessages(bool bRunToCompletion) +{ + CUtlVector eventsRanThisFrame; + + // check all posted messages + for (int i = 0; i < m_PostedMessages.Count(); i++) + { + PostedMessage_t &msgRef = m_PostedMessages[i]; + if (m_flCurrentTime < msgRef.startTime && !bRunToCompletion) + continue; + + // take a copy of th message + PostedMessage_t msg = msgRef; + + // remove the event + // do this before handling the message because the message queue may be messed with + m_PostedMessages.Remove(i); + // reset the count, start the whole queue again + i = -1; + + // handle the event + switch (msg.commandType) + { + case CMD_RUNEVENT: + { + RanEvent_t curEvent; + curEvent.event = msg.event; + curEvent.pParent = msg.parent.Get(); + + // run the event, but only if we haven't already run it this frame, for this parent + if (!eventsRanThisFrame.HasElement(curEvent)) + { + eventsRanThisFrame.AddToTail(curEvent); + RunCmd_RunEvent(msg); + } + } + break; + case CMD_STOPEVENT: + RunCmd_StopEvent(msg); + break; + case CMD_STOPPANELANIMATIONS: + RunCmd_StopPanelAnimations(msg); + break; + case CMD_STOPANIMATION: + RunCmd_StopAnimation(msg); + break; + case CMD_SETFONT: + RunCmd_SetFont(msg); + break; + case CMD_SETTEXTURE: + RunCmd_SetTexture(msg); + break; + case CMD_SETSTRING: + RunCmd_SetString( msg ); + break; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: runs the current animations +//----------------------------------------------------------------------------- +void AnimationController::UpdateActiveAnimations(bool bRunToCompletion) +{ + // iterate all the currently active animations + for (int i = 0; i < m_ActiveAnimations.Count(); i++) + { + ActiveAnimation_t &anim = m_ActiveAnimations[i]; + + // see if the anim is ready to start + if (m_flCurrentTime < anim.startTime && !bRunToCompletion) + continue; + + if (!anim.panel.Get()) + { + // panel is gone, remove the animation + m_ActiveAnimations.Remove(i); + --i; + continue; + } + + if (!anim.started && !bRunToCompletion) + { + // start the animation from the current value + anim.startValue = GetValue(anim, anim.panel, anim.variable); + anim.started = true; + + // 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()); + } + + // get the interpolated value + Value_t val; + if (m_flCurrentTime >= anim.endTime || bRunToCompletion) + { + // animation is done, use the last value + val = anim.endValue; + } + else + { + // get the interpolated value + val = GetInterpolatedValue(anim.interpolator, anim.interpolatorParam, m_flCurrentTime, anim.startTime, anim.endTime, anim.startValue, anim.endValue); + } + + // apply the new value to the panel + SetValue(anim, anim.panel, anim.variable, val); + + // Msg( "Animate value: %s => %.2f for panel '%s'\n", g_ScriptSymbols.String(anim.variable), val.a, anim.panel->GetName()); + + // see if we can remove the animation + if (m_flCurrentTime >= anim.endTime || bRunToCompletion) + { + m_ActiveAnimations.Remove(i); + --i; + } + } +} + +bool AnimationController::UpdateScreenSize() +{ + // get our screen size (for left/right/center alignment) + int screenWide, screenTall; + int sx = 0, sy = 0; + if ( m_hSizePanel != 0 ) + { + ipanel()->GetSize( m_hSizePanel, screenWide, screenTall ); + ipanel()->GetPos( m_hSizePanel, sx, sy ); + } + else + { + surface()->GetScreenSize(screenWide, screenTall); + } + + bool changed = m_nScreenBounds[ 0 ] != sx || + m_nScreenBounds[ 1 ] != sy || + m_nScreenBounds[ 2 ] != screenWide || + m_nScreenBounds[ 3 ] != screenTall; + + m_nScreenBounds[ 0 ] = sx; + m_nScreenBounds[ 1 ] = sy; + m_nScreenBounds[ 2 ] = screenWide; + m_nScreenBounds[ 3 ] = screenTall; + + return changed; +} +//----------------------------------------------------------------------------- +// Purpose: runs a frame of animation +//----------------------------------------------------------------------------- +void AnimationController::UpdateAnimations( float currentTime ) +{ + m_flCurrentTime = currentTime; + + if ( UpdateScreenSize() && m_ScriptFileNames.Count() ) + { + RunAllAnimationsToCompletion(); + ReloadScriptFile(); + } + + UpdatePostedMessages(false); + UpdateActiveAnimations(false); +} + +//----------------------------------------------------------------------------- +// Purpose: plays all animations to completion instantly +//----------------------------------------------------------------------------- +void AnimationController::RunAllAnimationsToCompletion() +{ + // Msg( "AnimationController::RunAllAnimationsToCompletion()\n" ); + UpdatePostedMessages(true); + UpdateActiveAnimations(true); +} + +//----------------------------------------------------------------------------- +// Purpose: Stops all current animations +//----------------------------------------------------------------------------- +void AnimationController::CancelAllAnimations() +{ + // Msg( "AnimationController::CancelAllAnimations()\n" ); + + m_ActiveAnimations.RemoveAll(); + m_PostedMessages.RemoveAll(); +} + +//----------------------------------------------------------------------------- +// Purpose: produces an interpolated value +//----------------------------------------------------------------------------- +AnimationController::Value_t AnimationController::GetInterpolatedValue(int interpolator, float interpolatorParam, float currentTime, float startTime, float endTime, Value_t &startValue, Value_t &endValue) +{ + // calculate how far we are into the animation + float pos = (currentTime - startTime) / (endTime - startTime); + + // adjust the percentage through by the interpolation function + switch (interpolator) + { + case INTERPOLATOR_ACCEL: + pos *= pos; + break; + case INTERPOLATOR_DEACCEL: + pos = sqrtf(pos); + break; + case INTERPOLATOR_SIMPLESPLINE: + pos = SimpleSpline( pos ); + break; + case INTERPOLATOR_PULSE: + // Make sure we end at 1.0, so use cosine + pos = 0.5f + 0.5f * ( cos( pos * 2.0f * M_PI * interpolatorParam ) ); + break; + case INTERPOLATOR_FLICKER: + if ( RandomFloat( 0.0f, 1.0f ) < interpolatorParam ) + { + pos = 1.0f; + } + else + { + pos = 0.0f; + } + break; + case INTERPOLATOR_BOUNCE: + { + // fall from startValue to endValue, bouncing a few times and settling out at endValue + const float hit1 = 0.33f; + const float hit2 = 0.67f; + const float hit3 = 1.0f; + + if ( pos < hit1 ) + { + pos = 1.0f - sin( M_PI * pos / hit1 ); + } + else if ( pos < hit2 ) + { + pos = 0.5f + 0.5f * ( 1.0f - sin( M_PI * ( pos - hit1 ) / ( hit2 - hit1 ) ) ); + } + else + { + pos = 0.8f + 0.2f * ( 1.0f - sin( M_PI * ( pos - hit2 ) / ( hit3 - hit2 ) ) ); + } + break; + } + case INTERPOLATOR_LINEAR: + default: + break; + } + + // calculate the value + Value_t val; + val.a = ((endValue.a - startValue.a) * pos) + startValue.a; + val.b = ((endValue.b - startValue.b) * pos) + startValue.b; + val.c = ((endValue.c - startValue.c) * pos) + startValue.c; + val.d = ((endValue.d - startValue.d) * pos) + startValue.d; + return val; +} + +//----------------------------------------------------------------------------- +// Purpose: sets that the script file should be reloaded each time a script is ran +// used for development +//----------------------------------------------------------------------------- +void AnimationController::SetAutoReloadScript(bool state) +{ + m_bAutoReloadScript = state; +} + +//----------------------------------------------------------------------------- +// Purpose: starts an animation sequence script +//----------------------------------------------------------------------------- +bool AnimationController::StartAnimationSequence(const char *sequenceName) +{ + // We support calling an animation on elements that are not the calling + // panel's children. Use the base parent to start the search. + + return StartAnimationSequence( GetParent(), sequenceName ); +} + +//----------------------------------------------------------------------------- +// Purpose: starts an animation sequence script +//----------------------------------------------------------------------------- +bool AnimationController::StartAnimationSequence(Panel *pWithinParent, const char *sequenceName) +{ + Assert( pWithinParent ); + + if (m_bAutoReloadScript) + { + // Reload the script files + ReloadScriptFile(); + } + + // lookup the symbol for the name + UtlSymId_t seqName = g_ScriptSymbols.Find(sequenceName); + if (seqName == UTL_INVAL_SYMBOL) + return false; + + // Msg("Starting animation sequence %s\n", sequenceName); + + // remove the existing command from the queue + RemoveQueuedAnimationCommands(seqName, pWithinParent); + + // look through for the sequence + int i; + for (i = 0; i < m_Sequences.Count(); i++) + { + if (m_Sequences[i].name == seqName) + break; + } + if (i >= m_Sequences.Count()) + return false; + + // execute the sequence + for (int cmdIndex = 0; cmdIndex < m_Sequences[i].cmdList.Count(); cmdIndex++) + { + ExecAnimationCommand(seqName, m_Sequences[i].cmdList[cmdIndex], pWithinParent); + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Runs a custom command from code, not from a script file +//----------------------------------------------------------------------------- +void AnimationController::RunAnimationCommand(vgui::Panel *panel, const char *variable, float targetValue, float startDelaySeconds, float duration, Interpolators_e interpolator, float animParameter /* = 0 */ ) +{ + // clear any previous animations of this variable + UtlSymId_t var = g_ScriptSymbols.AddString(variable); + RemoveQueuedAnimationByType(panel, var, UTL_INVAL_SYMBOL); + + // build a new animation + AnimCmdAnimate_t animateCmd; + memset(&animateCmd, 0, sizeof(animateCmd)); + animateCmd.panel = 0; + animateCmd.variable = var; + animateCmd.target.a = targetValue; + animateCmd.interpolationFunction = interpolator; + animateCmd.interpolationParameter = animParameter; + animateCmd.startTime = startDelaySeconds; + animateCmd.duration = duration; + + // start immediately + StartCmd_Animate(panel, 0, animateCmd); +} + +//----------------------------------------------------------------------------- +// Purpose: Runs a custom command from code, not from a script file +//----------------------------------------------------------------------------- +void AnimationController::RunAnimationCommand(vgui::Panel *panel, const char *variable, Color targetValue, float startDelaySeconds, float duration, Interpolators_e interpolator, float animParameter /* = 0 */ ) +{ + // clear any previous animations of this variable + UtlSymId_t var = g_ScriptSymbols.AddString(variable); + RemoveQueuedAnimationByType(panel, var, UTL_INVAL_SYMBOL); + + // build a new animation + AnimCmdAnimate_t animateCmd; + memset(&animateCmd, 0, sizeof(animateCmd)); + animateCmd.panel = 0; + animateCmd.variable = var; + animateCmd.target.a = targetValue[0]; + animateCmd.target.b = targetValue[1]; + animateCmd.target.c = targetValue[2]; + animateCmd.target.d = targetValue[3]; + animateCmd.interpolationFunction = interpolator; + animateCmd.interpolationParameter = animParameter; + animateCmd.startTime = startDelaySeconds; + animateCmd.duration = duration; + + // start immediately + StartCmd_Animate(panel, 0, animateCmd); +} + +//----------------------------------------------------------------------------- +// Purpose: gets the length of an animation sequence, in seconds +//----------------------------------------------------------------------------- +float AnimationController::GetAnimationSequenceLength(const char *sequenceName) +{ + // lookup the symbol for the name + UtlSymId_t seqName = g_ScriptSymbols.Find(sequenceName); + if (seqName == UTL_INVAL_SYMBOL) + return 0.0f; + + // look through for the sequence + int i; + for (i = 0; i < m_Sequences.Count(); i++) + { + if (m_Sequences[i].name == seqName) + break; + } + if (i >= m_Sequences.Count()) + return 0.0f; + + // sequence found + return m_Sequences[i].duration; +} + +//----------------------------------------------------------------------------- +// Purpose: removes an existing set of commands from the queue +//----------------------------------------------------------------------------- +void AnimationController::RemoveQueuedAnimationCommands(UtlSymId_t seqName, Panel *pWithinParent) +{ + // Msg("Removing queued anims for sequence %s\n", g_ScriptSymbols.String(seqName)); + + // remove messages posted by this sequence + // if pWithinParent is specified, remove only messages under that parent + {for (int i = 0; i < m_PostedMessages.Count(); i++) + { + if ( ( m_PostedMessages[i].seqName == seqName ) && + ( !pWithinParent || ( m_PostedMessages[i].parent == pWithinParent ) ) ) + { + m_PostedMessages.Remove(i); + --i; + } + }} + + // remove all animations + // if pWithinParent is specified, remove only animations under that parent + for (int i = 0; i < m_ActiveAnimations.Count(); i++) + { + if ( m_ActiveAnimations[i].seqName != seqName ) + continue; + + // panel this anim is on, m_ActiveAnimations[i].panel + if ( pWithinParent ) + { + Panel *animPanel = m_ActiveAnimations[i].panel; + + if ( !animPanel ) + continue; + + Panel *foundPanel = pWithinParent->FindChildByName(animPanel->GetName(),true); + + if ( foundPanel != animPanel ) + continue; + } + + m_ActiveAnimations.Remove(i); + --i; + } +} + +//----------------------------------------------------------------------------- +// Purpose: removes the specified queued animation +//----------------------------------------------------------------------------- +void AnimationController::RemoveQueuedAnimationByType(vgui::Panel *panel, UtlSymId_t variable, UtlSymId_t sequenceToIgnore) +{ + for (int i = 0; i < m_ActiveAnimations.Count(); i++) + { + if (m_ActiveAnimations[i].panel == panel && m_ActiveAnimations[i].variable == variable && m_ActiveAnimations[i].seqName != sequenceToIgnore) + { + // Msg("Removing queued anim %s::%s::%s\n", g_ScriptSymbols.String(m_ActiveAnimations[i].seqName), panel->GetName(), g_ScriptSymbols.String(variable)); + m_ActiveAnimations.Remove(i); + break; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: runs a single line of the script +//----------------------------------------------------------------------------- +void AnimationController::ExecAnimationCommand(UtlSymId_t seqName, AnimCommand_t &animCommand, Panel *pWithinParent) +{ + if (animCommand.commandType == CMD_ANIMATE) + { + StartCmd_Animate(seqName, animCommand.cmdData.animate, pWithinParent); + } + else + { + // post the command to happen at the specified time + PostedMessage_t &msg = m_PostedMessages[m_PostedMessages.AddToTail()]; + msg.seqName = seqName; + msg.commandType = animCommand.commandType; + msg.event = animCommand.cmdData.runEvent.event; + msg.variable = animCommand.cmdData.runEvent.variable; + msg.variable2 = animCommand.cmdData.runEvent.variable2; + msg.startTime = m_flCurrentTime + animCommand.cmdData.runEvent.timeDelay; + msg.parent = pWithinParent; + } +} + +//----------------------------------------------------------------------------- +// Purpose: starts a variable animation +//----------------------------------------------------------------------------- +void AnimationController::StartCmd_Animate(UtlSymId_t seqName, AnimCmdAnimate_t &cmd, Panel *pWithinParent) +{ + Assert( pWithinParent ); + if ( !pWithinParent ) + return; + + // make sure the child exists + Panel *panel = pWithinParent->FindChildByName(g_ScriptSymbols.String(cmd.panel),true); + if ( !panel ) + { + // Check the parent + Panel *parent = GetParent(); + if ( !Q_stricmp( parent->GetName(), g_ScriptSymbols.String(cmd.panel) ) ) + { + panel = parent; + } + } + if (!panel) + return; + + StartCmd_Animate(panel, seqName, cmd); +} + +//----------------------------------------------------------------------------- +// Purpose: Starts an animation command for the specified panel +//----------------------------------------------------------------------------- +void AnimationController::StartCmd_Animate(Panel *panel, UtlSymId_t seqName, AnimCmdAnimate_t &cmd) +{ + // build a command to add to the animation queue + ActiveAnimation_t &anim = m_ActiveAnimations[m_ActiveAnimations.AddToTail()]; + anim.panel = panel; + anim.seqName = seqName; + anim.variable = cmd.variable; + anim.interpolator = cmd.interpolationFunction; + anim.interpolatorParam = cmd.interpolationParameter; + // timings + anim.startTime = m_flCurrentTime + cmd.startTime; + anim.endTime = anim.startTime + cmd.duration; + // values + anim.started = false; + anim.endValue = cmd.target; + + anim.align = cmd.align; +} + +//----------------------------------------------------------------------------- +// Purpose: a posted message to run another event +//----------------------------------------------------------------------------- +void AnimationController::RunCmd_RunEvent(PostedMessage_t &msg) +{ + StartAnimationSequence(msg.parent.Get(), g_ScriptSymbols.String(msg.event)); +} + +//----------------------------------------------------------------------------- +// Purpose: a posted message to stop another event +//----------------------------------------------------------------------------- +void AnimationController::RunCmd_StopEvent(PostedMessage_t &msg) +{ + RemoveQueuedAnimationCommands(msg.event, msg.parent); +} + +//----------------------------------------------------------------------------- +// Purpose: a posted message to stop all animations relevant to a specified panel +//----------------------------------------------------------------------------- +void AnimationController::RunCmd_StopPanelAnimations(PostedMessage_t &msg) +{ + Panel *panel = FindSiblingByName(g_ScriptSymbols.String(msg.event)); + Assert(panel != NULL); + if (!panel) + return; + + // loop through all the active animations cancelling any that + // are operating on said panel, except for the event specified + for (int i = 0; i < m_ActiveAnimations.Count(); i++) + { + if (m_ActiveAnimations[i].panel == panel && m_ActiveAnimations[i].seqName != msg.seqName) + { + m_ActiveAnimations.Remove(i); + --i; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: a posted message to stop animations of a specific type +//----------------------------------------------------------------------------- +void AnimationController::RunCmd_StopAnimation(PostedMessage_t &msg) +{ + Panel *panel = FindSiblingByName(g_ScriptSymbols.String(msg.event)); + Assert(panel != NULL); + if (!panel) + return; + + RemoveQueuedAnimationByType(panel, msg.variable, msg.seqName); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void AnimationController::RunCmd_SetFont( PostedMessage_t &msg ) +{ + Panel *parent = msg.parent.Get(); + + if ( !parent ) + { + parent = GetParent(); + } + + Panel *panel = parent->FindChildByName(g_ScriptSymbols.String(msg.event), true); + Assert(panel != NULL); + if (!panel) + return; + + KeyValues *inputData = new KeyValues(g_ScriptSymbols.String(msg.variable)); + inputData->SetString(g_ScriptSymbols.String(msg.variable), g_ScriptSymbols.String(msg.variable2)); + if (!panel->SetInfo(inputData)) + { + // Assert(!("Unhandlable var in AnimationController::SetValue())")); + } + inputData->deleteThis(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void AnimationController::RunCmd_SetTexture( PostedMessage_t &msg ) +{ + Panel *panel = FindSiblingByName(g_ScriptSymbols.String(msg.event)); + Assert(panel != NULL); + if (!panel) + return; + + KeyValues *inputData = new KeyValues(g_ScriptSymbols.String(msg.variable)); + inputData->SetString(g_ScriptSymbols.String(msg.variable), g_ScriptSymbols.String(msg.variable2)); + if (!panel->SetInfo(inputData)) + { + // Assert(!("Unhandlable var in AnimationController::SetValue())")); + } + inputData->deleteThis(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void AnimationController::RunCmd_SetString( PostedMessage_t &msg ) +{ + Panel *panel = FindSiblingByName(g_ScriptSymbols.String(msg.event)); + Assert(panel != NULL); + if (!panel) + return; + + KeyValues *inputData = new KeyValues(g_ScriptSymbols.String(msg.variable)); + inputData->SetString(g_ScriptSymbols.String(msg.variable), g_ScriptSymbols.String(msg.variable2)); + if (!panel->SetInfo(inputData)) + { + // Assert(!("Unhandlable var in AnimationController::SetValue())")); + } + inputData->deleteThis(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int AnimationController::GetRelativeOffset( AnimAlign_t& align, bool xcoord ) +{ + if ( !align.relativePosition ) + return 0; + + Panel *panel = GetParent()->FindChildByName(g_ScriptSymbols.String(align.alignPanel), true); + if ( !panel ) + return 0; + + int x, y, w, h; + panel->GetBounds( x, y, w, h ); + + int offset =0; + switch ( align.alignment ) + { + default: + case a_northwest: + offset = xcoord ? x : y; + break; + case a_north: + offset = xcoord ? ( x + w ) / 2 : y; + break; + case a_northeast: + offset = xcoord ? ( x + w ) : y; + break; + case a_west: + offset = xcoord ? x : ( y + h ) / 2; + break; + case a_center: + offset = xcoord ? ( x + w ) / 2 : ( y + h ) / 2; + break; + case a_east: + offset = xcoord ? ( x + w ) : ( y + h ) / 2; + break; + case a_southwest: + offset = xcoord ? x : ( y + h ); + break; + case a_south: + offset = xcoord ? ( x + w ) / 2 : ( y + h ); + break; + case a_southeast: + offset = xcoord ? ( x + w ) : ( y + h ); + break; + } + + return offset; +} + +//----------------------------------------------------------------------------- +// Purpose: Gets the specified value from a panel +//----------------------------------------------------------------------------- +AnimationController::Value_t AnimationController::GetValue(ActiveAnimation_t& anim, Panel *panel, UtlSymId_t var) +{ + Value_t val = { 0, 0, 0, 0 }; + if (var == m_sPosition) + { + int x, y; + panel->GetPos(x, y); + val.a = (float)(x - GetRelativeOffset( anim.align, true ) ); + val.b = (float)(y - GetRelativeOffset( anim.align, false ) ); + } + else if (var == m_sSize) + { + int w, t; + panel->GetSize(w, t); + val.a = (float)w; + val.b = (float)t; + } + else if (var == m_sFgColor) + { + Color col = panel->GetFgColor(); + val.a = col[0]; + val.b = col[1]; + val.c = col[2]; + val.d = col[3]; + } + else if (var == m_sBgColor) + { + Color col = panel->GetBgColor(); + val.a = col[0]; + val.b = col[1]; + val.c = col[2]; + val.d = col[3]; + } + else if ( var == m_sXPos ) + { + int x, y; + panel->GetPos(x, y); + val.a = (float)( x - GetRelativeOffset( anim.align, true ) ); + } + else if ( var == m_sYPos ) + { + int x, y; + panel->GetPos(x, y); + val.a = (float)( y - GetRelativeOffset( anim.align, false ) ); + } + else if ( var == m_sWide ) + { + int w, h; + panel->GetSize(w, h); + val.a = (float)w; + } + else if ( var == m_sTall ) + { + int w, h; + panel->GetSize(w, h); + val.a = (float)h; + } + else + { + KeyValues *outputData = new KeyValues(g_ScriptSymbols.String(var)); + if (panel->RequestInfo(outputData)) + { + // find the var and lookup it's type + KeyValues *kv = outputData->FindKey(g_ScriptSymbols.String(var)); + if (kv && kv->GetDataType() == KeyValues::TYPE_FLOAT) + { + val.a = kv->GetFloat(); + val.b = 0.0f; + val.c = 0.0f; + val.d = 0.0f; + } + else if (kv && kv->GetDataType() == KeyValues::TYPE_COLOR) + { + Color col = kv->GetColor(); + val.a = col[0]; + val.b = col[1]; + val.c = col[2]; + val.d = col[3]; + } + } + else + { + // Assert(!("Unhandlable var in AnimationController::GetValue())")); + } + outputData->deleteThis(); + } + return val; +} + +//----------------------------------------------------------------------------- +// Purpose: Sets a value in a panel +//----------------------------------------------------------------------------- +void AnimationController::SetValue(ActiveAnimation_t& anim, Panel *panel, UtlSymId_t var, Value_t &value) +{ + if (var == m_sPosition) + { + int x = (int)value.a + GetRelativeOffset( anim.align, true ); + int y = (int)value.b + GetRelativeOffset( anim.align, false ); + panel->SetPos(x, y); + } + else if (var == m_sSize) + { + panel->SetSize((int)value.a, (int)value.b); + } + else if (var == m_sFgColor) + { + Color col = panel->GetFgColor(); + col[0] = (unsigned char)value.a; + col[1] = (unsigned char)value.b; + col[2] = (unsigned char)value.c; + col[3] = (unsigned char)value.d; + panel->SetFgColor(col); + } + else if (var == m_sBgColor) + { + Color col = panel->GetBgColor(); + col[0] = (unsigned char)value.a; + col[1] = (unsigned char)value.b; + col[2] = (unsigned char)value.c; + col[3] = (unsigned char)value.d; + panel->SetBgColor(col); + } + else if (var == m_sXPos) + { + int newx = (int)value.a + GetRelativeOffset( anim.align, true ); + int x, y; + panel->GetPos( x, y ); + x = newx; + panel->SetPos(x, y); + } + else if (var == m_sYPos) + { + int newy = (int)value.a + GetRelativeOffset( anim.align, false ); + int x, y; + panel->GetPos( x, y ); + y = newy; + panel->SetPos(x, y); + } + else if (var == m_sWide) + { + int neww = (int)value.a; + int w, h; + panel->GetSize( w, h ); + w = neww; + panel->SetSize(w, h); + } + else if (var == m_sTall) + { + int newh = (int)value.a; + int w, h; + panel->GetSize( w, h ); + h = newh; + panel->SetSize(w, h); + } + else + { + KeyValues *inputData = new KeyValues(g_ScriptSymbols.String(var)); + // set the custom value + if (value.b == 0.0f && value.c == 0.0f && value.d == 0.0f) + { + // only the first value is non-zero, so probably just a float value + inputData->SetFloat(g_ScriptSymbols.String(var), value.a); + } + else + { + // multivalue, set the color + Color col((unsigned char)value.a, (unsigned char)value.b, (unsigned char)value.c, (unsigned char)value.d); + inputData->SetColor(g_ScriptSymbols.String(var), col); + } + if (!panel->SetInfo(inputData)) + { + // Assert(!("Unhandlable var in AnimationController::SetValue())")); + } + inputData->deleteThis(); + } +} +// Hooks between panels and animation controller system + +class CPanelAnimationDictionary +{ +public: + CPanelAnimationDictionary() : m_PanelAnimationMapPool( 32 ) + { + } + + ~CPanelAnimationDictionary() + { + m_PanelAnimationMapPool.Clear(); + } + + PanelAnimationMap *FindOrAddPanelAnimationMap( char const *className ); + PanelAnimationMap *FindPanelAnimationMap( char const *className ); + void PanelAnimationDumpVars( char const *className ); +private: + + struct PanelAnimationMapDictionaryEntry + { + PanelAnimationMap *map; + }; + + char const *StripNamespace( char const *className ); + void PanelAnimationDumpMap( PanelAnimationMap *map, bool recursive ); + + CClassMemoryPool< PanelAnimationMap > m_PanelAnimationMapPool; + CUtlDict< PanelAnimationMapDictionaryEntry, int > m_AnimationMaps; +}; + + +char const *CPanelAnimationDictionary::StripNamespace( char const *className ) +{ + if ( !Q_strnicmp( className, "vgui::", 6 ) ) + { + return className + 6; + } + return className; +} + +//----------------------------------------------------------------------------- +// Purpose: Find but don't add mapping +//----------------------------------------------------------------------------- +PanelAnimationMap *CPanelAnimationDictionary::FindPanelAnimationMap( char const *className ) +{ + int lookup = m_AnimationMaps.Find( StripNamespace( className ) ); + if ( lookup != m_AnimationMaps.InvalidIndex() ) + { + return m_AnimationMaps[ lookup ].map; + } + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +PanelAnimationMap *CPanelAnimationDictionary::FindOrAddPanelAnimationMap( char const *className ) +{ + PanelAnimationMap *map = FindPanelAnimationMap( className ); + if ( map ) + return map; + + Panel::InitPropertyConverters(); + + PanelAnimationMapDictionaryEntry entry; + entry.map = (PanelAnimationMap *)m_PanelAnimationMapPool.Alloc(); + m_AnimationMaps.Insert( StripNamespace( className ), entry ); + return entry.map; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPanelAnimationDictionary::PanelAnimationDumpMap( PanelAnimationMap *map, bool recursive ) +{ + if ( map->pfnClassName ) + { + Msg( "%s\n", (*map->pfnClassName)() ); + } + int c = map->entries.Count(); + for ( int i = 0; i < c; i++ ) + { + PanelAnimationMapEntry *e = &map->entries[ i ]; + Msg( " %s %s\n", e->type(), e->name() ); + } + + if ( recursive && map->baseMap ) + { + PanelAnimationDumpMap( map->baseMap, recursive ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPanelAnimationDictionary::PanelAnimationDumpVars( char const *className ) +{ + if ( className == NULL ) + { + for ( int i = 0; i < (int)m_AnimationMaps.Count(); i++ ) + { + PanelAnimationDumpMap( m_AnimationMaps[ i ].map, false ); + } + } + else + { + PanelAnimationMap *map = FindPanelAnimationMap( className ); + if ( map ) + { + PanelAnimationDumpMap( map, true ); + } + else + { + Msg( "No such Panel Animation class %s\n", className ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: singleton accessor +//----------------------------------------------------------------------------- +CPanelAnimationDictionary& GetPanelAnimationDictionary() +{ + static CPanelAnimationDictionary dictionary; + return dictionary; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +PanelAnimationMap *FindOrAddPanelAnimationMap( char const *className ) +{ + return GetPanelAnimationDictionary().FindOrAddPanelAnimationMap( className ); +} + +//----------------------------------------------------------------------------- +// Purpose: Find but don't add mapping +//----------------------------------------------------------------------------- +PanelAnimationMap *FindPanelAnimationMap( char const *className ) +{ + return GetPanelAnimationDictionary().FindPanelAnimationMap( className ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void PanelAnimationDumpVars( char const *className ) +{ + GetPanelAnimationDictionary().PanelAnimationDumpVars( className ); } \ No newline at end of file -- cgit v1.2.3