You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1401 lines
43 KiB
C++
1401 lines
43 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
|
|
#include "UiAnimationSystem.h"
|
|
#include "AnimSplineTrack.h"
|
|
#include "AnimSequence.h"
|
|
#include "AzEntityNode.h"
|
|
#include "UiAnimSerialize.h"
|
|
|
|
#include <AzCore/Component/ComponentApplicationBus.h>
|
|
#include <StlUtils.h>
|
|
|
|
#include <ISystem.h>
|
|
#include <ILog.h>
|
|
#include <IConsole.h>
|
|
#include <ITimer.h>
|
|
#include <IRenderer.h>
|
|
#include <IViewSystem.h>
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Serialization for anim nodes & param types
|
|
#define REGISTER_NODE_TYPE(name) assert(g_animNodeEnumToStringMap.find(eUiAnimNodeType_ ## name) == g_animNodeEnumToStringMap.end()); \
|
|
g_animNodeEnumToStringMap[eUiAnimNodeType_ ## name] = AZ_STRINGIZE(name); \
|
|
g_animNodeStringToEnumMap[AZStd::string(AZ_STRINGIZE(name))] = eUiAnimNodeType_ ## name;
|
|
|
|
#define REGISTER_PARAM_TYPE(name) assert(g_animParamEnumToStringMap.find(eUiAnimParamType_ ## name) == g_animParamEnumToStringMap.end()); \
|
|
g_animParamEnumToStringMap[eUiAnimParamType_ ## name] = AZ_STRINGIZE(name); \
|
|
g_animParamStringToEnumMap[AZStd::string(AZ_STRINGIZE(name))] = eUiAnimParamType_ ## name;
|
|
|
|
namespace
|
|
{
|
|
AZStd::unordered_map<int, AZStd::string> g_animNodeEnumToStringMap;
|
|
StaticInstance<std::map<AZStd::string, EUiAnimNodeType, stl::less_stricmp<AZStd::string> >> g_animNodeStringToEnumMap;
|
|
|
|
AZStd::unordered_map<int, AZStd::string> g_animParamEnumToStringMap;
|
|
StaticInstance<std::map<AZStd::string, EUiAnimParamType, stl::less_stricmp<AZStd::string> >> g_animParamStringToEnumMap;
|
|
|
|
// If you get an assert in this function, it means two node types have the same enum value.
|
|
void RegisterNodeTypes()
|
|
{
|
|
REGISTER_NODE_TYPE(Entity)
|
|
REGISTER_NODE_TYPE(Director)
|
|
REGISTER_NODE_TYPE(Camera)
|
|
REGISTER_NODE_TYPE(CVar)
|
|
REGISTER_NODE_TYPE(ScriptVar)
|
|
REGISTER_NODE_TYPE(Material)
|
|
REGISTER_NODE_TYPE(Event)
|
|
REGISTER_NODE_TYPE(Group)
|
|
REGISTER_NODE_TYPE(Layer)
|
|
REGISTER_NODE_TYPE(Comment)
|
|
REGISTER_NODE_TYPE(RadialBlur)
|
|
REGISTER_NODE_TYPE(ColorCorrection)
|
|
REGISTER_NODE_TYPE(DepthOfField)
|
|
REGISTER_NODE_TYPE(ScreenFader)
|
|
REGISTER_NODE_TYPE(Light)
|
|
REGISTER_NODE_TYPE(HDRSetup)
|
|
REGISTER_NODE_TYPE(ShadowSetup)
|
|
REGISTER_NODE_TYPE(Alembic)
|
|
REGISTER_NODE_TYPE(GeomCache)
|
|
REGISTER_NODE_TYPE(Environment)
|
|
REGISTER_NODE_TYPE(ScreenDropsSetup)
|
|
REGISTER_NODE_TYPE(AzEntity)
|
|
}
|
|
|
|
// If you get an assert in this function, it means two param types have the same enum value.
|
|
void RegisterParamTypes()
|
|
{
|
|
REGISTER_PARAM_TYPE(Event)
|
|
REGISTER_PARAM_TYPE(Float)
|
|
REGISTER_PARAM_TYPE(TrackEvent)
|
|
REGISTER_PARAM_TYPE(AzComponentField)
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
UiAnimationSystem::UiAnimationSystem()
|
|
{
|
|
m_pSystem = (gEnv) ? gEnv->pSystem : nullptr;
|
|
m_bRecording = false;
|
|
m_pCallback = NULL;
|
|
m_bPaused = false;
|
|
m_sequenceStopBehavior = eSSB_GotoEndTime;
|
|
m_lastUpdateTime.SetValue(0);
|
|
|
|
m_nextSequenceId = 1;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
UiAnimationSystem::~UiAnimationSystem()
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::DoNodeStaticInitialisation()
|
|
{
|
|
CUiAnimAzEntityNode::Initialize();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool UiAnimationSystem::Load(const char* pszFile, const char* pszMission)
|
|
{
|
|
INDENT_LOG_DURING_SCOPE (true, "UI Animation system is loading the file '%s' (mission='%s')", pszFile, pszMission);
|
|
LOADING_TIME_PROFILE_SECTION(GetISystem());
|
|
|
|
XmlNodeRef rootNode = m_pSystem->LoadXmlFromFile(pszFile);
|
|
if (!rootNode)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
XmlNodeRef Node = NULL;
|
|
|
|
for (int i = 0; i < rootNode->getChildCount(); i++)
|
|
{
|
|
XmlNodeRef missionNode = rootNode->getChild(i);
|
|
XmlString sName;
|
|
if (!(sName = missionNode->getAttr("Name")))
|
|
{
|
|
continue;
|
|
}
|
|
if (_stricmp(sName.c_str(), pszMission))
|
|
{
|
|
continue;
|
|
}
|
|
Node = missionNode;
|
|
break;
|
|
}
|
|
|
|
if (!Node)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Serialize(Node, true, true, false);
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IUiAnimTrack* UiAnimationSystem::CreateTrack([[maybe_unused]] EUiAnimCurveType type)
|
|
{
|
|
#if 0
|
|
switch (type)
|
|
{
|
|
case eUiAnimCurveType_TCBFloat:
|
|
return new CTcbFloatTrack;
|
|
case eUiAnimCurveType_TCBVector:
|
|
return new CTcbVectorTrack;
|
|
case eUiAnimCurveType_TCBQuat:
|
|
return new CTcbQuatTrack;
|
|
}
|
|
;
|
|
#endif
|
|
assert(0);
|
|
return 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IUiAnimSequence* UiAnimationSystem::CreateSequence(const char* pSequenceName, bool bLoad, uint32 id)
|
|
{
|
|
if (!bLoad)
|
|
{
|
|
id = m_nextSequenceId++;
|
|
}
|
|
|
|
IUiAnimSequence* pSequence = aznew CUiAnimSequence(this, id);
|
|
pSequence->SetName(pSequenceName);
|
|
m_sequences.push_back(pSequence);
|
|
return pSequence;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IUiAnimSequence* UiAnimationSystem::LoadSequence(const char* pszFilePath)
|
|
{
|
|
XmlNodeRef sequenceNode = m_pSystem->LoadXmlFromFile(pszFilePath);
|
|
if (sequenceNode)
|
|
{
|
|
return LoadSequence(sequenceNode);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IUiAnimSequence* UiAnimationSystem::LoadSequence(XmlNodeRef& xmlNode, bool bLoadEmpty)
|
|
{
|
|
IUiAnimSequence* pSequence = aznew CUiAnimSequence(this, 0);
|
|
pSequence->Serialize(xmlNode, true, bLoadEmpty);
|
|
|
|
// Delete previous sequence with the same name.
|
|
const char* pFullName = pSequence->GetName();
|
|
|
|
IUiAnimSequence* pPrevSeq = FindSequence(pFullName);
|
|
if (pPrevSeq)
|
|
{
|
|
RemoveSequence(pPrevSeq);
|
|
}
|
|
|
|
m_sequences.push_back(pSequence);
|
|
return pSequence;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IUiAnimSequence* UiAnimationSystem::FindSequence(const char* pSequenceName) const
|
|
{
|
|
assert(pSequenceName);
|
|
if (!pSequenceName)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for (Sequences::const_iterator it = m_sequences.begin(); it != m_sequences.end(); ++it)
|
|
{
|
|
IUiAnimSequence* pCurrentSequence = it->get();
|
|
const char* fullname = pCurrentSequence->GetName();
|
|
|
|
if (_stricmp(fullname, pSequenceName) == 0)
|
|
{
|
|
return pCurrentSequence;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IUiAnimSequence* UiAnimationSystem::FindSequenceById(uint32 id) const
|
|
{
|
|
if (id == 0 || id >= m_nextSequenceId)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for (Sequences::const_iterator it = m_sequences.begin(); it != m_sequences.end(); ++it)
|
|
{
|
|
IUiAnimSequence* pCurrentSequence = it->get();
|
|
if (id == pCurrentSequence->GetId())
|
|
{
|
|
return pCurrentSequence;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool UiAnimationSystem::FindSequence(IUiAnimSequence* pSequence, PlayingSequences::const_iterator& sequenceIteratorOut) const
|
|
{
|
|
PlayingSequences::const_iterator itend = m_playingSequences.end();
|
|
|
|
for (sequenceIteratorOut = m_playingSequences.begin(); sequenceIteratorOut != itend; ++sequenceIteratorOut)
|
|
{
|
|
if (sequenceIteratorOut->sequence == pSequence)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool UiAnimationSystem::FindSequence(IUiAnimSequence* pSequence, PlayingSequences::iterator& sequenceIteratorOut)
|
|
{
|
|
PlayingSequences::const_iterator itend = m_playingSequences.end();
|
|
|
|
for (sequenceIteratorOut = m_playingSequences.begin(); sequenceIteratorOut != itend; ++sequenceIteratorOut)
|
|
{
|
|
if (sequenceIteratorOut->sequence == pSequence)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IUiAnimSequence* UiAnimationSystem::GetSequence(int i) const
|
|
{
|
|
assert(i >= 0 && i < GetNumSequences());
|
|
|
|
if (i < 0 || i >= GetNumSequences())
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return m_sequences[i].get();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int UiAnimationSystem::GetNumSequences() const
|
|
{
|
|
return static_cast<int>(m_sequences.size());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IUiAnimSequence* UiAnimationSystem::GetPlayingSequence(int i) const
|
|
{
|
|
assert(i >= 0 && i < GetNumPlayingSequences());
|
|
|
|
if (i < 0 || i >= GetNumPlayingSequences())
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return m_playingSequences[i].sequence.get();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int UiAnimationSystem::GetNumPlayingSequences() const
|
|
{
|
|
return static_cast<int>(m_playingSequences.size());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::AddSequence(IUiAnimSequence* pSequence)
|
|
{
|
|
m_sequences.push_back(pSequence);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool UiAnimationSystem::IsCutScenePlaying() const
|
|
{
|
|
const uint numPlayingSequences = static_cast<uint>(m_playingSequences.size());
|
|
for (uint i = 0; i < numPlayingSequences; ++i)
|
|
{
|
|
const IUiAnimSequence* pAnimSequence = m_playingSequences[i].sequence.get();
|
|
if (pAnimSequence && (pAnimSequence->GetFlags() & IUiAnimSequence::eSeqFlags_CutScene) != 0)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::RemoveSequence(IUiAnimSequence* pSequence)
|
|
{
|
|
assert(pSequence != 0);
|
|
if (pSequence)
|
|
{
|
|
IUiAnimationCallback* pCallback = GetCallback();
|
|
SetCallback(NULL);
|
|
StopSequence(pSequence);
|
|
|
|
for (Sequences::iterator it = m_sequences.begin(); it != m_sequences.end(); ++it)
|
|
{
|
|
if (pSequence == *it)
|
|
{
|
|
m_animationListenerMap.erase(pSequence);
|
|
m_sequences.erase(it);
|
|
break;
|
|
}
|
|
}
|
|
SetCallback(pCallback);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int UiAnimationSystem::OnSequenceRenamed(const char* before, const char* after)
|
|
{
|
|
assert(before && after);
|
|
if (before == NULL || after == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
if (_stricmp(before, after) == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int count = 0;
|
|
|
|
// UI_ANIMATION_REVISIT : this only did anything for director nodes
|
|
|
|
return count;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int UiAnimationSystem::OnCameraRenamed([[maybe_unused]] const char* before, [[maybe_unused]] const char* after)
|
|
{
|
|
// UI_ANIMATION_REVISIT - not used
|
|
return 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::RemoveAllSequences()
|
|
{
|
|
IUiAnimationCallback* pCallback = GetCallback();
|
|
SetCallback(NULL);
|
|
InternalStopAllSequences(true, false);
|
|
|
|
stl::free_container(m_sequences);
|
|
|
|
for (TUiAnimationListenerMap::iterator it = m_animationListenerMap.begin(); it != m_animationListenerMap.end(); )
|
|
{
|
|
if (it->first)
|
|
{
|
|
m_animationListenerMap.erase(it++);
|
|
}
|
|
else
|
|
{
|
|
++it;
|
|
}
|
|
}
|
|
SetCallback(pCallback);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::PlaySequence(const char* pSequenceName, IUiAnimSequence* pParentSeq, bool bResetFx, bool bTrackedSequence, float startTime, float endTime)
|
|
{
|
|
IUiAnimSequence* pSequence = FindSequence(pSequenceName);
|
|
if (pSequence)
|
|
{
|
|
PlaySequence(pSequence, pParentSeq, bResetFx, bTrackedSequence, startTime, endTime);
|
|
}
|
|
else
|
|
{
|
|
gEnv->pLog->Log ("UiAnimationSystem::PlaySequence: Error: Sequence \"%s\" not found", pSequenceName);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::PlaySequence(IUiAnimSequence* pSequence, IUiAnimSequence* parentSeq,
|
|
[[maybe_unused]] bool bResetFx, bool bTrackedSequence, float startTime, float endTime)
|
|
{
|
|
assert(pSequence != 0);
|
|
if (!pSequence || IsPlaying(pSequence))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// If this sequence is cut scene disable player.
|
|
if (pSequence->GetFlags() & IUiAnimSequence::eSeqFlags_CutScene)
|
|
{
|
|
OnCameraCut();
|
|
|
|
pSequence->SetParentSequence(parentSeq);
|
|
}
|
|
|
|
pSequence->Activate();
|
|
pSequence->Resume();
|
|
static_cast<CUiAnimSequence*>(pSequence)->OnStart();
|
|
|
|
PlayingUIAnimSequence ps;
|
|
ps.sequence = pSequence;
|
|
ps.startTime = startTime == -FLT_MAX ? pSequence->GetTimeRange().start : startTime;
|
|
ps.endTime = endTime == -FLT_MAX ? pSequence->GetTimeRange().end : endTime;
|
|
ps.currentTime = startTime == -FLT_MAX ? pSequence->GetTimeRange().start : startTime;
|
|
ps.currentSpeed = 1.0f;
|
|
ps.trackedSequence = bTrackedSequence;
|
|
ps.bSingleFrame = false;
|
|
// Make sure all members are initialized before pushing.
|
|
m_playingSequences.push_back(ps);
|
|
|
|
// tell all interested listeners
|
|
NotifyListeners(pSequence, IUiAnimationListener::eUiAnimationEvent_Started);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::NotifyListeners(IUiAnimSequence* pSequence, IUiAnimationListener::EUiAnimationEvent event)
|
|
{
|
|
TUiAnimationListenerMap::iterator found (m_animationListenerMap.find(pSequence));
|
|
if (found != m_animationListenerMap.end())
|
|
{
|
|
TUiAnimationListenerVec listForSeq = (*found).second;
|
|
TUiAnimationListenerVec::iterator iter (listForSeq.begin());
|
|
while (iter != listForSeq.end())
|
|
{
|
|
(*iter)->OnUiAnimationEvent(event, pSequence);
|
|
++iter;
|
|
}
|
|
}
|
|
|
|
// 'NULL' ones are listeners interested in every sequence. Do not send "update" here
|
|
if (event != IUiAnimationListener::eUiAnimationEvent_Updated)
|
|
{
|
|
TUiAnimationListenerMap::iterator found2 (m_animationListenerMap.find((IUiAnimSequence*)0));
|
|
if (found2 != m_animationListenerMap.end())
|
|
{
|
|
TUiAnimationListenerVec listForSeq = (*found2).second;
|
|
TUiAnimationListenerVec::iterator iter (listForSeq.begin());
|
|
while (iter != listForSeq.end())
|
|
{
|
|
(*iter)->OnUiAnimationEvent(event, pSequence);
|
|
++iter;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::NotifyTrackEventListeners(const char* eventName, const char* valueName, IUiAnimSequence* pSequence)
|
|
{
|
|
TUiAnimationListenerMap::iterator found(m_animationListenerMap.find(pSequence));
|
|
if (found != m_animationListenerMap.end())
|
|
{
|
|
TUiAnimationListenerVec listForSeq = (*found).second;
|
|
TUiAnimationListenerVec::iterator iter(listForSeq.begin());
|
|
while (iter != listForSeq.end())
|
|
{
|
|
(*iter)->OnUiTrackEvent(AZStd::string(eventName), AZStd::string(valueName), pSequence);
|
|
++iter;
|
|
}
|
|
}
|
|
|
|
// 'NULL' ones are listeners interested in every sequence.
|
|
TUiAnimationListenerMap::iterator found2(m_animationListenerMap.find(static_cast<IUiAnimSequence*>(nullptr)));
|
|
if (found2 != m_animationListenerMap.end())
|
|
{
|
|
TUiAnimationListenerVec listForSeq = (*found2).second;
|
|
TUiAnimationListenerVec::iterator iter(listForSeq.begin());
|
|
while (iter != listForSeq.end())
|
|
{
|
|
(*iter)->OnUiTrackEvent(AZStd::string(eventName), AZStd::string(valueName), pSequence);
|
|
++iter;
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool UiAnimationSystem::StopSequence(const char* pSequenceName)
|
|
{
|
|
IUiAnimSequence* pSequence = FindSequence(pSequenceName);
|
|
if (pSequence)
|
|
{
|
|
return StopSequence(pSequence);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool UiAnimationSystem::StopSequence(IUiAnimSequence* pSequence)
|
|
{
|
|
return InternalStopSequence(pSequence, false, true);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::InternalStopAllSequences(bool bAbort, bool bAnimate)
|
|
{
|
|
while (!m_playingSequences.empty())
|
|
{
|
|
InternalStopSequence(m_playingSequences.begin()->sequence.get(), bAbort, bAnimate);
|
|
}
|
|
|
|
stl::free_container(m_playingSequences);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool UiAnimationSystem::InternalStopSequence(IUiAnimSequence* pSequence, bool bAbort, bool bAnimate)
|
|
{
|
|
assert(pSequence != 0);
|
|
|
|
bool bRet = false;
|
|
PlayingSequences::iterator it;
|
|
|
|
if (FindSequence(pSequence, it))
|
|
{
|
|
if (bAnimate)
|
|
{
|
|
if (m_sequenceStopBehavior == eSSB_GotoEndTime)
|
|
{
|
|
SUiAnimContext ac;
|
|
ac.bSingleFrame = true;
|
|
ac.time = pSequence->GetTimeRange().end;
|
|
pSequence->Animate(ac);
|
|
}
|
|
else if (m_sequenceStopBehavior == eSSB_GotoStartTime)
|
|
{
|
|
SUiAnimContext ac;
|
|
ac.bSingleFrame = true;
|
|
ac.time = pSequence->GetTimeRange().start;
|
|
pSequence->Animate(ac);
|
|
}
|
|
|
|
pSequence->Deactivate();
|
|
}
|
|
|
|
// tell all interested listeners
|
|
NotifyListeners(pSequence, bAbort ? IUiAnimationListener::eUiAnimationEvent_Aborted : IUiAnimationListener::eUiAnimationEvent_Stopped);
|
|
|
|
// erase the sequence after notifying listeners so if they choose to they can get the ending time of this sequence
|
|
if (FindSequence(pSequence, it))
|
|
{
|
|
m_playingSequences.erase(it);
|
|
}
|
|
|
|
pSequence->Resume();
|
|
static_cast<CUiAnimSequence*>(pSequence)->OnStop();
|
|
bRet = true;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool UiAnimationSystem::AbortSequence(IUiAnimSequence* pSequence, bool bLeaveTime)
|
|
{
|
|
assert(pSequence);
|
|
|
|
// to avoid any camera blending after aborting a cut scene
|
|
IViewSystem* pViewSystem = gEnv->pSystem->GetIViewSystem();
|
|
if (pViewSystem)
|
|
{
|
|
pViewSystem->SetBlendParams(0, 0, 0);
|
|
IView* pView = pViewSystem->GetActiveView();
|
|
if (pView)
|
|
{
|
|
pView->ResetBlending();
|
|
}
|
|
}
|
|
|
|
return InternalStopSequence(pSequence, true, !bLeaveTime);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::StopAllSequences()
|
|
{
|
|
InternalStopAllSequences(false, true);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::StopAllCutScenes()
|
|
{
|
|
bool bAnyStoped;
|
|
PlayingSequences::iterator next;
|
|
do
|
|
{
|
|
bAnyStoped = false;
|
|
for (PlayingSequences::iterator it = m_playingSequences.begin(); it != m_playingSequences.end(); it = next)
|
|
{
|
|
next = it;
|
|
++next;
|
|
IUiAnimSequence* pCurrentSequence = it->sequence.get();
|
|
if (pCurrentSequence->GetFlags() & IUiAnimSequence::eSeqFlags_CutScene)
|
|
{
|
|
bAnyStoped = true;
|
|
StopSequence(pCurrentSequence);
|
|
break;
|
|
}
|
|
}
|
|
} while (bAnyStoped);
|
|
|
|
if (m_playingSequences.empty())
|
|
{
|
|
stl::free_container(m_playingSequences);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool UiAnimationSystem::IsPlaying(IUiAnimSequence* pSequence) const
|
|
{
|
|
for (PlayingSequences::const_iterator it = m_playingSequences.begin(); it != m_playingSequences.end(); ++it)
|
|
{
|
|
if (it->sequence == pSequence)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::Reset(bool bPlayOnReset, bool bSeekToStart)
|
|
{
|
|
InternalStopAllSequences(true, false);
|
|
|
|
// Reset all sequences.
|
|
for (Sequences::iterator iter = m_sequences.begin(); iter != m_sequences.end(); ++iter)
|
|
{
|
|
IUiAnimSequence* pCurrentSequence = iter->get();
|
|
NotifyListeners(pCurrentSequence, IUiAnimationListener::eUiAnimationEvent_Started);
|
|
pCurrentSequence->Reset(bSeekToStart);
|
|
NotifyListeners(pCurrentSequence, IUiAnimationListener::eUiAnimationEvent_Stopped);
|
|
}
|
|
|
|
if (bPlayOnReset)
|
|
{
|
|
for (Sequences::iterator iter = m_sequences.begin(); iter != m_sequences.end(); ++iter)
|
|
{
|
|
IUiAnimSequence* pCurrentSequence = iter->get();
|
|
if (pCurrentSequence->GetFlags() & IUiAnimSequence::eSeqFlags_PlayOnReset)
|
|
{
|
|
PlaySequence(pCurrentSequence);
|
|
}
|
|
}
|
|
}
|
|
|
|
// un-pause the UI animation system
|
|
m_bPaused = false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::PlayOnLoadSequences()
|
|
{
|
|
for (Sequences::iterator sit = m_sequences.begin(); sit != m_sequences.end(); ++sit)
|
|
{
|
|
IUiAnimSequence* pSequence = sit->get();
|
|
if (pSequence->GetFlags() & IUiAnimSequence::eSeqFlags_PlayOnReset)
|
|
{
|
|
PlaySequence(pSequence);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::StillUpdate()
|
|
{
|
|
if (!gEnv->IsEditor())
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (PlayingSequences::iterator it = m_playingSequences.begin(); it != m_playingSequences.end(); ++it)
|
|
{
|
|
PlayingUIAnimSequence& playingSequence = *it;
|
|
|
|
playingSequence.sequence->StillUpdate();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::ShowPlayedSequencesDebug()
|
|
{
|
|
f32 green[4] = {0, 1, 0, 1};
|
|
f32 purple[4] = {1, 0, 1, 1};
|
|
f32 white[4] = {1, 1, 1, 1};
|
|
float y = 10.0f;
|
|
AZStd::vector<AZStd::string> names;
|
|
|
|
for (PlayingSequences::iterator it = m_playingSequences.begin(); it != m_playingSequences.end(); ++it)
|
|
{
|
|
PlayingUIAnimSequence& playingSequence = *it;
|
|
|
|
if (playingSequence.sequence == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const char* fullname = playingSequence.sequence->GetName();
|
|
gEnv->pRenderer->Draw2dLabel(1.0f, y, 1.3f, green, false, "Sequence %s : %f (x %f)", fullname, playingSequence.currentTime, playingSequence.currentSpeed);
|
|
|
|
y += 16.0f;
|
|
|
|
for (int i = 0; i < playingSequence.sequence->GetNodeCount(); ++i)
|
|
{
|
|
// Checks nodes which happen to be in several sequences.
|
|
// Those can be a bug, since several sequences may try to control the same entity.
|
|
AZStd::string name = playingSequence.sequence->GetNode(i)->GetName();
|
|
bool alreadyThere = false;
|
|
if (AZStd::find(names.begin(), names.end(), name) != names.end())
|
|
{
|
|
alreadyThere = true;
|
|
}
|
|
else
|
|
{
|
|
names.push_back(name);
|
|
}
|
|
|
|
gEnv->pRenderer->Draw2dLabel((21.0f + 100.0f * i), ((i % 2) ? (y + 8.0f) : y), 1.0f, alreadyThere ? white : purple, false, "%s", name.c_str());
|
|
}
|
|
|
|
y += 32.0f;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::PreUpdate(float deltaTime)
|
|
{
|
|
UpdateInternal(deltaTime, true);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::PostUpdate(float deltaTime)
|
|
{
|
|
UpdateInternal(deltaTime, false);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::UpdateInternal(const float deltaTime, const bool bPreUpdate)
|
|
{
|
|
SUiAnimContext animContext;
|
|
|
|
if (m_bPaused)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// don't update more than once if dt==0.0
|
|
CTimeValue curTime = gEnv->pTimer->GetFrameStartTime();
|
|
if (deltaTime == 0.0f && curTime == m_lastUpdateTime && !gEnv->IsEditor())
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_lastUpdateTime = curTime;
|
|
|
|
float fps = 60.0f;
|
|
|
|
std::vector<IUiAnimSequence*> stopSequences;
|
|
|
|
const size_t numPlayingSequences = m_playingSequences.size();
|
|
for (size_t i = 0; i < numPlayingSequences; ++i)
|
|
{
|
|
PlayingUIAnimSequence& playingSequence = m_playingSequences[i];
|
|
|
|
if (playingSequence.sequence->IsPaused())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const float scaledTimeDelta = deltaTime * playingSequence.currentSpeed;
|
|
|
|
// Increase play time in pre-update
|
|
if (bPreUpdate)
|
|
{
|
|
playingSequence.currentTime += scaledTimeDelta;
|
|
}
|
|
|
|
// Skip sequence if current update does not apply
|
|
const bool bSequenceEarlyUpdate = (playingSequence.sequence->GetFlags() & IUiAnimSequence::eSeqFlags_EarlyAnimationUpdate) != 0;
|
|
if (bPreUpdate && !bSequenceEarlyUpdate || !bPreUpdate && bSequenceEarlyUpdate)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
animContext.time = playingSequence.currentTime;
|
|
animContext.pSequence = playingSequence.sequence.get();
|
|
animContext.dt = scaledTimeDelta;
|
|
animContext.fps = fps;
|
|
animContext.startTime = playingSequence.startTime;
|
|
|
|
// Check time out of range, setting up playingSequence for the next Update
|
|
bool wasLooped = false;
|
|
if (playingSequence.currentTime > playingSequence.endTime)
|
|
{
|
|
int seqFlags = playingSequence.sequence->GetFlags();
|
|
if (seqFlags & IUiAnimSequence::eSeqFlags_OutOfRangeLoop)
|
|
{
|
|
// Time wrap's back to the start of the time range.
|
|
playingSequence.currentTime = playingSequence.startTime; // should there be a fmodf here?
|
|
wasLooped = true;
|
|
}
|
|
else if (seqFlags & IUiAnimSequence::eSeqFlags_OutOfRangeConstant)
|
|
{
|
|
// Time just continues normally past the end of time range.
|
|
}
|
|
else
|
|
{
|
|
// If no out-of-range type specified sequence stopped when time reaches end of range.
|
|
// Que sequence for stopping.
|
|
if (playingSequence.trackedSequence == false)
|
|
{
|
|
stopSequences.push_back(playingSequence.sequence.get());
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NotifyListeners(playingSequence.sequence.get(), IUiAnimationListener::eUiAnimationEvent_Updated);
|
|
}
|
|
|
|
animContext.bSingleFrame = playingSequence.bSingleFrame;
|
|
playingSequence.bSingleFrame = false;
|
|
|
|
// Animate sequence. (Can invalidate iterator)
|
|
playingSequence.sequence->Animate(animContext);
|
|
|
|
// we call OnLoop() *after* Animate() to reset sounds (for CUiAnimSceneNodes), for the next update (the looped update)
|
|
if (wasLooped)
|
|
{
|
|
playingSequence.sequence->OnLoop();
|
|
}
|
|
}
|
|
|
|
// Stop queued sequences.
|
|
for (int i = 0; i < (int)stopSequences.size(); i++)
|
|
{
|
|
StopSequence(stopSequences[i]);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::Render()
|
|
{
|
|
for (PlayingSequences::iterator it = m_playingSequences.begin(); it != m_playingSequences.end(); ++it)
|
|
{
|
|
PlayingUIAnimSequence& playingSequence = *it;
|
|
playingSequence.sequence->Render();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::Callback(IUiAnimationCallback::ECallbackReason reason, IUiAnimNode* pNode)
|
|
{
|
|
if (m_pCallback)
|
|
{
|
|
m_pCallback->OnUiAnimationCallback(reason, pNode);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::Serialize(XmlNodeRef& xmlNode, bool bLoading, [[maybe_unused]] bool bRemoveOldNodes, bool bLoadEmpty)
|
|
{
|
|
if (bLoading)
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Load sequences from XML.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
XmlNodeRef seqNode = xmlNode->findChild("SequenceData");
|
|
if (seqNode)
|
|
{
|
|
RemoveAllSequences();
|
|
|
|
INDENT_LOG_DURING_SCOPE(true, "SequenceData tag contains %u sequences", seqNode->getChildCount());
|
|
|
|
for (int i = 0; i < seqNode->getChildCount(); i++)
|
|
{
|
|
XmlNodeRef childNode = seqNode->getChild(i);
|
|
if (!LoadSequence(childNode, bLoadEmpty))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XmlNodeRef sequencesNode = xmlNode->newChild("SequenceData");
|
|
for (int i = 0; i < GetNumSequences(); ++i)
|
|
{
|
|
IUiAnimSequence* pSequence = GetSequence(i);
|
|
XmlNodeRef sequenceNode = sequencesNode->newChild("Sequence");
|
|
pSequence->Serialize(sequenceNode, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::InitPostLoad(bool remapIds, LyShine::EntityIdMap* entityIdMap)
|
|
{
|
|
for (int i = 0; i < GetNumSequences(); ++i)
|
|
{
|
|
IUiAnimSequence* pSequence = GetSequence(i);
|
|
pSequence->InitPostLoad(this, remapIds, entityIdMap);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::Pause()
|
|
{
|
|
m_bPaused = true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::Resume()
|
|
{
|
|
m_bPaused = false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
float UiAnimationSystem::GetPlayingTime(IUiAnimSequence* pSequence)
|
|
{
|
|
if (!pSequence || !IsPlaying(pSequence))
|
|
{
|
|
return -1.0;
|
|
}
|
|
|
|
PlayingSequences::const_iterator it;
|
|
if (FindSequence(pSequence, it))
|
|
{
|
|
return it->currentTime;
|
|
}
|
|
|
|
return -1.0f;
|
|
}
|
|
|
|
float UiAnimationSystem::GetPlayingSpeed(IUiAnimSequence* pSequence)
|
|
{
|
|
if (!pSequence || !IsPlaying(pSequence))
|
|
{
|
|
return -1.0f;
|
|
}
|
|
|
|
PlayingSequences::const_iterator it;
|
|
if (FindSequence(pSequence, it))
|
|
{
|
|
return it->currentSpeed;
|
|
}
|
|
|
|
return -1.0f;
|
|
}
|
|
|
|
bool UiAnimationSystem::SetPlayingTime(IUiAnimSequence* pSequence, float fTime)
|
|
{
|
|
if (!pSequence || !IsPlaying(pSequence))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
PlayingSequences::iterator it;
|
|
if (FindSequence(pSequence, it) && !(pSequence->GetFlags() & IUiAnimSequence::eSeqFlags_NoSeek))
|
|
{
|
|
it->currentTime = fTime;
|
|
it->bSingleFrame = true;
|
|
NotifyListeners(pSequence, IUiAnimationListener::eUiAnimationEvent_Updated);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool UiAnimationSystem::SetPlayingSpeed(IUiAnimSequence* pSequence, float fSpeed)
|
|
{
|
|
if (!pSequence)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
PlayingSequences::iterator it;
|
|
if (FindSequence(pSequence, it) && !(pSequence->GetFlags() & IUiAnimSequence::eSeqFlags_NoSpeed))
|
|
{
|
|
NotifyListeners(pSequence, IUiAnimationListener::eUiAnimationEvent_Updated);
|
|
it->currentSpeed = fSpeed;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool UiAnimationSystem::GetStartEndTime(IUiAnimSequence* pSequence, float& fStartTime, float& fEndTime)
|
|
{
|
|
fStartTime = 0.0f;
|
|
fEndTime = 0.0f;
|
|
|
|
if (!pSequence || !IsPlaying(pSequence))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
PlayingSequences::const_iterator it;
|
|
if (FindSequence(pSequence, it))
|
|
{
|
|
fStartTime = it->startTime;
|
|
fEndTime = it->endTime;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool UiAnimationSystem::SetStartEndTime(IUiAnimSequence* pSeq, const float fStartTime, const float fEndTime)
|
|
{
|
|
if (!pSeq || !IsPlaying(pSeq))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
PlayingSequences::iterator it;
|
|
if (FindSequence(pSeq, it))
|
|
{
|
|
it->startTime = fStartTime;
|
|
it->endTime = fEndTime;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void UiAnimationSystem::SetSequenceStopBehavior(ESequenceStopBehavior behavior)
|
|
{
|
|
m_sequenceStopBehavior = behavior;
|
|
}
|
|
|
|
IUiAnimationSystem::ESequenceStopBehavior UiAnimationSystem::GetSequenceStopBehavior()
|
|
{
|
|
return m_sequenceStopBehavior;
|
|
}
|
|
|
|
bool UiAnimationSystem::AddUiAnimationListener(IUiAnimSequence* pSequence, IUiAnimationListener* pListener)
|
|
{
|
|
assert (pListener != 0);
|
|
if (pSequence != NULL && std::find(m_sequences.begin(), m_sequences.end(), pSequence) == m_sequences.end())
|
|
{
|
|
gEnv->pLog->Log ("UiAnimationSystem::AddUiAnimationListener: Sequence %p unknown to UiAnimationSystem", pSequence);
|
|
return false;
|
|
}
|
|
|
|
return stl::push_back_unique(m_animationListenerMap[pSequence], pListener);
|
|
}
|
|
|
|
bool UiAnimationSystem::RemoveUiAnimationListener(IUiAnimSequence* pSequence, IUiAnimationListener* pListener)
|
|
{
|
|
assert (pListener != 0);
|
|
if (pSequence != NULL
|
|
&& std::find(m_sequences.begin(), m_sequences.end(), pSequence) == m_sequences.end())
|
|
{
|
|
gEnv->pLog->Log ("UiAnimationSystem::AddUiAnimationListener: Sequence %p unknown to UiAnimationSystem", pSequence);
|
|
return false;
|
|
}
|
|
return stl::find_and_erase(m_animationListenerMap[pSequence], pListener);
|
|
}
|
|
|
|
void UiAnimationSystem::GoToFrame(const char* seqName, float targetFrame)
|
|
{
|
|
assert(seqName != NULL);
|
|
|
|
for (PlayingSequences::iterator it = m_playingSequences.begin();
|
|
it != m_playingSequences.end(); ++it)
|
|
{
|
|
PlayingUIAnimSequence& ps = *it;
|
|
|
|
const char* fullname = ps.sequence->GetName();
|
|
if (strcmp(fullname, seqName) == 0)
|
|
{
|
|
assert(ps.sequence->GetTimeRange().start <= targetFrame && targetFrame <= ps.sequence->GetTimeRange().end);
|
|
ps.currentTime = targetFrame;
|
|
ps.bSingleFrame = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::SerializeNodeType(EUiAnimNodeType& animNodeType, XmlNodeRef& xmlNode, bool bLoading, const uint version, int flags)
|
|
{
|
|
static const char* kType = "Type";
|
|
|
|
if (bLoading)
|
|
{
|
|
// Old serialization values that are no longer
|
|
// defined in IUiAnimationSystem.h, but needed for conversion:
|
|
static const int kOldParticleNodeType = 0x18;
|
|
|
|
animNodeType = eUiAnimNodeType_Invalid;
|
|
|
|
// In old versions there was special code for particles
|
|
// that is now handles by generic entity node code
|
|
if (version == 0 && animNodeType == kOldParticleNodeType)
|
|
{
|
|
animNodeType = eUiAnimNodeType_Entity;
|
|
return;
|
|
}
|
|
|
|
// Convert light nodes that are not part of a light
|
|
// animation set to common entity nodes
|
|
if (version <= 1 && animNodeType == eUiAnimNodeType_Light && !(flags & IUiAnimSequence::eSeqFlags_LightAnimationSet))
|
|
{
|
|
animNodeType = eUiAnimNodeType_Entity;
|
|
return;
|
|
}
|
|
|
|
if (version <= 2)
|
|
{
|
|
int type;
|
|
if (xmlNode->getAttr(kType, type))
|
|
{
|
|
animNodeType = (EUiAnimNodeType)type;
|
|
}
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
XmlString nodeTypeString;
|
|
if (xmlNode->getAttr(kType, nodeTypeString))
|
|
{
|
|
assert(g_animNodeStringToEnumMap.find(nodeTypeString.c_str()) != g_animNodeStringToEnumMap.end());
|
|
animNodeType = stl::find_in_map(g_animNodeStringToEnumMap, nodeTypeString.c_str(), eUiAnimNodeType_Invalid);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const char* pTypeString = "Invalid";
|
|
assert(g_animNodeEnumToStringMap.find(animNodeType) != g_animNodeEnumToStringMap.end());
|
|
pTypeString = g_animNodeEnumToStringMap[animNodeType].c_str();
|
|
xmlNode->setAttr(kType, pTypeString);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::SerializeParamType(CUiAnimParamType& animParamType, XmlNodeRef& xmlNode, bool bLoading, const uint version)
|
|
{
|
|
static const char* kByNameAttrName = "paramIdIsName";
|
|
static const char* kParamUserValue = "paramUserValue";
|
|
|
|
if (bLoading)
|
|
{
|
|
animParamType.m_type = eUiAnimParamType_Invalid;
|
|
|
|
if (version <= 6)
|
|
{
|
|
static const char* kParamId = "paramId";
|
|
|
|
if (xmlNode->haveAttr(kByNameAttrName))
|
|
{
|
|
XmlString name;
|
|
if (xmlNode->getAttr(kParamId, name))
|
|
{
|
|
animParamType.m_type = eUiAnimParamType_ByString;
|
|
animParamType.m_name = name.c_str();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int type;
|
|
xmlNode->getAttr(kParamId, type);
|
|
animParamType.m_type = (EUiAnimParamType)type;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
static const char* kParamType = "paramType";
|
|
|
|
XmlString paramTypeString;
|
|
if (xmlNode->getAttr(kParamType, paramTypeString))
|
|
{
|
|
if (paramTypeString == "ByString")
|
|
{
|
|
animParamType.m_type = eUiAnimParamType_ByString;
|
|
|
|
XmlString userValue;
|
|
xmlNode->getAttr(kParamUserValue, userValue);
|
|
animParamType.m_name = userValue;
|
|
}
|
|
else if (paramTypeString == "User")
|
|
{
|
|
animParamType.m_type = eUiAnimParamType_User;
|
|
|
|
int type;
|
|
xmlNode->getAttr(kParamUserValue, type);
|
|
animParamType.m_type = (EUiAnimParamType)type;
|
|
}
|
|
else
|
|
{
|
|
assert(g_animParamStringToEnumMap.find(paramTypeString.c_str()) != g_animParamStringToEnumMap.end());
|
|
animParamType.m_type = stl::find_in_map(g_animParamStringToEnumMap, paramTypeString.c_str(), eUiAnimParamType_Invalid);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
static const char* kParamType = "paramType";
|
|
const char* pTypeString = "Invalid";
|
|
|
|
if (animParamType.m_type == eUiAnimParamType_ByString)
|
|
{
|
|
pTypeString = "ByString";
|
|
xmlNode->setAttr(kParamUserValue, animParamType.m_name.c_str());
|
|
}
|
|
else if (animParamType.m_type >= eUiAnimParamType_User)
|
|
{
|
|
pTypeString = "User";
|
|
xmlNode->setAttr(kParamUserValue, (int)animParamType.m_type);
|
|
}
|
|
else
|
|
{
|
|
assert(g_animParamEnumToStringMap.find(animParamType.m_type) != g_animParamEnumToStringMap.end());
|
|
pTypeString = g_animParamEnumToStringMap[animParamType.m_type].c_str();
|
|
}
|
|
|
|
xmlNode->setAttr(kParamType, pTypeString);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::SerializeParamData(UiAnimParamData& animParamData, XmlNodeRef& xmlNode, bool bLoading)
|
|
{
|
|
static const char* kLabelComponentIdHi = "ParamComponentIdHi";
|
|
static const char* kLabelComponentIdLo = "ParamComponentIdLo";
|
|
static const char* kLabelTypeId = "ParamTypeId";
|
|
static const char* kLabelName = "ParamName";
|
|
static const char* kLabelOffset = "ParamOffset";
|
|
|
|
if (bLoading)
|
|
{
|
|
unsigned long idHi = 0;
|
|
unsigned long idLo = 0;
|
|
XmlString uuidStr;
|
|
XmlString nameStr;
|
|
size_t offset = 0;
|
|
|
|
xmlNode->getAttr(kLabelComponentIdHi, idHi);
|
|
xmlNode->getAttr(kLabelComponentIdLo, idLo);
|
|
xmlNode->getAttr(kLabelTypeId, uuidStr);
|
|
xmlNode->getAttr(kLabelName, nameStr);
|
|
xmlNode->getAttr(kLabelOffset, offset);
|
|
|
|
AZ::u64 id64 = ((AZ::u64)idHi) << 32 | idLo;
|
|
AZ::Uuid uuid(uuidStr.c_str(), uuidStr.length());
|
|
|
|
animParamData = UiAnimParamData(id64, nameStr.c_str(), uuid, offset);
|
|
}
|
|
else
|
|
{
|
|
AZ::u64 id64 = animParamData.GetComponentId();
|
|
unsigned long idHi = id64 >> 32;
|
|
unsigned long idLo = id64 & 0xFFFFFFFF;
|
|
|
|
XmlString uuidStr = animParamData.GetTypeId().ToString<XmlString>();
|
|
XmlString nameStr(animParamData.GetName());
|
|
size_t offset = animParamData.GetOffset();
|
|
|
|
xmlNode->setAttr(kLabelComponentIdHi, idHi);
|
|
xmlNode->setAttr(kLabelComponentIdLo, idLo);
|
|
xmlNode->setAttr(kLabelTypeId, uuidStr);
|
|
xmlNode->setAttr(kLabelName, nameStr);
|
|
xmlNode->setAttr(kLabelOffset, offset);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
const char* UiAnimationSystem::GetParamTypeName(const CUiAnimParamType& animParamType)
|
|
{
|
|
if (animParamType.m_type == eUiAnimParamType_ByString)
|
|
{
|
|
return animParamType.GetName();
|
|
}
|
|
else if (animParamType.m_type >= eUiAnimParamType_User)
|
|
{
|
|
return "User";
|
|
}
|
|
else
|
|
{
|
|
if (g_animParamEnumToStringMap.find(animParamType.m_type) != g_animParamEnumToStringMap.end())
|
|
{
|
|
return g_animParamEnumToStringMap[animParamType.m_type].c_str();
|
|
}
|
|
}
|
|
|
|
return "Invalid";
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::OnCameraCut()
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::StaticInitialize()
|
|
{
|
|
DoNodeStaticInitialisation();
|
|
|
|
RegisterNodeTypes();
|
|
RegisterParamTypes();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void UiAnimationSystem::Reflect(AZ::SerializeContext* serializeContext)
|
|
{
|
|
serializeContext->Class<UiAnimationSystem>()
|
|
->Version(1)
|
|
->Field("Sequences", &UiAnimationSystem::m_sequences);
|
|
|
|
UiAnimSerialize::ReflectUiAnimTypes(serializeContext);
|
|
|
|
// These rely on these classes having a friend declaration for this class
|
|
serializeContext->Class<CUiAnimParamType>()
|
|
->Version(1)
|
|
->Field("Type", &CUiAnimParamType::m_type);
|
|
|
|
serializeContext->Class<UiAnimParamData>()
|
|
->Version(1)
|
|
->Field("ComponentId", &UiAnimParamData::m_componentId)
|
|
->Field("TypeId", &UiAnimParamData::m_typeId)
|
|
->Field("Name", &UiAnimParamData::m_name);
|
|
}
|
|
|
|
#ifdef UI_ANIMATION_SYSTEM_SUPPORT_EDITING
|
|
//////////////////////////////////////////////////////////////////////////
|
|
EUiAnimNodeType UiAnimationSystem::GetNodeTypeFromString(const char* pString) const
|
|
{
|
|
return stl::find_in_map(g_animNodeStringToEnumMap, pString, eUiAnimNodeType_Invalid);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CUiAnimParamType UiAnimationSystem::GetParamTypeFromString(const char* pString) const
|
|
{
|
|
const EUiAnimParamType paramType = stl::find_in_map(g_animParamStringToEnumMap, pString, eUiAnimParamType_Invalid);
|
|
|
|
if (paramType != eUiAnimParamType_Invalid)
|
|
{
|
|
return CUiAnimParamType(paramType);
|
|
}
|
|
|
|
return CUiAnimParamType(pString);
|
|
}
|
|
#endif
|