123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233 |
- /*
- * 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
- *
- */
- // Description : Implementation of IAnimSequence interface.
- #include "AnimSequence.h"
- #include "StlUtils.h"
- #include "EventNode.h"
- #include "AzEntityNode.h"
- #include "UiAnimSerialize.h"
- //////////////////////////////////////////////////////////////////////////
- CUiAnimSequence::CUiAnimSequence()
- : CUiAnimSequence(nullptr, 0)
- {
- }
- //////////////////////////////////////////////////////////////////////////
- CUiAnimSequence::CUiAnimSequence(IUiAnimationSystem* pUiAnimationSystem, uint32 id)
- : m_refCount(0)
- {
- m_nextGenId = 1;
- m_pUiAnimationSystem = pUiAnimationSystem;
- m_flags = 0;
- m_pParentSequence = NULL;
- m_timeRange.Set(0, 10);
- m_bPaused = false;
- m_bActive = false;
- m_pOwner = NULL;
- m_pActiveDirector = NULL;
- m_precached = false;
- m_bResetting = false;
- m_id = id;
- m_time = -FLT_MAX;
- m_pEventStrings = aznew CUiAnimStringTable;
- }
- //////////////////////////////////////////////////////////////////////////
- CUiAnimSequence::~CUiAnimSequence()
- {
- // clear reference to me from all my nodes
- for (int i = static_cast<int>(m_nodes.size()); --i >= 0;)
- {
- if (m_nodes[i])
- {
- m_nodes[i]->SetSequence(nullptr);
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::add_ref()
- {
- ++m_refCount;
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::release()
- {
- if (--m_refCount <= 0)
- {
- delete this;
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::SetName(const char* name)
- {
- if (!m_pUiAnimationSystem)
- {
- return; // should never happen, null pointer guard
- }
- AZStd::string originalName = GetName();
- m_name = name;
- m_pUiAnimationSystem->OnSequenceRenamed(originalName.c_str(), m_name.c_str());
- if (GetOwner())
- {
- GetOwner()->OnModified();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- const char* CUiAnimSequence::GetName() const
- {
- return m_name.c_str();
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::SetFlags(int flags)
- {
- m_flags = flags;
- }
- //////////////////////////////////////////////////////////////////////////
- int CUiAnimSequence::GetFlags() const
- {
- return m_flags;
- }
- //////////////////////////////////////////////////////////////////////////
- int CUiAnimSequence::GetCutSceneFlags(const bool localFlags) const
- {
- int currentFlags = m_flags & (eSeqFlags_NoHUD | eSeqFlags_NoPlayer | eSeqFlags_16To9 | eSeqFlags_NoGameSounds | eSeqFlags_NoAbort);
- if (m_pParentSequence != NULL)
- {
- if (localFlags == true)
- {
- currentFlags &= ~m_pParentSequence->GetCutSceneFlags();
- }
- else
- {
- currentFlags |= m_pParentSequence->GetCutSceneFlags();
- }
- }
- return currentFlags;
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::SetParentSequence(IUiAnimSequence* pParentSequence)
- {
- m_pParentSequence = pParentSequence;
- }
- //////////////////////////////////////////////////////////////////////////
- const IUiAnimSequence* CUiAnimSequence::GetParentSequence() const
- {
- return m_pParentSequence;
- }
- //////////////////////////////////////////////////////////////////////////
- int CUiAnimSequence::GetNodeCount() const
- {
- return static_cast<int>(m_nodes.size());
- }
- //////////////////////////////////////////////////////////////////////////
- IUiAnimNode* CUiAnimSequence::GetNode(int index) const
- {
- assert(index >= 0 && index < (int)m_nodes.size());
- return m_nodes[index].get();
- }
- //////////////////////////////////////////////////////////////////////////
- bool CUiAnimSequence::AddNode(IUiAnimNode* pAnimNode)
- {
- AZ_Assert(pAnimNode, "Expected valid animNode");
- if(!pAnimNode)
- {
- return false;
- }
- pAnimNode->SetSequence(this);
- pAnimNode->SetTimeRange(m_timeRange);
- // Check if this node already in sequence.
- bool found = false;
- for (int i = 0; i < (int)m_nodes.size(); i++)
- {
- if (pAnimNode == m_nodes[i].get())
- {
- found = true;
- break;
- }
- }
- if (!found)
- {
- m_nodes.push_back(AZStd::intrusive_ptr<IUiAnimNode>(pAnimNode));
- }
- const int nodeId = static_cast<CUiAnimNode*>(pAnimNode)->GetId();
- if (nodeId >= static_cast<int>(m_nextGenId))
- {
- m_nextGenId = nodeId + 1;
- }
- if (pAnimNode->NeedToRender())
- {
- AddNodeNeedToRender(pAnimNode);
- }
- bool bNewDirectorNode = m_pActiveDirector == NULL && pAnimNode->GetType() == eUiAnimNodeType_Director;
- if (bNewDirectorNode)
- {
- m_pActiveDirector = pAnimNode;
- }
- return true;
- }
- //////////////////////////////////////////////////////////////////////////
- IUiAnimNode* CUiAnimSequence::CreateNodeInternal(EUiAnimNodeType nodeType, uint32 nNodeId)
- {
- CUiAnimNode* pAnimNode = NULL;
- if (nNodeId == -1)
- {
- nNodeId = m_nextGenId;
- }
- switch (nodeType)
- {
- case eUiAnimNodeType_AzEntity:
- pAnimNode = aznew CUiAnimAzEntityNode(nNodeId);
- break;
- case eUiAnimNodeType_Event:
- pAnimNode = aznew CUiAnimEventNode(nNodeId);
- break;
- }
- if (pAnimNode)
- {
- AddNode(pAnimNode);
- }
- return pAnimNode;
- }
- //////////////////////////////////////////////////////////////////////////
- IUiAnimNode* CUiAnimSequence::CreateNode(EUiAnimNodeType nodeType)
- {
- return CreateNodeInternal(nodeType);
- }
- //////////////////////////////////////////////////////////////////////////
- IUiAnimNode* CUiAnimSequence::CreateNode(XmlNodeRef node)
- {
- if (!GetUiAnimationSystem())
- {
- return 0; // should never happen, null pointer guard
- }
- EUiAnimNodeType type;
- static_cast<UiAnimationSystem*>(GetUiAnimationSystem())->SerializeNodeType(type, node, true, IUiAnimSequence::kSequenceVersion, 0);
- XmlString name;
- if (!node->getAttr("Name", name))
- {
- return 0;
- }
- IUiAnimNode* pNewNode = CreateNode(type);
- if (!pNewNode)
- {
- return 0;
- }
- pNewNode->SetName(name);
- pNewNode->Serialize(node, true, true);
- CUiAnimNode* newAnimNode = static_cast<CUiAnimNode*>(pNewNode);
- // Make sure de-serializing this node didn't just create an id conflict. This can happen sometimes
- // when copy/pasting nodes from a different sequence to this one.
- for (auto curNode : m_nodes)
- {
- CUiAnimNode* animNode = static_cast<CUiAnimNode*>(curNode.get());
- if (animNode->GetId() == newAnimNode->GetId() && animNode != newAnimNode)
- {
- // Conflict detected, resolve it by assigning a new id to the new node.
- newAnimNode->SetId(m_nextGenId++);
- }
- }
- return pNewNode;
- }
- //////////////////////////////////////////////////////////////////////////
- // Only called from undo/redo
- void CUiAnimSequence::RemoveNode(IUiAnimNode* node)
- {
- assert(node != 0);
- static_cast<CUiAnimNode*>(node)->Activate(false);
- static_cast<CUiAnimNode*>(node)->OnReset();
- for (int i = 0; i < (int)m_nodes.size(); )
- {
- if (node == m_nodes[i].get())
- {
- m_nodes.erase(m_nodes.begin() + i);
- if (node->NeedToRender())
- {
- RemoveNodeNeedToRender(node);
- }
- continue;
- }
- if (m_nodes[i]->GetParent() == node)
- {
- m_nodes[i]->SetParent(0);
- }
- i++;
- }
- // The removed one was the active director node.
- if (m_pActiveDirector == node)
- {
- // Clear the active one.
- m_pActiveDirector = NULL;
- // If there is another director node, set it as active.
- for (AnimNodes::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pNode = it->get();
- if (pNode->GetType() == eUiAnimNodeType_Director)
- {
- SetActiveDirector(pNode);
- break;
- }
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::RemoveAll()
- {
- stl::free_container(m_nodes);
- stl::free_container(m_events);
- stl::free_container(m_nodesNeedToRender);
- m_pActiveDirector = NULL;
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::Reset(bool bSeekToStart)
- {
- if (GetFlags() & eSeqFlags_LightAnimationSet)
- {
- return;
- }
- m_precached = false;
- m_bResetting = true;
- if (!bSeekToStart)
- {
- for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- static_cast<CUiAnimNode*>(pAnimNode)->OnReset();
- }
- m_bResetting = false;
- return;
- }
- bool bWasActive = m_bActive;
- if (!bWasActive)
- {
- Activate();
- }
- SUiAnimContext ec;
- ec.bSingleFrame = true;
- ec.bResetting = true;
- ec.pSequence = this;
- ec.time = m_timeRange.start;
- Animate(ec);
- if (!bWasActive)
- {
- Deactivate();
- }
- else
- {
- for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- static_cast<CUiAnimNode*>(pAnimNode)->OnReset();
- }
- }
- m_bResetting = false;
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::ResetHard()
- {
- if (GetFlags() & eSeqFlags_LightAnimationSet)
- {
- return;
- }
- m_bResetting = true;
- bool bWasActive = m_bActive;
- if (!bWasActive)
- {
- Activate();
- }
- SUiAnimContext ec;
- ec.bSingleFrame = true;
- ec.bResetting = true;
- ec.pSequence = this;
- ec.time = m_timeRange.start;
- Animate(ec);
- if (!bWasActive)
- {
- Deactivate();
- }
- else
- {
- for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- static_cast<CUiAnimNode*>(pAnimNode)->OnResetHard();
- }
- }
- m_bResetting = false;
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::Pause()
- {
- if (GetFlags() & eSeqFlags_LightAnimationSet || m_bPaused)
- {
- return;
- }
- m_bPaused = true;
- // Detach animation block from all nodes in this sequence.
- for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- static_cast<CUiAnimNode*>(pAnimNode)->OnPause();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::Resume()
- {
- if (GetFlags() & eSeqFlags_LightAnimationSet)
- {
- return;
- }
- if (m_bPaused)
- {
- m_bPaused = false;
- for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- static_cast<CUiAnimNode*>(pAnimNode)->OnResume();
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::OnLoop()
- {
- for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- static_cast<CUiAnimNode*>(pAnimNode)->OnLoop();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- bool CUiAnimSequence::IsPaused() const
- {
- return m_bPaused;
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::OnStart()
- {
- for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- static_cast<CUiAnimNode*>(pAnimNode)->OnStart();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::OnStop()
- {
- for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- static_cast<CUiAnimNode*>(pAnimNode)->OnStop();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::StillUpdate()
- {
- if (GetFlags() & eSeqFlags_LightAnimationSet)
- {
- return;
- }
- for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- pAnimNode->StillUpdate();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::Animate(const SUiAnimContext& ec)
- {
- assert(m_bActive);
- if (GetFlags() & eSeqFlags_LightAnimationSet)
- {
- return;
- }
- SUiAnimContext animContext = ec;
- animContext.pSequence = this;
- m_time = animContext.time;
- // Evaluate all animation nodes in sequence.
- // The director first.
- if (m_pActiveDirector)
- {
- m_pActiveDirector->Animate(animContext);
- }
- for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- // Make sure correct animation block is binded to node.
- IUiAnimNode* pAnimNode = it->get();
- // All other (inactive) director nodes are skipped.
- if (pAnimNode->GetType() == eUiAnimNodeType_Director)
- {
- continue;
- }
- // If this is a descendant of a director node and that director is currently not active, skip this one.
- IUiAnimNode* pParentDirector = pAnimNode->HasDirectorAsParent();
- if (pParentDirector && pParentDirector != m_pActiveDirector)
- {
- continue;
- }
- if (pAnimNode->GetFlags() & eUiAnimNodeFlags_Disabled)
- {
- continue;
- }
- // Animate node.
- pAnimNode->Animate(animContext);
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::Render()
- {
- for (AnimNodes::iterator it = m_nodesNeedToRender.begin(); it != m_nodesNeedToRender.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- pAnimNode->Render();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::Activate()
- {
- if (m_bActive)
- {
- return;
- }
- m_bActive = true;
- // Assign animation block to all nodes in this sequence.
- for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- CUiAnimNode* pAnimNode = static_cast<CUiAnimNode*>(it->get());
- pAnimNode->OnReset();
- pAnimNode->Activate(true);
- }
- }
- typedef AZStd::fixed_string<512> stack_string;
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::Deactivate()
- {
- if (!m_bActive)
- {
- return;
- }
- // Detach animation block from all nodes in this sequence.
- for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- CUiAnimNode* pAnimNode = static_cast<CUiAnimNode*>(it->get());
- pAnimNode->Activate(false);
- pAnimNode->OnReset();
- }
- // Remove a possibly cached game hint associated with this anim sequence.
- stack_string sTemp("anim_sequence_");
- sTemp += m_name.c_str();
- // Audio: Release precached sound
- m_bActive = false;
- m_precached = false;
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::PrecacheData(float startTime)
- {
- PrecacheStatic(startTime);
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::PrecacheStatic(const float startTime)
- {
- // pre-cache animation keys
- for (AnimNodes::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- static_cast<CUiAnimNode*>(pAnimNode)->PrecacheStatic(startTime);
- }
- PrecacheDynamic(startTime);
- if (m_precached)
- {
- return;
- }
- // Try to cache this sequence's game hint if one exists.
- stack_string sTemp("anim_sequence_");
- sTemp += m_name.c_str();
- gEnv->pLog->Log("=== Precaching render data for Ui animation: %s ===", GetName());
- m_precached = true;
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::PrecacheDynamic(float time)
- {
- // pre-cache animation keys
- for (AnimNodes::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- static_cast<CUiAnimNode*>(pAnimNode)->PrecacheDynamic(time);
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::Reflect(AZ::SerializeContext* serializeContext)
- {
- serializeContext->Class<CUiAnimSequence>()
- ->Version(2)
- ->Field("Name", &CUiAnimSequence::m_name)
- ->Field("Flags", &CUiAnimSequence::m_flags)
- ->Field("TimeRange", &CUiAnimSequence::m_timeRange)
- ->Field("ID", &CUiAnimSequence::m_id)
- ->Field("Nodes", &CUiAnimSequence::m_nodes)
- ->Field("Events", &CUiAnimSequence::m_events);
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::Serialize(XmlNodeRef& xmlNode, bool bLoading, bool bLoadEmptyTracks, uint32 overrideId, [[maybe_unused]] bool bResetLightAnimSet)
- {
- if (bLoading)
- {
- // Load.
- RemoveAll();
- int sequenceVersion = 0;
- xmlNode->getAttr("SequenceVersion", sequenceVersion);
- Range timeRange;
- m_name = xmlNode->getAttr("Name");
- xmlNode->getAttr("Flags", m_flags);
- xmlNode->getAttr("StartTime", timeRange.start);
- xmlNode->getAttr("EndTime", timeRange.end);
- xmlNode->getAttr("ID", m_id);
- if (overrideId != 0)
- {
- m_id = overrideId;
- }
- INDENT_LOG_DURING_SCOPE(true, "Loading sequence '%s' (start time = %.2f, end time = %.2f) %s ID #%u",
- m_name.c_str(), timeRange.start, timeRange.end, overrideId ? "override" : "default", m_id);
- // Loading.
- XmlNodeRef nodes = xmlNode->findChild("Nodes");
- if (nodes)
- {
- uint32 id;
- EUiAnimNodeType nodeType;
- for (int i = 0; i < nodes->getChildCount(); ++i)
- {
- XmlNodeRef childNode = nodes->getChild(i);
- childNode->getAttr("Id", id);
- static_cast<UiAnimationSystem*>(GetUiAnimationSystem())->SerializeNodeType(nodeType, childNode, bLoading, sequenceVersion, m_flags);
- if (nodeType == eUiAnimNodeType_Invalid)
- {
- continue;
- }
- IUiAnimNode* pAnimNode = CreateNodeInternal((EUiAnimNodeType)nodeType, id);
- if (!pAnimNode)
- {
- continue;
- }
- pAnimNode->Serialize(childNode, bLoading, bLoadEmptyTracks);
- }
- // When all nodes loaded restore group hierarchy
- for (AnimNodes::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- CUiAnimNode* pAnimNode = static_cast<CUiAnimNode*>((*it).get());
- pAnimNode->PostLoad();
- // And properly adjust the 'm_lastGenId' to prevent the id clash.
- if (pAnimNode->GetId() >= (int)m_nextGenId)
- {
- m_nextGenId = pAnimNode->GetId() + 1;
- }
- }
- }
- // Setting the time range must be done after the loading of all nodes
- // since it sets the time range of tracks, also.
- SetTimeRange(timeRange);
- Deactivate();
- //ComputeTimeRange();
- if (GetOwner())
- {
- GetOwner()->OnModified();
- }
- }
- else
- {
- xmlNode->setAttr("SequenceVersion", IUiAnimSequence::kSequenceVersion);
- const char* fullname = GetName();
- xmlNode->setAttr("Name", fullname); // Save the full path as a name.
- xmlNode->setAttr("Flags", m_flags);
- xmlNode->setAttr("StartTime", m_timeRange.start);
- xmlNode->setAttr("EndTime", m_timeRange.end);
- xmlNode->setAttr("ID", m_id);
- // Save.
- XmlNodeRef nodes = xmlNode->newChild("Nodes");
- int num = GetNodeCount();
- for (int i = 0; i < num; i++)
- {
- IUiAnimNode* pAnimNode = GetNode(i);
- if (pAnimNode)
- {
- XmlNodeRef xn = nodes->newChild("Node");
- pAnimNode->Serialize(xn, bLoading, true);
- }
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::InitPostLoad(IUiAnimationSystem* pUiAnimationSystem, bool remapIds, LyShine::EntityIdMap* entityIdMap)
- {
- m_pUiAnimationSystem = pUiAnimationSystem;
- int nodeCount = GetNodeCount();
- for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++)
- {
- IUiAnimNode* animNode = GetNode(nodeIndex);
- if (animNode)
- {
- animNode->InitPostLoad(this, remapIds, entityIdMap);
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::SetTimeRange(Range timeRange)
- {
- m_timeRange = timeRange;
- // Set this time range for every track in animation.
- // Set time range to be in range of largest animation track.
- for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* anode = it->get();
- anode->SetTimeRange(timeRange);
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::AdjustKeysToTimeRange(const Range& timeRange)
- {
- float offset = timeRange.start - m_timeRange.start;
- // Calculate scale ratio.
- float scale = timeRange.Length() / m_timeRange.Length();
- m_timeRange = timeRange;
- // Set time range to be in range of largest animation track.
- for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- int trackCount = pAnimNode->GetTrackCount();
- for (int paramIndex = 0; paramIndex < trackCount; paramIndex++)
- {
- IUiAnimTrack* track = pAnimNode->GetTrackByIndex(paramIndex);
- int nkey = track->GetNumKeys();
- for (int k = 0; k < nkey; k++)
- {
- float keytime = track->GetKeyTime(k);
- keytime = offset + keytime * scale;
- track->SetKeyTime(k, keytime);
- }
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::ComputeTimeRange()
- {
- Range timeRange = m_timeRange;
- // Set time range to be in range of largest animation track.
- for (AnimNodes::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- int trackCount = pAnimNode->GetTrackCount();
- for (int paramIndex = 0; paramIndex < trackCount; paramIndex++)
- {
- IUiAnimTrack* track = pAnimNode->GetTrackByIndex(paramIndex);
- int nkey = track->GetNumKeys();
- if (nkey > 0)
- {
- timeRange.start = std::min(timeRange.start, track->GetKeyTime(0));
- timeRange.end = std::max(timeRange.end, track->GetKeyTime(nkey - 1));
- }
- }
- }
- if (timeRange.start > 0)
- {
- timeRange.start = 0;
- }
- m_timeRange = timeRange;
- }
- //////////////////////////////////////////////////////////////////////////
- bool CUiAnimSequence::AddTrackEvent(const char* szEvent)
- {
- AZ_Assert(szEvent && szEvent[0], "Track Event is nullptr.");
- if (stl::push_back_unique(m_events, szEvent))
- {
- NotifyTrackEvent(IUiTrackEventListener::eTrackEventReason_Added, szEvent);
- return true;
- }
- return false;
- }
- //////////////////////////////////////////////////////////////////////////
- bool CUiAnimSequence::RemoveTrackEvent(const char* szEvent)
- {
- AZ_Assert(szEvent && szEvent[0], "Track Event is nullptr.");
- if (stl::find_and_erase(m_events, szEvent))
- {
- NotifyTrackEvent(IUiTrackEventListener::eTrackEventReason_Removed, szEvent);
- return true;
- }
- return false;
- }
- //////////////////////////////////////////////////////////////////////////
- bool CUiAnimSequence::RenameTrackEvent(const char* szEvent, const char* szNewEvent)
- {
- AZ_Assert(szEvent && szEvent[0], "Track Event is nullptr.");
- AZ_Assert(szNewEvent && szNewEvent[0], "New Track Event is nullptr.");
- for (size_t i = 0; i < m_events.size(); ++i)
- {
- if (m_events[i] == szEvent)
- {
- m_events[i] = szNewEvent;
- NotifyTrackEvent(IUiTrackEventListener::eTrackEventReason_Renamed, szEvent, szNewEvent);
- return true;
- }
- }
- return false;
- }
- //////////////////////////////////////////////////////////////////////////
- bool CUiAnimSequence::MoveUpTrackEvent(const char* szEvent)
- {
- AZ_Assert(szEvent && szEvent[0], "Track Event is nullptr.");
- for (size_t i = 0; i < m_events.size(); ++i)
- {
- if (m_events[i] == szEvent)
- {
- AZ_Assert(i > 0, "Event already first in Track.");
- if (i > 0)
- {
- std::swap(m_events[i - 1], m_events[i]);
- NotifyTrackEvent(IUiTrackEventListener::eTrackEventReason_MovedUp, szEvent);
- }
- return true;
- }
- }
- return false;
- }
- //////////////////////////////////////////////////////////////////////////
- bool CUiAnimSequence::MoveDownTrackEvent(const char* szEvent)
- {
- AZ_Assert(szEvent && szEvent[0], "Track Event is nullptr.");
- for (size_t i = 0; i < m_events.size(); ++i)
- {
- if (m_events[i] == szEvent)
- {
- AZ_Assert(i < m_events.size() - 1, "Event already last in Track.");
- if (i < m_events.size() - 1)
- {
- std::swap(m_events[i], m_events[i + 1]);
- NotifyTrackEvent(IUiTrackEventListener::eTrackEventReason_MovedDown, szEvent);
- }
- return true;
- }
- }
- return false;
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::ClearTrackEvents()
- {
- m_events.clear();
- }
- //////////////////////////////////////////////////////////////////////////
- int CUiAnimSequence::GetTrackEventsCount() const
- {
- return static_cast<int>(m_events.size());
- }
- //////////////////////////////////////////////////////////////////////////
- char const* CUiAnimSequence::GetTrackEvent(int iIndex) const
- {
- char const* szResult = NULL;
- const bool bValid = (iIndex >= 0 && iIndex < GetTrackEventsCount());
- AZ_Assert(bValid, "Track Event index out of range.");
- if (bValid)
- {
- szResult = m_events[iIndex].c_str();
- }
- return szResult;
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::NotifyTrackEvent(IUiTrackEventListener::ETrackEventReason reason,
- const char* event, const char* param)
- {
- // Notify listeners
- for (TUiTrackEventListeners::iterator j = m_listeners.begin(); j != m_listeners.end(); ++j)
- {
- (*j)->OnTrackEvent(this, reason, event, (void*)param);
- }
- // Pass to Animation System to notify via EBus
- GetUiAnimationSystem()->NotifyTrackEventListeners(event, param, this);
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::TriggerTrackEvent(const char* event, const char* param)
- {
- NotifyTrackEvent(IUiTrackEventListener::eTrackEventReason_Triggered, event, param);
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::AddTrackEventListener(IUiTrackEventListener* pListener)
- {
- if (AZStd::find(m_listeners.begin(), m_listeners.end(), pListener) == m_listeners.end())
- {
- m_listeners.push_back(pListener);
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::RemoveTrackEventListener(IUiTrackEventListener* pListener)
- {
- TUiTrackEventListeners::iterator it = AZStd::find(m_listeners.begin(), m_listeners.end(), pListener);
- if (it != m_listeners.end())
- {
- m_listeners.erase(it);
- }
- }
- //////////////////////////////////////////////////////////////////////////
- IUiAnimNode* CUiAnimSequence::FindNodeById(int nNodeId)
- {
- for (AnimNodes::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- if (static_cast<CUiAnimNode*>(pAnimNode)->GetId() == nNodeId)
- {
- return pAnimNode;
- }
- }
- return 0;
- }
- //////////////////////////////////////////////////////////////////////////
- IUiAnimNode* CUiAnimSequence::FindNodeByName(const char* sNodeName, const IUiAnimNode* pParentDirector)
- {
- for (AnimNodes::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- // Case insensitive name comparison.
- if (_stricmp(((CUiAnimNode*)pAnimNode)->GetNameFast(), sNodeName) == 0)
- {
- bool bParentDirectorCheck = pAnimNode->HasDirectorAsParent() == pParentDirector;
- if (bParentDirectorCheck)
- {
- return pAnimNode;
- }
- }
- }
- return 0;
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::ReorderNode(IUiAnimNode* pNode, IUiAnimNode* pPivotNode, bool bNext)
- {
- if (pNode == pPivotNode || !pNode)
- {
- return;
- }
- AZStd::intrusive_ptr<IUiAnimNode> pTempHolder(pNode); // Keep reference to node so it is not deleted by erasing from list.
- stl::find_and_erase_if(m_nodes, [pNode](const AZStd::intrusive_ptr<IUiAnimNode>& sp) { return sp.get() == pNode; });
- AnimNodes::iterator it;
- for (it = m_nodes.begin(); it != m_nodes.end(); ++it)
- {
- IUiAnimNode* pAnimNode = it->get();
- if (pAnimNode == pPivotNode)
- {
- if (bNext)
- {
- m_nodes.insert(it + 1, AZStd::intrusive_ptr<IUiAnimNode>(pNode));
- }
- else
- {
- m_nodes.insert(it, AZStd::intrusive_ptr<IUiAnimNode>(pNode));
- }
- break;
- }
- }
- if (it == m_nodes.end())
- {
- m_nodes.insert(m_nodes.begin(), AZStd::intrusive_ptr<IUiAnimNode>(pNode));
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::CopyNodeChildren(XmlNodeRef& xmlNode, IUiAnimNode* pAnimNode)
- {
- for (int k = 0; k < GetNodeCount(); ++k)
- {
- if (GetNode(k)->GetParent() == pAnimNode)
- {
- XmlNodeRef childNode = xmlNode->newChild("Node");
- GetNode(k)->Serialize(childNode, false, true);
- if (GetNode(k)->GetType() == eUiAnimNodeType_Group
- || pAnimNode->GetType() == eUiAnimNodeType_Director)
- {
- CopyNodeChildren(xmlNode, GetNode(k));
- }
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::CopyNodes(XmlNodeRef& xmlNode, IUiAnimNode** pSelectedNodes, uint32 count)
- {
- for (uint32 i = 0; i < count; ++i)
- {
- IUiAnimNode* pAnimNode = pSelectedNodes[i];
- if (pAnimNode)
- {
- XmlNodeRef xn = xmlNode->newChild("Node");
- pAnimNode->Serialize(xn, false, true);
- // If it is a group node, copy its children also.
- if (pAnimNode->GetType() == eUiAnimNodeType_Group || pAnimNode->GetType() == eUiAnimNodeType_Director)
- {
- CopyNodeChildren(xmlNode, pAnimNode);
- }
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::PasteNodes(const XmlNodeRef& xmlNode, IUiAnimNode* pParent)
- {
- int type, id;
- std::map<int, IUiAnimNode*> idToNode;
- for (int i = 0; i < xmlNode->getChildCount(); i++)
- {
- XmlNodeRef xn = xmlNode->getChild(i);
- if (!xn->getAttr("Type", type))
- {
- continue;
- }
- xn->getAttr("Id", id);
- IUiAnimNode* node = CreateNode((EUiAnimNodeType)type);
- if (!node)
- {
- continue;
- }
- idToNode[id] = node;
- xn->setAttr("Id", static_cast<CUiAnimNode*>(node)->GetId());
- node->Serialize(xn, true, true);
- int parentId = 0;
- if (xn->getAttr("ParentNode", parentId))
- {
- node->SetParent(idToNode[parentId]);
- }
- else
- // This means a top-level node.
- {
- if (pParent)
- {
- node->SetParent(pParent);
- }
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- bool CUiAnimSequence::AddNodeNeedToRender(IUiAnimNode* pNode)
- {
- assert(pNode != 0);
- return stl::push_back_unique(m_nodesNeedToRender, AZStd::intrusive_ptr<IUiAnimNode>(pNode));
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::RemoveNodeNeedToRender(IUiAnimNode* pNode)
- {
- assert(pNode != 0);
- stl::find_and_erase_if(m_nodesNeedToRender, [pNode](const AZStd::intrusive_ptr<IUiAnimNode>& sp) { return sp.get() == pNode; });
- }
- //////////////////////////////////////////////////////////////////////////
- void CUiAnimSequence::SetActiveDirector(IUiAnimNode* pDirectorNode)
- {
- if (!pDirectorNode)
- {
- return;
- }
- AZ_Assert(pDirectorNode->GetType() == eUiAnimNodeType_Director, "New Director Node is not Director Type.");
- if (pDirectorNode->GetType() != eUiAnimNodeType_Director)
- {
- return; // It's not a director node.
- }
- if (pDirectorNode->GetSequence() != this)
- {
- return; // It's not a node belong to this sequence.
- }
- m_pActiveDirector = pDirectorNode;
- }
- //////////////////////////////////////////////////////////////////////////
- IUiAnimNode* CUiAnimSequence::GetActiveDirector() const
- {
- return m_pActiveDirector;
- }
- //////////////////////////////////////////////////////////////////////////
- bool CUiAnimSequence::IsAncestorOf(const IUiAnimSequence* pSequence) const
- {
- AZ_Assert(this != pSequence, "Checked if UiAnimSequence was ancestor of itself.");
- if (this == pSequence)
- {
- return true;
- }
- // UI_ANIMATION_REVISIT: was only doing anything for sequence tracks
- return false;
- }
|