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.
1238 lines
40 KiB
C++
1238 lines
40 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 <AzCore/Serialization/SerializeContext.h>
|
|
#include "AnimNode.h"
|
|
#include "AnimTrack.h"
|
|
#include "AnimSequence.h"
|
|
#include <Maestro/Types/AssetBlendKey.h>
|
|
#include "AssetBlendTrack.h"
|
|
#include "CharacterTrack.h"
|
|
#include "AnimSplineTrack.h"
|
|
#include "BoolTrack.h"
|
|
#include "SelectTrack.h"
|
|
#include "EventTrack.h"
|
|
#include "SoundTrack.h"
|
|
#include "ConsoleTrack.h"
|
|
#include "LookAtTrack.h"
|
|
#include "TrackEventTrack.h"
|
|
#include "SequenceTrack.h"
|
|
#include "CompoundSplineTrack.h"
|
|
#include "GotoTrack.h"
|
|
#include "CaptureTrack.h"
|
|
#include "CommentTrack.h"
|
|
#include "ScreenFaderTrack.h"
|
|
#include "TimeRangesTrack.h"
|
|
#include "SoundTrack.h"
|
|
|
|
#include <AzCore/std/sort.h>
|
|
#include <AzCore/Math/MathUtils.h>
|
|
#include <AzCore/Component/TickBus.h>
|
|
#include <ctime>
|
|
#include "Maestro/Types/AnimValueType.h"
|
|
#include "Maestro/Types/AnimNodeType.h"
|
|
#include "Maestro/Types/AnimParamType.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Old deprecated IDs
|
|
//////////////////////////////////////////////////////////////////////////
|
|
#define APARAM_CHARACTER4 static_cast<AnimParamType>(static_cast<int>(AnimParamType::User) + 0x10)
|
|
#define APARAM_CHARACTER5 static_cast<AnimParamType>(static_cast<int>(AnimParamType::User) + 0x11)
|
|
#define APARAM_CHARACTER6 static_cast<AnimParamType>(static_cast<int>(AnimParamType::User) + 0x12)
|
|
#define APARAM_CHARACTER7 static_cast<AnimParamType>(static_cast<int>(AnimParamType::User) + 0x13)
|
|
#define APARAM_CHARACTER8 static_cast<AnimParamType>(static_cast<int>(AnimParamType::User) + 0x14)
|
|
#define APARAM_CHARACTER9 static_cast<AnimParamType>(static_cast<int>(AnimParamType::User) + 0x15)
|
|
#define APARAM_CHARACTER10 static_cast<AnimParamType>(static_cast<int>(AnimParamType::User) + 0x16)
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
static const EAnimCurveType DEFAULT_TRACK_TYPE = eAnimCurveType_BezierFloat;
|
|
|
|
// Old serialization values that are no longer
|
|
// defined in IMovieSystem.h, but needed for conversion:
|
|
static const int OLD_ACURVE_GOTO = 21;
|
|
static const int OLD_APARAM_PARTICLE_COUNT_SCALE = 95;
|
|
static const int OLD_APARAM_PARTICLE_PULSE_PERIOD = 96;
|
|
static const int OLD_APARAM_PARTICLE_SCALE = 97;
|
|
static const int OLD_APARAM_PARTICLE_SPEED_SCALE = 98;
|
|
static const int OLD_APARAM_PARTICLE_STRENGTH = 99;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CAnimNode.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimNode::Activate([[maybe_unused]] bool bActivate)
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int CAnimNode::GetTrackCount() const
|
|
{
|
|
return static_cast<int>(m_tracks.size());
|
|
}
|
|
|
|
AZStd::string CAnimNode::GetParamName(const CAnimParamType& paramType) const
|
|
{
|
|
SParamInfo info;
|
|
if (GetParamInfoFromType(paramType, info))
|
|
{
|
|
return info.name;
|
|
}
|
|
|
|
return "Unknown";
|
|
}
|
|
|
|
AnimValueType CAnimNode::GetParamValueType(const CAnimParamType& paramType) const
|
|
{
|
|
SParamInfo info;
|
|
if (GetParamInfoFromType(paramType, info))
|
|
{
|
|
return info.valueType;
|
|
}
|
|
|
|
return AnimValueType::Unknown;
|
|
}
|
|
|
|
IAnimNode::ESupportedParamFlags CAnimNode::GetParamFlags(const CAnimParamType& paramType) const
|
|
{
|
|
SParamInfo info;
|
|
if (GetParamInfoFromType(paramType, info))
|
|
{
|
|
return info.flags;
|
|
}
|
|
|
|
return IAnimNode::ESupportedParamFlags(0);
|
|
}
|
|
|
|
IAnimTrack* CAnimNode::GetTrackForParameter(const CAnimParamType& paramType) const
|
|
{
|
|
for (int i = 0, num = (int)m_tracks.size(); i < num; i++)
|
|
{
|
|
if (m_tracks[i]->GetParameterType() == paramType)
|
|
{
|
|
return m_tracks[i].get();
|
|
}
|
|
|
|
// Search the sub-tracks also if any.
|
|
for (int k = 0; k < m_tracks[i]->GetSubTrackCount(); ++k)
|
|
{
|
|
if (m_tracks[i]->GetSubTrack(k)->GetParameterType() == paramType)
|
|
{
|
|
return m_tracks[i]->GetSubTrack(k);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
IAnimTrack* CAnimNode::GetTrackForParameter(const CAnimParamType& paramType, uint32 index) const
|
|
{
|
|
SParamInfo paramInfo;
|
|
GetParamInfoFromType(paramType, paramInfo);
|
|
|
|
if ((paramInfo.flags & IAnimNode::eSupportedParamFlags_MultipleTracks) == 0)
|
|
{
|
|
return GetTrackForParameter(paramType);
|
|
}
|
|
|
|
uint32 count = 0;
|
|
for (int i = 0, num = (int)m_tracks.size(); i < num; i++)
|
|
{
|
|
if (m_tracks[i]->GetParameterType() == paramType && count++ == index)
|
|
{
|
|
return m_tracks[i].get();
|
|
}
|
|
|
|
// For this case, no subtracks are considered.
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint32 CAnimNode::GetTrackParamIndex(const IAnimTrack* pTrack) const
|
|
{
|
|
assert(pTrack);
|
|
uint32 index = 0;
|
|
CAnimParamType paramType = pTrack->GetParameterType();
|
|
|
|
SParamInfo paramInfo;
|
|
GetParamInfoFromType(paramType, paramInfo);
|
|
|
|
if ((paramInfo.flags & IAnimNode::eSupportedParamFlags_MultipleTracks) == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
for (int i = 0, num = (int)m_tracks.size(); i < num; i++)
|
|
{
|
|
if (m_tracks[i].get() == pTrack)
|
|
{
|
|
return index;
|
|
}
|
|
|
|
if (m_tracks[i]->GetParameterType() == paramType)
|
|
{
|
|
++index;
|
|
}
|
|
|
|
// For this case, no subtracks are considered.
|
|
}
|
|
assert(!"CAnimNode::GetTrackParamIndex() called with an invalid argument!");
|
|
return 0;
|
|
}
|
|
|
|
IAnimTrack* CAnimNode::GetTrackByIndex(int nIndex) const
|
|
{
|
|
if (nIndex >= (int)m_tracks.size())
|
|
{
|
|
assert("nIndex>=m_tracks.size()" && false);
|
|
return NULL;
|
|
}
|
|
return m_tracks[nIndex].get();
|
|
}
|
|
|
|
void CAnimNode::SetTrack(const CAnimParamType& paramType, IAnimTrack* pTrack)
|
|
{
|
|
if (pTrack)
|
|
{
|
|
for (unsigned int i = 0; i < m_tracks.size(); i++)
|
|
{
|
|
if (m_tracks[i]->GetParameterType() == paramType)
|
|
{
|
|
m_tracks[i].reset(pTrack);
|
|
return;
|
|
}
|
|
}
|
|
|
|
AddTrack(pTrack);
|
|
}
|
|
else
|
|
{
|
|
// Remove track at this id.
|
|
for (unsigned int i = 0; i < m_tracks.size(); i++)
|
|
{
|
|
if (m_tracks[i]->GetParameterType() == paramType)
|
|
{
|
|
m_tracks.erase(m_tracks.begin() + i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CAnimNode::TrackOrder(const AZStd::intrusive_ptr<IAnimTrack>& left, const AZStd::intrusive_ptr<IAnimTrack>& right)
|
|
{
|
|
return left->GetParameterType() < right->GetParameterType();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimNode::AddTrack(IAnimTrack* pTrack)
|
|
{
|
|
RegisterTrack(pTrack);
|
|
m_tracks.push_back(AZStd::intrusive_ptr<IAnimTrack>(pTrack));
|
|
SortTracks();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimNode::RegisterTrack(IAnimTrack* pTrack)
|
|
{
|
|
pTrack->SetTimeRange(GetSequence()->GetTimeRange());
|
|
pTrack->SetNode(this);
|
|
}
|
|
|
|
void CAnimNode::SortTracks()
|
|
{
|
|
AZStd::insertion_sort(m_tracks.begin(), m_tracks.end(), TrackOrder);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CAnimNode::RemoveTrack(IAnimTrack* pTrack)
|
|
{
|
|
for (unsigned int i = 0; i < m_tracks.size(); i++)
|
|
{
|
|
if (m_tracks[i].get() == pTrack)
|
|
{
|
|
m_tracks.erase(m_tracks.begin() + i);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
static bool AnimNodeVersionConverter(
|
|
AZ::SerializeContext& serializeContext,
|
|
AZ::SerializeContext::DataElementNode& rootElement)
|
|
{
|
|
if (rootElement.GetVersion() < 3)
|
|
{
|
|
rootElement.AddElement(serializeContext, "BaseClass1", azrtti_typeid<IAnimNode>());
|
|
}
|
|
|
|
if (rootElement.GetVersion() < 4)
|
|
{
|
|
// remove vector scale tracks from transform anim nodes
|
|
AZStd::string name;
|
|
if (rootElement.FindSubElementAndGetData<AZStd::string>(AZ_CRC_CE("Name"), name) && name == "Transform")
|
|
{
|
|
auto tracksElement = rootElement.FindSubElement(AZ_CRC_CE("Tracks"));
|
|
if (tracksElement)
|
|
{
|
|
for (int trackIndex = tracksElement->GetNumSubElements() - 1; trackIndex >= 0; trackIndex--)
|
|
{
|
|
auto trackElement = tracksElement->GetSubElement(trackIndex);
|
|
bool isScale = false;
|
|
|
|
// trackElement should be an intrusive_ptr with one child
|
|
if (trackElement.GetNumSubElements() == 1)
|
|
{
|
|
auto ptrElement = trackElement.GetSubElement(0);
|
|
auto paramTypeElement = ptrElement.FindSubElement(AZ_CRC_CE("ParamType"));
|
|
if (paramTypeElement)
|
|
{
|
|
AZStd::string paramName;
|
|
if (paramTypeElement->FindSubElementAndGetData<AZStd::string>(AZ_CRC_CE("Name"), paramName) && paramName == "Scale")
|
|
{
|
|
isScale = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isScale)
|
|
{
|
|
tracksElement->RemoveElement(trackIndex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CAnimNode::Reflect(AZ::ReflectContext* context)
|
|
{
|
|
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
|
{
|
|
serializeContext->Class<CAnimNode, IAnimNode>()
|
|
->Version(4, &AnimNodeVersionConverter)
|
|
->Field("ID", &CAnimNode::m_id)
|
|
->Field("Name", &CAnimNode::m_name)
|
|
->Field("Flags", &CAnimNode::m_flags)
|
|
->Field("Tracks", &CAnimNode::m_tracks)
|
|
->Field("Parent", &CAnimNode::m_parentNodeId)
|
|
->Field("Type", &CAnimNode::m_nodeType)
|
|
->Field("Expanded", &CAnimNode::m_expanded);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IAnimTrack* CAnimNode::CreateTrackInternal(const CAnimParamType& paramType, EAnimCurveType trackType, AnimValueType valueType)
|
|
{
|
|
|
|
if (valueType == AnimValueType::Unknown)
|
|
{
|
|
SParamInfo info;
|
|
|
|
// Try to get info from paramType, else we can't determine the track data type
|
|
if (!GetParamInfoFromType(paramType, info))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
valueType = info.valueType;
|
|
}
|
|
|
|
IAnimTrack* pTrack = NULL;
|
|
|
|
switch (paramType.GetType())
|
|
{
|
|
// Create sub-classed tracks
|
|
case AnimParamType::Event:
|
|
pTrack = aznew CEventTrack(m_pSequence->GetTrackEventStringTable());
|
|
break;
|
|
case AnimParamType::Sound:
|
|
pTrack = aznew CSoundTrack;
|
|
break;
|
|
case AnimParamType::Animation:
|
|
pTrack = aznew CCharacterTrack;
|
|
break;
|
|
case AnimParamType::Console:
|
|
pTrack = aznew CConsoleTrack;
|
|
break;
|
|
case AnimParamType::LookAt:
|
|
pTrack = aznew CLookAtTrack;
|
|
break;
|
|
case AnimParamType::TrackEvent:
|
|
pTrack = aznew CTrackEventTrack(m_pSequence->GetTrackEventStringTable());
|
|
break;
|
|
case AnimParamType::Sequence:
|
|
pTrack = aznew CSequenceTrack;
|
|
break;
|
|
case AnimParamType::Capture:
|
|
pTrack = aznew CCaptureTrack;
|
|
break;
|
|
case AnimParamType::CommentText:
|
|
pTrack = aznew CCommentTrack;
|
|
break;
|
|
case AnimParamType::ScreenFader:
|
|
pTrack = aznew CScreenFaderTrack;
|
|
break;
|
|
case AnimParamType::Goto:
|
|
pTrack = aznew CGotoTrack;
|
|
break;
|
|
case AnimParamType::TimeRanges:
|
|
pTrack = aznew CTimeRangesTrack;
|
|
break;
|
|
case AnimParamType::Float:
|
|
pTrack = CreateTrackInternalFloat(trackType);
|
|
break;
|
|
|
|
default:
|
|
// Create standard tracks
|
|
switch (valueType)
|
|
{
|
|
case AnimValueType::Float:
|
|
pTrack = CreateTrackInternalFloat(trackType);
|
|
break;
|
|
case AnimValueType::RGB:
|
|
case AnimValueType::Vector:
|
|
pTrack = CreateTrackInternalVector(trackType, paramType, valueType);
|
|
break;
|
|
case AnimValueType::Quat:
|
|
pTrack = CreateTrackInternalQuat(trackType, paramType);
|
|
break;
|
|
case AnimValueType::Bool:
|
|
pTrack = aznew CBoolTrack;
|
|
break;
|
|
case AnimValueType::Select:
|
|
pTrack = aznew CSelectTrack;
|
|
break;
|
|
case AnimValueType::Vector4:
|
|
pTrack = CreateTrackInternalVector4(paramType);
|
|
break;
|
|
case AnimValueType::CharacterAnim:
|
|
pTrack = aznew CCharacterTrack;
|
|
break;
|
|
case AnimValueType::AssetBlend:
|
|
pTrack = aznew CAssetBlendTrack;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pTrack)
|
|
{
|
|
pTrack->SetParameterType(paramType);
|
|
|
|
// Assign a unique id for every track.
|
|
pTrack->SetId(m_pSequence->GetUniqueTrackIdAndGenerateNext());
|
|
int subTrackCount = pTrack->GetSubTrackCount();
|
|
for (int subTrackIndex = 0; subTrackIndex < subTrackCount; subTrackIndex++)
|
|
{
|
|
IAnimTrack* subTrack = pTrack->GetSubTrack(subTrackIndex);
|
|
subTrack->SetId(m_pSequence->GetUniqueTrackIdAndGenerateNext());
|
|
}
|
|
|
|
AddTrack(pTrack);
|
|
}
|
|
|
|
return pTrack;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IAnimTrack* CAnimNode::CreateTrack(const CAnimParamType& paramType)
|
|
{
|
|
IAnimTrack* pTrack = CreateTrackInternal(paramType, DEFAULT_TRACK_TYPE, AnimValueType::Unknown);
|
|
InitializeTrackDefaultValue(pTrack, paramType);
|
|
return pTrack;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimNode::SerializeAnims(XmlNodeRef& xmlNode, bool bLoading, bool bLoadEmptyTracks)
|
|
{
|
|
if (bLoading)
|
|
{
|
|
// Delete all tracks.
|
|
stl::free_container(m_tracks);
|
|
|
|
CAnimNode::SParamInfo info;
|
|
// Loading.
|
|
int paramTypeVersion = 0;
|
|
xmlNode->getAttr("paramIdVersion", paramTypeVersion);
|
|
CAnimParamType paramType;
|
|
int num = xmlNode->getChildCount();
|
|
for (int i = 0; i < num; i++)
|
|
{
|
|
XmlNodeRef trackNode = xmlNode->getChild(i);
|
|
paramType.Serialize(trackNode, bLoading, paramTypeVersion);
|
|
|
|
|
|
if (paramType.GetType() == AnimParamType::Music)
|
|
{
|
|
// skip loading AnimParamType::Music - it's deprecated
|
|
continue;
|
|
}
|
|
|
|
if (paramTypeVersion == 0) // for old version with sound and animation param ids swapped
|
|
{
|
|
AnimParamType APARAM_ANIMATION_OLD = AnimParamType::Sound;
|
|
AnimParamType APARAM_SOUND_OLD = AnimParamType::Animation;
|
|
if (paramType.GetType() == APARAM_ANIMATION_OLD)
|
|
{
|
|
paramType = AnimParamType::Animation;
|
|
}
|
|
else if (paramType.GetType() == APARAM_SOUND_OLD)
|
|
{
|
|
paramType = AnimParamType::Sound;
|
|
}
|
|
}
|
|
|
|
int curveType = eAnimCurveType_Unknown;
|
|
trackNode->getAttr("Type", curveType);
|
|
if (curveType == eAnimCurveType_Unknown)
|
|
{
|
|
if (paramTypeVersion == 0)
|
|
{
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Backward compatibility code
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Legacy animation track.
|
|
// Collapse parameter ID to the single type
|
|
if (paramType.GetType() >= AnimParamType::Sound && paramType.GetType() <= static_cast<AnimParamType>(static_cast<int>(AnimParamType::Sound) + 2))
|
|
{
|
|
paramType = AnimParamType::Sound;
|
|
}
|
|
if (paramType.GetType() >= AnimParamType::Animation && paramType.GetType() <= static_cast<AnimParamType>(static_cast<int>(AnimParamType::Animation) + 2))
|
|
{
|
|
paramType = AnimParamType::Animation;
|
|
}
|
|
if (paramType.GetType() >= APARAM_CHARACTER4 && paramType.GetType() <= APARAM_CHARACTER10)
|
|
{
|
|
paramType = AnimParamType::Animation;
|
|
}
|
|
|
|
// Old tracks always used TCB tracks.
|
|
// Backward compatibility to the CryEngine2 for track type (will make TCB controller)
|
|
curveType = eAnimCurveType_TCBVector;
|
|
}
|
|
}
|
|
|
|
if (paramTypeVersion <= 1)
|
|
{
|
|
// In old versions goto tracks were identified by a curve id
|
|
if (curveType == OLD_ACURVE_GOTO)
|
|
{
|
|
paramType = AnimParamType::Goto;
|
|
curveType = eAnimCurveType_Unknown;
|
|
}
|
|
}
|
|
|
|
if (paramTypeVersion <= 3 && paramType.GetType() >= static_cast<AnimParamType>(OLD_APARAM_USER))
|
|
{
|
|
// APARAM_USER 100 => 100000
|
|
paramType = static_cast<AnimParamType>(static_cast<int>(paramType.GetType()) + static_cast<int>(AnimParamType::User) - OLD_APARAM_USER);
|
|
}
|
|
|
|
if (paramTypeVersion <= 4)
|
|
{
|
|
// In old versions there was special code for particles
|
|
// that is now handles by generic entity node code
|
|
switch (paramType.GetType())
|
|
{
|
|
case static_cast<AnimParamType>(OLD_APARAM_PARTICLE_COUNT_SCALE) :
|
|
paramType = CAnimParamType("ScriptTable:Properties/CountScale");
|
|
break;
|
|
case static_cast<AnimParamType>(OLD_APARAM_PARTICLE_PULSE_PERIOD) :
|
|
paramType = CAnimParamType("ScriptTable:Properties/PulsePeriod");
|
|
break;
|
|
case static_cast<AnimParamType>(OLD_APARAM_PARTICLE_SCALE) :
|
|
paramType = CAnimParamType("ScriptTable:Properties/Scale");
|
|
break;
|
|
case static_cast<AnimParamType>(OLD_APARAM_PARTICLE_SPEED_SCALE) :
|
|
paramType = CAnimParamType("ScriptTable:Properties/SpeedScale");
|
|
break;
|
|
case static_cast<AnimParamType>(OLD_APARAM_PARTICLE_STRENGTH):
|
|
paramType = CAnimParamType("ScriptTable:Properties/Strength");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (paramTypeVersion <= 5 && !(GetSequence()->GetFlags() & IAnimSequence::eSeqFlags_LightAnimationSet))
|
|
{
|
|
// In old versions there was special code for lights that is now handled
|
|
// by generic entity node code if this is not a light animation set sequence
|
|
switch (paramType.GetType())
|
|
{
|
|
case AnimParamType::LightDiffuse:
|
|
paramType = CAnimParamType("ScriptTable:Properties/Color/clrDiffuse");
|
|
break;
|
|
case AnimParamType::LightRadius:
|
|
paramType = CAnimParamType("ScriptTable:Properties/Radius");
|
|
break;
|
|
case AnimParamType::LightDiffuseMult:
|
|
paramType = CAnimParamType("ScriptTable:Properties/Color/fDiffuseMultiplier");
|
|
break;
|
|
case AnimParamType::LightHDRDynamic:
|
|
paramType = CAnimParamType("ScriptTable:Properties/Color/fHDRDynamic");
|
|
break;
|
|
case AnimParamType::LightSpecularMult:
|
|
paramType = CAnimParamType("ScriptTable:Properties/Color/fSpecularMultiplier");
|
|
break;
|
|
case AnimParamType::LightSpecPercentage:
|
|
paramType = CAnimParamType("ScriptTable:Properties/Color/fSpecularPercentage");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (paramTypeVersion <= 7 && paramType.GetType() == AnimParamType::Physics)
|
|
{
|
|
paramType = AnimParamType::PhysicsDriven;
|
|
}
|
|
|
|
int valueType = static_cast<int>(AnimValueType::Unknown);
|
|
trackNode->getAttr("ValueType", valueType);
|
|
|
|
IAnimTrack* pTrack = CreateTrackInternal(paramType, (EAnimCurveType)curveType, static_cast<AnimValueType>(valueType));
|
|
bool trackRemoved = false;
|
|
if (pTrack)
|
|
{
|
|
if (!pTrack->Serialize(trackNode, bLoading, bLoadEmptyTracks))
|
|
{
|
|
// Boolean tracks must always be loaded even if empty.
|
|
if (pTrack->GetValueType() != AnimValueType::Bool)
|
|
{
|
|
RemoveTrack(pTrack);
|
|
trackRemoved = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!trackRemoved && gEnv->IsEditor())
|
|
{
|
|
InitializeTrackDefaultValue(pTrack, paramType);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Saving.
|
|
xmlNode->setAttr("paramIdVersion", CAnimParamType::kParamTypeVersion);
|
|
for (unsigned int i = 0; i < m_tracks.size(); i++)
|
|
{
|
|
IAnimTrack* pTrack = m_tracks[i].get();
|
|
if (pTrack)
|
|
{
|
|
CAnimParamType paramType = m_tracks[i]->GetParameterType();
|
|
XmlNodeRef trackNode = xmlNode->newChild("Track");
|
|
paramType.Serialize(trackNode, bLoading);
|
|
int nTrackType = pTrack->GetCurveType();
|
|
trackNode->setAttr("Type", nTrackType);
|
|
pTrack->Serialize(trackNode, bLoading);
|
|
int valueType = static_cast<int>(pTrack->GetValueType());
|
|
trackNode->setAttr("ValueType", valueType);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimNode::SetTimeRange(Range timeRange)
|
|
{
|
|
for (unsigned int i = 0; i < m_tracks.size(); i++)
|
|
{
|
|
if (m_tracks[i])
|
|
{
|
|
m_tracks[i]->SetTimeRange(timeRange);
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// AZ::Serialization requires a default constructor
|
|
CAnimNode::CAnimNode()
|
|
: CAnimNode(0, AnimNodeType::Invalid)
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// explicit copy constructor is required to prevent compiler's generated copy constructor
|
|
// from calling AZStd::mutex's private copy constructor
|
|
CAnimNode::CAnimNode(const CAnimNode& other)
|
|
: m_refCount(0)
|
|
, m_id(0) // don't copy id - these should be unique
|
|
, m_parentNodeId(other.m_parentNodeId)
|
|
, m_nodeType(other.m_nodeType)
|
|
, m_pOwner(other.m_pOwner)
|
|
, m_pSequence(other.m_pSequence)
|
|
, m_flags(other.m_flags)
|
|
, m_pParentNode(other.m_pParentNode)
|
|
, m_nLoadedParentNodeId(other.m_nLoadedParentNodeId)
|
|
, m_expanded(other.m_expanded)
|
|
{
|
|
// m_bIgnoreSetParam not copied
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CAnimNode::CAnimNode(const int id, AnimNodeType nodeType)
|
|
: m_refCount(0)
|
|
, m_id(id)
|
|
, m_parentNodeId(0)
|
|
, m_nodeType(nodeType)
|
|
{
|
|
m_pOwner = 0;
|
|
m_pSequence = 0;
|
|
m_flags = 0;
|
|
m_bIgnoreSetParam = false;
|
|
m_pParentNode = 0;
|
|
m_nLoadedParentNodeId = 0;
|
|
m_expanded = true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
CAnimNode::~CAnimNode()
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimNode::add_ref()
|
|
{
|
|
++m_refCount;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimNode::release()
|
|
{
|
|
if (--m_refCount <= 0)
|
|
{
|
|
delete this;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimNode::SetFlags(int flags)
|
|
{
|
|
m_flags = flags;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int CAnimNode::GetFlags() const
|
|
{
|
|
return m_flags;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CAnimNode::AreFlagsSetOnNodeOrAnyParent(EAnimNodeFlags flagsToCheck) const
|
|
{
|
|
if (m_pParentNode)
|
|
{
|
|
// recurse up parent chain until we find the flagsToCheck set or get to the top of the chain
|
|
return ((GetFlags() & flagsToCheck) != 0) || m_pParentNode->AreFlagsSetOnNodeOrAnyParent(flagsToCheck);
|
|
}
|
|
|
|
// top of parent chain
|
|
return ((GetFlags() & flagsToCheck) != 0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimNode::Animate([[maybe_unused]] SAnimContext& ec)
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CAnimNode::IsParamValid(const CAnimParamType& paramType) const
|
|
{
|
|
SParamInfo info;
|
|
|
|
if (GetParamInfoFromType(paramType, info))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CAnimNode::SetParamValue(float time, CAnimParamType param, float value)
|
|
{
|
|
if (m_bIgnoreSetParam)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
IAnimTrack* pTrack = GetTrackForParameter(param);
|
|
if (pTrack && pTrack->GetValueType() == AnimValueType::Float)
|
|
{
|
|
// Float track.
|
|
bool bDefault = !(gEnv->pMovieSystem->IsRecording() && (m_flags & eAnimNodeFlags_EntitySelected)); // Only selected nodes can be recorded
|
|
pTrack->SetValue(time, value, bDefault);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CAnimNode::SetParamValue(float time, CAnimParamType param, const Vec3& value)
|
|
{
|
|
if (m_bIgnoreSetParam)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
CCompoundSplineTrack* pTrack = static_cast<CCompoundSplineTrack*>(GetTrackForParameter(param));
|
|
if (pTrack && pTrack->GetValueType() == AnimValueType::Vector)
|
|
{
|
|
// Vec3 track.
|
|
bool bDefault = !(gEnv->pMovieSystem->IsRecording() && (m_flags & eAnimNodeFlags_EntitySelected)); // Only selected nodes can be recorded
|
|
pTrack->SetValue(time, value, bDefault);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CAnimNode::SetParamValue(float time, CAnimParamType param, const Vec4& value)
|
|
{
|
|
if (m_bIgnoreSetParam)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
CCompoundSplineTrack* pTrack = static_cast<CCompoundSplineTrack*>(GetTrackForParameter(param));
|
|
if (pTrack && pTrack->GetValueType() == AnimValueType::Vector4)
|
|
{
|
|
// Vec4 track.
|
|
bool bDefault = !(gEnv->pMovieSystem->IsRecording() && (m_flags & eAnimNodeFlags_EntitySelected)); // Only selected nodes can be recorded
|
|
pTrack->SetValue(time, value, bDefault);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CAnimNode::GetParamValue(float time, CAnimParamType param, float& value)
|
|
{
|
|
IAnimTrack* pTrack = GetTrackForParameter(param);
|
|
if (pTrack && pTrack->GetValueType() == AnimValueType::Float && pTrack->GetNumKeys() > 0)
|
|
{
|
|
// Float track.
|
|
pTrack->GetValue(time, value);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CAnimNode::GetParamValue(float time, CAnimParamType param, Vec3& value)
|
|
{
|
|
CCompoundSplineTrack* pTrack = static_cast<CCompoundSplineTrack*>(GetTrackForParameter(param));
|
|
if (pTrack && pTrack->GetValueType() == AnimValueType::Vector && pTrack->GetNumKeys() > 0)
|
|
{
|
|
// Vec3 track.
|
|
pTrack->GetValue(time, value);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CAnimNode::GetParamValue(float time, CAnimParamType param, Vec4& value)
|
|
{
|
|
CCompoundSplineTrack* pTrack = static_cast<CCompoundSplineTrack*>(GetTrackForParameter(param));
|
|
if (pTrack && pTrack->GetValueType() == AnimValueType::Vector4 && pTrack->GetNumKeys() > 0)
|
|
{
|
|
// Vec4 track.
|
|
pTrack->GetValue(time, value);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
/// @deprecated Serialization for Sequence data in Component Entity Sequences now occurs through AZ::SerializeContext and the Sequence Component
|
|
void CAnimNode::Serialize(XmlNodeRef& xmlNode, bool bLoading, bool bLoadEmptyTracks)
|
|
{
|
|
if (bLoading)
|
|
{
|
|
xmlNode->getAttr("Id", m_id);
|
|
const char* name = xmlNode->getAttr("Name");
|
|
int flags;
|
|
if (xmlNode->getAttr("Flags", flags))
|
|
{
|
|
// Don't load expanded or selected flags
|
|
flags = flags & ~(eAnimNodeFlags_Expanded | eAnimNodeFlags_EntitySelected);
|
|
SetFlags(flags);
|
|
}
|
|
|
|
SetName(name);
|
|
|
|
m_nLoadedParentNodeId = 0;
|
|
xmlNode->getAttr("ParentNode", m_nLoadedParentNodeId);
|
|
}
|
|
else
|
|
{
|
|
m_nLoadedParentNodeId = 0;
|
|
xmlNode->setAttr("Id", m_id);
|
|
|
|
AnimNodeType nodeType = GetType();
|
|
GetMovieSystem()->SerializeNodeType(nodeType, xmlNode, bLoading, IAnimSequence::kSequenceVersion, m_flags);
|
|
|
|
xmlNode->setAttr("Name", GetName());
|
|
|
|
// Don't store expanded or selected flags
|
|
int flags = GetFlags() & ~(eAnimNodeFlags_Expanded | eAnimNodeFlags_EntitySelected);
|
|
xmlNode->setAttr("Flags", flags);
|
|
|
|
if (m_pParentNode)
|
|
{
|
|
xmlNode->setAttr("ParentNode", static_cast<CAnimNode*>(m_pParentNode)->GetId());
|
|
}
|
|
}
|
|
|
|
SerializeAnims(xmlNode, bLoading, bLoadEmptyTracks);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimNode::InitPostLoad(IAnimSequence* sequence)
|
|
{
|
|
m_pSequence = sequence;
|
|
m_pParentNode = ((CAnimSequence*)m_pSequence)->FindNodeById(m_parentNodeId);
|
|
|
|
// fix up animNode pointers and time ranges on tracks, then sort them
|
|
for (unsigned int i = 0; i < m_tracks.size(); i++)
|
|
{
|
|
RegisterTrack(m_tracks[i].get());
|
|
m_tracks[i].get()->InitPostLoad(sequence);
|
|
}
|
|
SortTracks();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimNode::SetNodeOwner(IAnimNodeOwner* pOwner)
|
|
{
|
|
m_pOwner = pOwner;
|
|
|
|
if (pOwner)
|
|
{
|
|
pOwner->OnNodeAnimated(this);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimNode::PostLoad()
|
|
{
|
|
if (m_nLoadedParentNodeId)
|
|
{
|
|
IAnimNode* pParentNode = ((CAnimSequence*)m_pSequence)->FindNodeById(m_nLoadedParentNodeId);
|
|
m_pParentNode = pParentNode;
|
|
m_parentNodeId = m_nLoadedParentNodeId; // adding as a temporary fix while we support both serialization methods
|
|
m_nLoadedParentNodeId = 0;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
Matrix34 CAnimNode::GetReferenceMatrix() const
|
|
{
|
|
static Matrix34 tm(IDENTITY);
|
|
return tm;
|
|
}
|
|
|
|
IAnimTrack* CAnimNode::CreateTrackInternalFloat([[maybe_unused]] int trackType) const
|
|
{
|
|
return aznew C2DSplineTrack;
|
|
}
|
|
|
|
IAnimTrack* CAnimNode::CreateTrackInternalVector([[maybe_unused]] EAnimCurveType trackType, const CAnimParamType& paramType, const AnimValueType animValue) const
|
|
{
|
|
CAnimParamType subTrackParamTypes[MAX_SUBTRACKS];
|
|
for (unsigned int i = 0; i < MAX_SUBTRACKS; ++i)
|
|
{
|
|
subTrackParamTypes[i] = AnimParamType::Float;
|
|
}
|
|
|
|
if (paramType == AnimParamType::Position)
|
|
{
|
|
subTrackParamTypes[0] = AnimParamType::PositionX;
|
|
subTrackParamTypes[1] = AnimParamType::PositionY;
|
|
subTrackParamTypes[2] = AnimParamType::PositionZ;
|
|
}
|
|
else if (paramType == AnimParamType::Scale)
|
|
{
|
|
subTrackParamTypes[0] = AnimParamType::ScaleX;
|
|
subTrackParamTypes[1] = AnimParamType::ScaleY;
|
|
subTrackParamTypes[2] = AnimParamType::ScaleZ;
|
|
}
|
|
else if (paramType == AnimParamType::Rotation)
|
|
{
|
|
subTrackParamTypes[0] = AnimParamType::RotationX;
|
|
subTrackParamTypes[1] = AnimParamType::RotationY;
|
|
subTrackParamTypes[2] = AnimParamType::RotationZ;
|
|
IAnimTrack* pTrack = aznew CCompoundSplineTrack(3, AnimValueType::Quat, subTrackParamTypes, false);
|
|
return pTrack;
|
|
}
|
|
else if (paramType == AnimParamType::DepthOfField)
|
|
{
|
|
subTrackParamTypes[0] = AnimParamType::FocusDistance;
|
|
subTrackParamTypes[1] = AnimParamType::FocusRange;
|
|
subTrackParamTypes[2] = AnimParamType::BlurAmount;
|
|
IAnimTrack* pTrack = aznew CCompoundSplineTrack(3, AnimValueType::Vector, subTrackParamTypes, false);
|
|
pTrack->SetSubTrackName(0, "FocusDist");
|
|
pTrack->SetSubTrackName(1, "FocusRange");
|
|
pTrack->SetSubTrackName(2, "BlurAmount");
|
|
return pTrack;
|
|
}
|
|
else if (animValue == AnimValueType::RGB || paramType == AnimParamType::LightDiffuse ||
|
|
paramType == AnimParamType::MaterialDiffuse || paramType == AnimParamType::MaterialSpecular
|
|
|| paramType == AnimParamType::MaterialEmissive)
|
|
{
|
|
subTrackParamTypes[0] = AnimParamType::ColorR;
|
|
subTrackParamTypes[1] = AnimParamType::ColorG;
|
|
subTrackParamTypes[2] = AnimParamType::ColorB;
|
|
IAnimTrack* pTrack = aznew CCompoundSplineTrack(3, AnimValueType::RGB, subTrackParamTypes, false);
|
|
pTrack->SetSubTrackName(0, "Red");
|
|
pTrack->SetSubTrackName(1, "Green");
|
|
pTrack->SetSubTrackName(2, "Blue");
|
|
return pTrack;
|
|
}
|
|
|
|
return aznew CCompoundSplineTrack(3, AnimValueType::Vector, subTrackParamTypes, false);
|
|
}
|
|
|
|
IAnimTrack* CAnimNode::CreateTrackInternalQuat([[maybe_unused]] EAnimCurveType trackType, const CAnimParamType& paramType) const
|
|
{
|
|
CAnimParamType subTrackParamTypes[MAX_SUBTRACKS];
|
|
if (paramType == AnimParamType::Rotation)
|
|
{
|
|
subTrackParamTypes[0] = AnimParamType::RotationX;
|
|
subTrackParamTypes[1] = AnimParamType::RotationY;
|
|
subTrackParamTypes[2] = AnimParamType::RotationZ;
|
|
}
|
|
else
|
|
{
|
|
// Unknown param type
|
|
assert(0);
|
|
}
|
|
|
|
return aznew CCompoundSplineTrack(3, AnimValueType::Quat, subTrackParamTypes, false);
|
|
}
|
|
|
|
IAnimTrack* CAnimNode::CreateTrackInternalVector4(const CAnimParamType& paramType) const
|
|
{
|
|
IAnimTrack* pTrack;
|
|
|
|
CAnimParamType subTrackParamTypes[MAX_SUBTRACKS];
|
|
|
|
// set up track subtypes
|
|
if (paramType == AnimParamType::TransformNoise
|
|
|| paramType == AnimParamType::ShakeMultiplier)
|
|
{
|
|
subTrackParamTypes[0] = AnimParamType::ShakeAmpAMult;
|
|
subTrackParamTypes[1] = AnimParamType::ShakeAmpBMult;
|
|
subTrackParamTypes[2] = AnimParamType::ShakeFreqAMult;
|
|
subTrackParamTypes[3] = AnimParamType::ShakeFreqBMult;
|
|
}
|
|
else
|
|
{
|
|
// default to a Vector4 of floats
|
|
for (unsigned int i = 0; i < MAX_SUBTRACKS; ++i)
|
|
{
|
|
subTrackParamTypes[i] = AnimParamType::Float;
|
|
}
|
|
}
|
|
|
|
// create track
|
|
pTrack = aznew CCompoundSplineTrack(4, AnimValueType::Vector4, subTrackParamTypes, true);
|
|
|
|
// label subtypes
|
|
if (paramType == AnimParamType::TransformNoise)
|
|
{
|
|
pTrack->SetSubTrackName(0, "Pos Noise Amp");
|
|
pTrack->SetSubTrackName(1, "Pos Noise Freq");
|
|
pTrack->SetSubTrackName(2, "Rot Noise Amp");
|
|
pTrack->SetSubTrackName(3, "Rot Noise Freq");
|
|
}
|
|
else if (paramType == AnimParamType::ShakeMultiplier)
|
|
{
|
|
pTrack->SetSubTrackName(0, "Amplitude A");
|
|
pTrack->SetSubTrackName(1, "Amplitude B");
|
|
pTrack->SetSubTrackName(2, "Frequency A");
|
|
pTrack->SetSubTrackName(3, "Frequency B");
|
|
}
|
|
|
|
return pTrack;
|
|
}
|
|
|
|
void CAnimNode::TimeChanged(float newTime)
|
|
{
|
|
// if the newTime is on a sound key, then reset sounds so sound will playback on next call to Animate()
|
|
if (IsTimeOnSoundKey(newTime))
|
|
{
|
|
ResetSounds();
|
|
}
|
|
}
|
|
|
|
bool CAnimNode::IsTimeOnSoundKey(float queryTime) const
|
|
{
|
|
bool retIsTimeOnSoundKey = false;
|
|
const float tolerance = 0.0333f; // one frame at 30 fps
|
|
|
|
int trackCount = NumTracks();
|
|
for (int trackIndex = 0; trackIndex < trackCount; trackIndex++)
|
|
{
|
|
CAnimParamType paramType = m_tracks[trackIndex]->GetParameterType();
|
|
IAnimTrack* pTrack = m_tracks[trackIndex].get();
|
|
if ((paramType.GetType() != AnimParamType::Sound)
|
|
|| (pTrack->HasKeys() == false && pTrack->GetParameterType() != AnimParamType::Visibility)
|
|
|| (pTrack->GetFlags() & IAnimTrack::eAnimTrackFlags_Disabled))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// if we're here, pTrack points to a AnimParamType::Sound track
|
|
ISoundKey oSoundKey;
|
|
int const nSoundKey = static_cast<CSoundTrack*>(pTrack)->GetActiveKey(queryTime, &oSoundKey);
|
|
if (nSoundKey >= 0)
|
|
{
|
|
retIsTimeOnSoundKey = AZ::IsClose(queryTime, oSoundKey.time, tolerance);
|
|
if (retIsTimeOnSoundKey)
|
|
{
|
|
break; // no need to search further, we have a hit
|
|
}
|
|
}
|
|
}
|
|
|
|
return retIsTimeOnSoundKey;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimNode::AnimateSound(std::vector<SSoundInfo>& nodeSoundInfo, SAnimContext& ec, IAnimTrack* pTrack, size_t numAudioTracks)
|
|
{
|
|
bool const bMute = gEnv->IsEditor() && (pTrack->GetFlags() & IAnimTrack::eAnimTrackFlags_Muted);
|
|
|
|
if (!bMute && ec.time >= 0.0f)
|
|
{
|
|
ISoundKey oSoundKey;
|
|
int const nSoundKey = static_cast<CSoundTrack*>(pTrack)->GetActiveKey(ec.time, &oSoundKey);
|
|
SSoundInfo& rSoundInfo = nodeSoundInfo[numAudioTracks - 1];
|
|
|
|
if (nSoundKey >= 0)
|
|
{
|
|
float const fSoundKeyTime = (ec.time - oSoundKey.time);
|
|
|
|
if (rSoundInfo.nSoundKeyStart < nSoundKey && fSoundKeyTime < oSoundKey.fDuration)
|
|
{
|
|
ApplyAudioKey(oSoundKey.sStartTrigger.c_str());
|
|
}
|
|
|
|
if (rSoundInfo.nSoundKeyStart > nSoundKey)
|
|
{
|
|
rSoundInfo.nSoundKeyStop = nSoundKey;
|
|
}
|
|
|
|
rSoundInfo.nSoundKeyStart = nSoundKey;
|
|
|
|
if (fSoundKeyTime >= oSoundKey.fDuration)
|
|
{
|
|
if (rSoundInfo.nSoundKeyStop < nSoundKey)
|
|
{
|
|
rSoundInfo.nSoundKeyStop = nSoundKey;
|
|
|
|
if (oSoundKey.sStopTrigger.empty())
|
|
{
|
|
ApplyAudioKey(oSoundKey.sStartTrigger.c_str(), false);
|
|
}
|
|
else
|
|
{
|
|
ApplyAudioKey(oSoundKey.sStopTrigger.c_str());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rSoundInfo.nSoundKeyStop = -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rSoundInfo.Reset();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CAnimNode::SetParent(IAnimNode* parent)
|
|
{
|
|
m_pParentNode = parent;
|
|
if (parent)
|
|
{
|
|
m_parentNodeId = static_cast<CAnimNode*>(m_pParentNode)->GetId();
|
|
}
|
|
else
|
|
{
|
|
m_parentNodeId = 0;
|
|
}
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
IAnimNode* CAnimNode::HasDirectorAsParent() const
|
|
{
|
|
IAnimNode* pParent = GetParent();
|
|
while (pParent)
|
|
{
|
|
if (pParent->GetType() == AnimNodeType::Director)
|
|
{
|
|
return pParent;
|
|
}
|
|
// There are some invalid data.
|
|
if (pParent->GetParent() == pParent)
|
|
{
|
|
pParent->SetParent(NULL);
|
|
return NULL;
|
|
}
|
|
pParent = pParent->GetParent();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void CAnimNode::UpdateDynamicParams()
|
|
{
|
|
if (gEnv->IsEditor())
|
|
{
|
|
// UpdateDynamicParams is called as the result of an editor event that is fired when a material is loaded,
|
|
// which could happen from multiple threads. Lock to avoid a crash iterating over the lua stack
|
|
AZStd::lock_guard<AZStd::mutex> lock(m_updateDynamicParamsLock);
|
|
|
|
// run this on the main thread to prevent further threading issues downstream in
|
|
// AnimNodes that may use EBuses that are not thread safe
|
|
if (gEnv && gEnv->mMainThreadId == CryGetCurrentThreadId())
|
|
{
|
|
UpdateDynamicParamsInternal();
|
|
}
|
|
else
|
|
{
|
|
AZ::TickBus::QueueFunction([this] {
|
|
UpdateDynamicParamsInternal();
|
|
});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UpdateDynamicParamsInternal();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void CAnimNode::SetExpanded(bool expanded)
|
|
{
|
|
m_expanded = expanded;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool CAnimNode::GetExpanded() const
|
|
{
|
|
return m_expanded;
|
|
}
|