3
0

AzEntityNode.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "AzEntityNode.h"
  9. #include "AnimSplineTrack.h"
  10. #include "BoolTrack.h"
  11. #include "ISystem.h"
  12. #include "CompoundSplineTrack.h"
  13. #include "UiAnimationSystem.h"
  14. #include "PNoise3.h"
  15. #include "AnimSequence.h"
  16. #include <AzCore/Serialization/SerializeContext.h>
  17. #include <AzCore/Component/ComponentApplicationBus.h>
  18. #include <LyShine/Bus/UiAnimateEntityBus.h>
  19. //////////////////////////////////////////////////////////////////////////
  20. namespace
  21. {
  22. const char* kScriptTablePrefix = "ScriptTable:";
  23. AZStd::array<CUiAnimNode::SParamInfo, 1> s_nodeParams{ { {
  24. /*.name =*/"Component Field float",
  25. /*.paramType =*/eUiAnimParamType_AzComponentField,
  26. /*.valueType =*/eUiAnimValue_Float,
  27. /*.flags =*/(IUiAnimNode::ESupportedParamFlags)0,
  28. } } };
  29. }
  30. //////////////////////////////////////////////////////////////////////////
  31. CUiAnimAzEntityNode::CUiAnimAzEntityNode(const int id)
  32. : CUiAnimNode(id, eUiAnimNodeType_AzEntity)
  33. {
  34. m_bWasTransRot = false;
  35. m_bInitialPhysicsStatus = false;
  36. m_pos(0, 0, 0);
  37. m_scale(1, 1, 1);
  38. m_rotate.SetIdentity();
  39. m_visible = true;
  40. m_time = 0.0f;
  41. m_lastEntityKey = -1;
  42. #ifdef CHECK_FOR_TOO_MANY_ONPROPERTY_SCRIPT_CALLS
  43. m_OnPropertyCalls = 0;
  44. #endif
  45. UiAnimNodeBus::Handler::BusConnect(this);
  46. }
  47. //////////////////////////////////////////////////////////////////////////
  48. CUiAnimAzEntityNode::CUiAnimAzEntityNode()
  49. : CUiAnimAzEntityNode(0)
  50. {
  51. }
  52. //////////////////////////////////////////////////////////////////////////
  53. void CUiAnimAzEntityNode::AddTrack(IUiAnimTrack* track)
  54. {
  55. CUiAnimNode::AddTrack(track);
  56. }
  57. //////////////////////////////////////////////////////////////////////////
  58. void CUiAnimAzEntityNode::UpdateDynamicParams()
  59. {
  60. m_entityScriptPropertiesParamInfos.clear();
  61. m_nameToScriptPropertyParamInfo.clear();
  62. // editor stores *all* properties of *every* entity used in an AnimAzEntityNode, including to-display names, full lua paths, string maps for fast access, etc.
  63. // in pure game mode we just need to store the properties that we know are going to be used in a track, so we can save a lot of memory.
  64. if (gEnv->IsEditor())
  65. {
  66. UpdateDynamicParams_Editor();
  67. }
  68. else
  69. {
  70. UpdateDynamicParams_PureGame();
  71. }
  72. }
  73. //////////////////////////////////////////////////////////////////////////
  74. void CUiAnimAzEntityNode::UpdateDynamicParams_Editor()
  75. {
  76. }
  77. //////////////////////////////////////////////////////////////////////////
  78. void CUiAnimAzEntityNode::UpdateDynamicParams_PureGame()
  79. {
  80. }
  81. //////////////////////////////////////////////////////////////////////////
  82. void CUiAnimAzEntityNode::CreateDefaultTracks()
  83. {
  84. }
  85. //////////////////////////////////////////////////////////////////////////
  86. CUiAnimAzEntityNode::~CUiAnimAzEntityNode()
  87. {
  88. ReleaseSounds();
  89. UiAnimNodeBus::Handler::BusDisconnect();
  90. }
  91. //////////////////////////////////////////////////////////////////////////
  92. unsigned int CUiAnimAzEntityNode::GetParamCount() const
  93. {
  94. return static_cast<unsigned int>(CUiAnimAzEntityNode::GetParamCountStatic() + m_entityScriptPropertiesParamInfos.size());
  95. }
  96. //////////////////////////////////////////////////////////////////////////
  97. CUiAnimParamType CUiAnimAzEntityNode::GetParamType(unsigned int nIndex) const
  98. {
  99. SParamInfo info;
  100. if (!CUiAnimAzEntityNode::GetParamInfoStatic(nIndex, info))
  101. {
  102. const uint scriptParamsOffset = (uint)s_nodeParams.size();
  103. const uint end = (uint)s_nodeParams.size() + (uint)m_entityScriptPropertiesParamInfos.size();
  104. if (nIndex >= scriptParamsOffset && nIndex < end)
  105. {
  106. return m_entityScriptPropertiesParamInfos[nIndex - scriptParamsOffset].animNodeParamInfo.paramType;
  107. }
  108. return eUiAnimParamType_Invalid;
  109. }
  110. return info.paramType;
  111. }
  112. //////////////////////////////////////////////////////////////////////////
  113. int CUiAnimAzEntityNode::GetParamCountStatic()
  114. {
  115. return static_cast<int>(s_nodeParams.size());
  116. }
  117. //////////////////////////////////////////////////////////////////////////
  118. bool CUiAnimAzEntityNode::GetParamInfoStatic(int nIndex, SParamInfo& info)
  119. {
  120. if (nIndex >= 0 && nIndex < (int)s_nodeParams.size())
  121. {
  122. info = s_nodeParams[nIndex];
  123. return true;
  124. }
  125. return false;
  126. }
  127. //////////////////////////////////////////////////////////////////////////
  128. void CUiAnimAzEntityNode::Reflect(AZ::SerializeContext* serializeContext)
  129. {
  130. serializeContext->Class<CUiAnimAzEntityNode, CUiAnimNode>()
  131. ->Version(1)
  132. ->Field("Entity", &CUiAnimAzEntityNode::m_entityId);
  133. }
  134. //////////////////////////////////////////////////////////////////////////
  135. bool CUiAnimAzEntityNode::GetParamInfoFromType(const CUiAnimParamType& paramId, SParamInfo& info) const
  136. {
  137. for (int i = 0; i < (int)s_nodeParams.size(); i++)
  138. {
  139. if (s_nodeParams[i].paramType == paramId)
  140. {
  141. info = s_nodeParams[i];
  142. return true;
  143. }
  144. }
  145. for (size_t i = 0; i < m_entityScriptPropertiesParamInfos.size(); ++i)
  146. {
  147. if (m_entityScriptPropertiesParamInfos[i].animNodeParamInfo.paramType == paramId)
  148. {
  149. info = m_entityScriptPropertiesParamInfos[i].animNodeParamInfo;
  150. return true;
  151. }
  152. }
  153. return false;
  154. }
  155. //////////////////////////////////////////////////////////////////////////
  156. const AZ::SerializeContext::ClassElement* CUiAnimAzEntityNode::ComputeOffsetFromElementName(
  157. const AZ::SerializeContext::ClassData* classData,
  158. IUiAnimTrack* track,
  159. size_t baseOffset)
  160. {
  161. const UiAnimParamData& paramData = track->GetParamData();
  162. // find the data element in the class data that matches the name in the paramData
  163. AZ::Crc32 nameCrc = AZ_CRC(paramData.GetName());
  164. const AZ::SerializeContext::ClassElement* element = nullptr;
  165. for (const AZ::SerializeContext::ClassElement& classElement : classData->m_elements)
  166. {
  167. if (classElement.m_nameCrc == nameCrc)
  168. {
  169. element = &classElement;
  170. break;
  171. }
  172. }
  173. // if the name doesn't exist or is of the wrong type then the animation data
  174. // no longer matches the component definition. This could happen if the serialization format of
  175. // a component is changed. We don't want to assert in that case. Ideally we would have
  176. // some way of converting the animation data. We do not have that yet. So we will output a warning
  177. // and recover.
  178. if (!element || element->m_typeId != paramData.GetTypeId())
  179. {
  180. bool mismatch = true;
  181. if (element)
  182. {
  183. // Allow AZ::Vector2 types to be assigned Vec2 animation data and AZ::Color types
  184. // to be assiged AZ::Vector3 animation data
  185. if (((element->m_typeId == AZ::SerializeTypeInfo<AZ::Vector2>::GetUuid()) && (paramData.GetTypeId() == AZ::SerializeTypeInfo<Vec2>::GetUuid()))
  186. || ((element->m_typeId == AZ::SerializeTypeInfo<AZ::Color>::GetUuid()) && (paramData.GetTypeId() == AZ::SerializeTypeInfo<AZ::Vector3>::GetUuid())))
  187. {
  188. mismatch = false;
  189. }
  190. }
  191. if (mismatch)
  192. {
  193. CryWarning(VALIDATOR_MODULE_SHINE, VALIDATOR_WARNING,
  194. "Data mismatch reading animation data for type %s. The field \"%s\" %s. This part of the animation data will be ignored.",
  195. classData->m_typeId.ToString<AZStd::string>().c_str(),
  196. paramData.GetName(),
  197. (!element ? "cannot be found" : "has a different type to that in the animation data")
  198. );
  199. return nullptr;
  200. }
  201. }
  202. // Set the correct offset in the param data for the track
  203. UiAnimParamData newParamData(paramData.GetComponentId(), paramData.GetName(), element->m_typeId, baseOffset + element->m_offset);
  204. track->SetParamData(newParamData);
  205. return element;
  206. }
  207. //////////////////////////////////////////////////////////////////////////
  208. void CUiAnimAzEntityNode::ComputeOffsetsFromElementNames()
  209. {
  210. // Get the serialize context for the application
  211. AZ::SerializeContext* context = nullptr;
  212. AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
  213. AZ_Assert(context, "No serialization context found");
  214. // Get the AZ entity that this node is animating
  215. AZ::Entity* entity = nullptr;
  216. AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationBus::Events::FindEntity, m_entityId);
  217. if (!entity)
  218. {
  219. // This can happen, if a UI element is deleted we do not delete all AnimNodes
  220. // that reference it (which could be in multiple sequences). Instead we leave
  221. // them in the sequences and draw them in red and they have no effect.
  222. // If the canvas is saved like that and reloaded we come through here. The
  223. // AnimNode can't be made functional again at this point but is there so that
  224. // the user can see that their sequence was animating something that has now
  225. // been deleted.
  226. return;
  227. }
  228. // go through all its tracks and update the offsets
  229. for (int i = 0, num = (int)m_tracks.size(); i < num; i++)
  230. {
  231. IUiAnimTrack* track = m_tracks[i].get();
  232. if (track->GetParameterType() == eUiAnimParamType_AzComponentField)
  233. {
  234. // Get the class data for the component that this track is animating
  235. const UiAnimParamData& paramData = track->GetParamData();
  236. AZ::Component* component = paramData.GetComponent(entity);
  237. const AZ::Uuid& classId = AZ::SerializeTypeInfo<AZ::Component>::GetUuid(component);
  238. const AZ::SerializeContext::ClassData* classData = context->FindClassData(classId);
  239. // update the offset for the field this track is animating
  240. const AZ::SerializeContext::ClassElement* element = ComputeOffsetFromElementName(classData, track, 0);
  241. bool deleteTrack = false;
  242. if (element)
  243. {
  244. // the field is a valid field in the component, proceed with sub tracks if any
  245. size_t baseOffset = element->m_offset;
  246. const AZ::SerializeContext::ClassData* baseElementClassData = context->FindClassData(element->m_typeId);
  247. // Search the sub-tracks also if any.
  248. if (baseElementClassData && !baseElementClassData->m_elements.empty())
  249. {
  250. for (int k = 0; k < track->GetSubTrackCount(); ++k)
  251. {
  252. IUiAnimTrack* pSubTrack = track->GetSubTrack(k);
  253. if (pSubTrack->GetParameterType() == eUiAnimParamType_AzComponentField)
  254. {
  255. // update the offset for this subtrack
  256. if (!ComputeOffsetFromElementName(baseElementClassData, pSubTrack, baseOffset))
  257. {
  258. deleteTrack = true; // animation data is no longer valid
  259. }
  260. }
  261. }
  262. }
  263. }
  264. else
  265. {
  266. deleteTrack = true; // animation data is no longer valid
  267. }
  268. if (deleteTrack)
  269. {
  270. // delete track and leave as nullptr to be cleaned up after loop
  271. m_tracks[i].reset();
  272. }
  273. }
  274. }
  275. // remove any null entries from m_tracks (only happens if we found invalid animation data)
  276. stl::find_and_erase_if(m_tracks, [](const AZStd::intrusive_ptr<IUiAnimTrack>& sp) { return !sp; });
  277. }
  278. //////////////////////////////////////////////////////////////////////////
  279. AZStd::string CUiAnimAzEntityNode::GetParamName(const CUiAnimParamType& param) const
  280. {
  281. SParamInfo info;
  282. if (GetParamInfoFromType(param, info))
  283. {
  284. return info.name;
  285. }
  286. const char* pName = param.GetName();
  287. if (param.GetType() == eUiAnimParamType_ByString && pName && strncmp(pName, kScriptTablePrefix, strlen(kScriptTablePrefix)) == 0)
  288. {
  289. return pName + strlen(kScriptTablePrefix);
  290. }
  291. return "Unknown Entity Parameter";
  292. }
  293. //////////////////////////////////////////////////////////////////////////
  294. AZStd::string CUiAnimAzEntityNode::GetParamNameForTrack(const CUiAnimParamType& param, const IUiAnimTrack* track) const
  295. {
  296. // for Az Component Fields we use the name from the ClassElement
  297. if (param == eUiAnimParamType_AzComponentField)
  298. {
  299. // if the edit context is available it would be better to use the EditContext to get
  300. // the name? If so then we should pass than in as the name when creating the track
  301. return track->GetParamData().GetName();
  302. }
  303. SParamInfo info;
  304. if (GetParamInfoFromType(param, info))
  305. {
  306. return info.name;
  307. }
  308. const char* pName = param.GetName();
  309. if (param.GetType() == eUiAnimParamType_ByString && pName && strncmp(pName, kScriptTablePrefix, strlen(kScriptTablePrefix)) == 0)
  310. {
  311. return pName + strlen(kScriptTablePrefix);
  312. }
  313. return "Unknown Entity Parameter";
  314. }
  315. //////////////////////////////////////////////////////////////////////////
  316. void CUiAnimAzEntityNode::StillUpdate()
  317. {
  318. // used to handle LookAt
  319. }
  320. //////////////////////////////////////////////////////////////////////////
  321. void CUiAnimAzEntityNode::EnableEntityPhysics([[maybe_unused]] bool bEnable)
  322. {
  323. }
  324. //////////////////////////////////////////////////////////////////////////
  325. void CUiAnimAzEntityNode::Animate(SUiAnimContext& ec)
  326. {
  327. if (!m_entityId.IsValid())
  328. {
  329. return;
  330. }
  331. AZ::Entity* entity = nullptr;
  332. AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationBus::Events::FindEntity, m_entityId);
  333. if (!entity)
  334. {
  335. // This can happen, if a UI element is deleted we do not delete all AnimNodes
  336. // that reference it (which could be in multiple sequences). Instead we leave
  337. // them in the sequences and draw them in red and they have no effect. If the
  338. // delete is undone they will go back to working.
  339. return;
  340. }
  341. int trackCount = NumTracks();
  342. for (int paramIndex = 0; paramIndex < trackCount; paramIndex++)
  343. {
  344. IUiAnimTrack* track = m_tracks[paramIndex].get();
  345. CUiAnimParamType paramType = m_tracks[paramIndex]->GetParameterType();
  346. if ((track->HasKeys() == false)
  347. || (track->GetFlags() & IUiAnimTrack::eUiAnimTrackFlags_Disabled)
  348. || track->IsMasked(ec.trackMask))
  349. {
  350. continue;
  351. }
  352. AZ_Assert(paramType.GetType() == eUiAnimParamType_AzComponentField, "Invalid param type");
  353. const UiAnimParamData& paramData = track->GetParamData();
  354. AZ::Component* component = paramData.GetComponent(entity);
  355. if (!component)
  356. {
  357. continue;
  358. }
  359. void* elementData = reinterpret_cast<char*>(component) + paramData.GetOffset();
  360. if (paramData.GetTypeId() == AZ::SerializeTypeInfo<float>::GetUuid())
  361. {
  362. float* elementFloat = reinterpret_cast<float*>(elementData);
  363. float trackValue;
  364. track->GetValue(ec.time, trackValue);
  365. *elementFloat = trackValue;
  366. }
  367. else if (paramData.GetTypeId() == AZ::SerializeTypeInfo<bool>::GetUuid())
  368. {
  369. bool* elementValue = reinterpret_cast<bool*>(elementData);
  370. bool trackValue;
  371. track->GetValue(ec.time, trackValue);
  372. *elementValue = trackValue;
  373. }
  374. else if (paramData.GetTypeId() == AZ::SerializeTypeInfo<AZ::Vector2>::GetUuid())
  375. {
  376. AZ::Vector2* elementValue = reinterpret_cast<AZ::Vector2*>(elementData);
  377. AZ::Vector2 trackValue;
  378. track->GetValue(ec.time, trackValue);
  379. *elementValue = trackValue;
  380. }
  381. else if (paramData.GetTypeId() == AZ::SerializeTypeInfo<AZ::Vector3>::GetUuid())
  382. {
  383. AZ::Vector3* elementValue = reinterpret_cast<AZ::Vector3*>(elementData);
  384. AZ::Vector3 trackValue;
  385. track->GetValue(ec.time, trackValue);
  386. *elementValue = trackValue;
  387. }
  388. else if (paramData.GetTypeId() == AZ::SerializeTypeInfo<AZ::Vector4>::GetUuid())
  389. {
  390. AZ::Vector4* elementValue = reinterpret_cast<AZ::Vector4*>(elementData);
  391. AZ::Vector4 trackValue;
  392. track->GetValue(ec.time, trackValue);
  393. *elementValue = trackValue;
  394. }
  395. else if (paramData.GetTypeId() == AZ::SerializeTypeInfo<AZ::Color>::GetUuid())
  396. {
  397. AZ::Color* elementValue = reinterpret_cast<AZ::Color*>(elementData);
  398. AZ::Color trackValue = AZ::Color::CreateOne(); // Initialize alpha
  399. track->GetValue(ec.time, trackValue);
  400. *elementValue = trackValue;
  401. }
  402. else
  403. {
  404. // Animate the sub-tracks also if any.
  405. for (int k = 0; k < track->GetSubTrackCount(); ++k)
  406. {
  407. IUiAnimTrack* pSubTrack = track->GetSubTrack(k);
  408. const UiAnimParamData& subTrackParamData = pSubTrack->GetParamData();
  409. if (pSubTrack->GetParameterType() == eUiAnimParamType_AzComponentField)
  410. {
  411. elementData = reinterpret_cast<char*>(component) + subTrackParamData.GetOffset();
  412. if (subTrackParamData.GetTypeId() == AZ::SerializeTypeInfo<float>::GetUuid())
  413. {
  414. float* elementFloat = reinterpret_cast<float*>(elementData);
  415. float trackValue;
  416. pSubTrack->GetValue(ec.time, trackValue);
  417. *elementFloat = trackValue;
  418. }
  419. else if (subTrackParamData.GetTypeId() == AZ::SerializeTypeInfo<bool>::GetUuid())
  420. {
  421. bool* elementValue = reinterpret_cast<bool*>(elementData);
  422. bool trackValue;
  423. pSubTrack->GetValue(ec.time, trackValue);
  424. *elementValue = trackValue;
  425. }
  426. }
  427. }
  428. }
  429. }
  430. m_time = ec.time;
  431. if (m_pOwner)
  432. {
  433. m_bIgnoreSetParam = true; // Prevents feedback change of track.
  434. m_pOwner->OnNodeUiAnimated(this);
  435. m_bIgnoreSetParam = false;
  436. }
  437. UiAnimateEntityBus::Event(m_entityId, &UiAnimateEntityBus::Events::PropertyValuesChanged);
  438. }
  439. //////////////////////////////////////////////////////////////////////////
  440. void CUiAnimAzEntityNode::ReleaseSounds()
  441. {
  442. // Audio: Stop all playing sounds
  443. }
  444. //////////////////////////////////////////////////////////////////////////
  445. void CUiAnimAzEntityNode::OnReset()
  446. {
  447. m_lastEntityKey = -1;
  448. ReleaseSounds();
  449. UpdateDynamicParams();
  450. }
  451. //////////////////////////////////////////////////////////////////////////
  452. void CUiAnimAzEntityNode::OnResetHard()
  453. {
  454. OnReset();
  455. if (m_pOwner)
  456. {
  457. m_pOwner->OnNodeReset(this);
  458. }
  459. }
  460. //////////////////////////////////////////////////////////////////////////
  461. void CUiAnimAzEntityNode::Activate(bool bActivate)
  462. {
  463. CUiAnimNode::Activate(bActivate);
  464. if (bActivate)
  465. {
  466. #ifdef CHECK_FOR_TOO_MANY_ONPROPERTY_SCRIPT_CALLS
  467. m_OnPropertyCalls = 0;
  468. #endif
  469. }
  470. else
  471. {
  472. #ifdef CHECK_FOR_TOO_MANY_ONPROPERTY_SCRIPT_CALLS
  473. IEntity* pEntity = GetEntity();
  474. if (m_OnPropertyCalls > 30) // arbitrary amount
  475. {
  476. CryWarning(VALIDATOR_MODULE_SHINE, VALIDATOR_ERROR, "Entity: %s. A UI animation has called lua function 'OnPropertyChange' too many (%d) times .This is a performance issue. Adding Some custom management in the entity lua code will fix the issue", pEntity ? pEntity->GetName() : "<UNKNOWN", m_OnPropertyCalls);
  477. }
  478. #endif
  479. }
  480. };
  481. //////////////////////////////////////////////////////////////////////////
  482. IUiAnimTrack* CUiAnimAzEntityNode::GetTrackForAzField(const UiAnimParamData& param) const
  483. {
  484. for (int i = 0, num = (int)m_tracks.size(); i < num; i++)
  485. {
  486. IUiAnimTrack* track = m_tracks[i].get();
  487. if (track->GetParameterType() == eUiAnimParamType_AzComponentField)
  488. {
  489. if (track->GetParamData() == param)
  490. {
  491. return track;
  492. }
  493. }
  494. // Search the sub-tracks also if any.
  495. for (int k = 0; k < track->GetSubTrackCount(); ++k)
  496. {
  497. IUiAnimTrack* pSubTrack = track->GetSubTrack(k);
  498. if (pSubTrack->GetParameterType() == eUiAnimParamType_AzComponentField)
  499. {
  500. if (pSubTrack->GetParamData() == param)
  501. {
  502. return pSubTrack;
  503. }
  504. }
  505. }
  506. }
  507. return 0;
  508. }
  509. //////////////////////////////////////////////////////////////////////////
  510. IUiAnimTrack* CUiAnimAzEntityNode::CreateTrackForAzField(const UiAnimParamData& param)
  511. {
  512. AZ::SerializeContext* context = nullptr;
  513. AZ::ComponentApplicationBus::BroadcastResult(context, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
  514. AZ_Assert(context, "No serialization context found");
  515. IUiAnimTrack* track = nullptr;
  516. const AZ::SerializeContext::ClassData* classData = context->FindClassData(param.GetTypeId());
  517. if (classData && !classData->m_elements.empty())
  518. {
  519. // this is a compound type, create a compound track
  520. // We only support compound tracks with 2, 3 or 4 subtracks
  521. int numElements = static_cast<int>(classData->m_elements.size());
  522. if (numElements < 2 || numElements > 4)
  523. {
  524. return nullptr;
  525. }
  526. EUiAnimValue valueType = eUiAnimValue_Unknown;
  527. switch (numElements)
  528. {
  529. case 2:
  530. valueType = eUiAnimValue_Vector2;
  531. break;
  532. case 3:
  533. valueType = eUiAnimValue_Vector3;
  534. break;
  535. case 4:
  536. valueType = eUiAnimValue_Vector4;
  537. break;
  538. }
  539. track = CreateTrackInternal(eUiAnimParamType_AzComponentField, eUiAnimCurveType_BezierFloat, valueType);
  540. track->SetParamData(param);
  541. int numSubTracks = track->GetSubTrackCount();
  542. int curSubTrack = 0;
  543. for (const AZ::SerializeContext::ClassElement& element : classData->m_elements)
  544. {
  545. if (element.m_typeId == AZ::SerializeTypeInfo<float>::GetUuid() && curSubTrack < numSubTracks)
  546. {
  547. IUiAnimTrack* pSubTrack = track->GetSubTrack(curSubTrack);
  548. pSubTrack->SetParameterType(eUiAnimParamType_AzComponentField);
  549. UiAnimParamData subTrackParam(param.GetComponentId(), element.m_name,
  550. element.m_typeId, param.GetOffset() + element.m_offset);
  551. pSubTrack->SetParamData(subTrackParam);
  552. track->SetSubTrackName(curSubTrack, element.m_name);
  553. curSubTrack++;
  554. }
  555. }
  556. for (int i = curSubTrack; i < numElements; ++i)
  557. {
  558. track->SetSubTrackName(i, "_unused"); // only happens if some elements were not floats
  559. }
  560. }
  561. else if (param.GetTypeId() == AZ::SerializeTypeInfo<AZ::Vector2>::GetUuid())
  562. {
  563. track = CreateVectorTrack(param, eUiAnimValue_Vector2, 2);
  564. }
  565. else if (param.GetTypeId() == AZ::SerializeTypeInfo<AZ::Vector3>::GetUuid())
  566. {
  567. track = CreateVectorTrack(param, eUiAnimValue_Vector3, 3);
  568. }
  569. else if (param.GetTypeId() == AZ::SerializeTypeInfo<AZ::Vector4>::GetUuid())
  570. {
  571. track = CreateVectorTrack(param, eUiAnimValue_Vector4, 4);
  572. }
  573. else if (param.GetTypeId() == AZ::SerializeTypeInfo<AZ::Color>::GetUuid())
  574. {
  575. // this is a compound type, create a compound track
  576. track = CreateTrackInternal(eUiAnimParamType_AzComponentField, eUiAnimCurveType_BezierFloat, eUiAnimValue_Vector3);
  577. track->SetParamData(param);
  578. track->SetSubTrackName(0, "R");
  579. track->SetSubTrackName(1, "G");
  580. track->SetSubTrackName(2, "B");
  581. int numSubTracks = track->GetSubTrackCount();
  582. for (int i = 0; i < numSubTracks; ++i)
  583. {
  584. IUiAnimTrack* pSubTrack = track->GetSubTrack(i);
  585. pSubTrack->SetParameterType(eUiAnimParamType_Float); // subtracks are not actual component properties
  586. }
  587. return track;
  588. }
  589. else
  590. {
  591. if (param.GetTypeId() == AZ::SerializeTypeInfo<float>::GetUuid())
  592. {
  593. track = CreateTrackInternal(eUiAnimParamType_AzComponentField, eUiAnimCurveType_BezierFloat, eUiAnimValue_Unknown);
  594. }
  595. else if (param.GetTypeId() == AZ::SerializeTypeInfo<bool>::GetUuid())
  596. {
  597. track = CreateTrackInternal(eUiAnimParamType_AzComponentField, eUiAnimCurveType_BezierFloat, eUiAnimValue_Bool);
  598. }
  599. else if (param.GetTypeId() == AZ::SerializeTypeInfo<int>::GetUuid())
  600. {
  601. // no support for int yet
  602. track = CreateTrackInternal(eUiAnimParamType_AzComponentField, eUiAnimCurveType_BezierFloat, eUiAnimValue_Bool);
  603. }
  604. else if (param.GetTypeId() == AZ::SerializeTypeInfo<unsigned int>::GetUuid())
  605. {
  606. // no support for int yet
  607. track = CreateTrackInternal(eUiAnimParamType_AzComponentField, eUiAnimCurveType_BezierFloat, eUiAnimValue_Bool);
  608. }
  609. track->SetParamData(param);
  610. }
  611. return track;
  612. }
  613. void CUiAnimAzEntityNode::OnStart()
  614. {
  615. }
  616. //////////////////////////////////////////////////////////////////////////
  617. void CUiAnimAzEntityNode::OnPause()
  618. {
  619. ReleaseSounds();
  620. }
  621. //////////////////////////////////////////////////////////////////////////
  622. void CUiAnimAzEntityNode::OnStop()
  623. {
  624. ReleaseSounds();
  625. }
  626. //////////////////////////////////////////////////////////////////////////
  627. bool CUiAnimAzEntityNode::SetParamValueAz(float time, const UiAnimParamData& param, float value)
  628. {
  629. IUiAnimTrack* track = GetTrackForAzField(param);
  630. if (track)
  631. {
  632. track->SetValue(time, value);
  633. return true;
  634. }
  635. return false;
  636. }
  637. //////////////////////////////////////////////////////////////////////////
  638. bool CUiAnimAzEntityNode::SetParamValueAz(float time, const UiAnimParamData& param, bool value)
  639. {
  640. IUiAnimTrack* track = GetTrackForAzField(param);
  641. if (track)
  642. {
  643. track->CreateKey(time);
  644. track->SetValue(time, value);
  645. return true;
  646. }
  647. return false;
  648. }
  649. //////////////////////////////////////////////////////////////////////////
  650. bool CUiAnimAzEntityNode::SetParamValueAz(float time, const UiAnimParamData& param, [[maybe_unused]] int value)
  651. {
  652. IUiAnimTrack* track = GetTrackForAzField(param);
  653. if (track)
  654. {
  655. track->CreateKey(time);
  656. return true;
  657. }
  658. return false;
  659. }
  660. //////////////////////////////////////////////////////////////////////////
  661. bool CUiAnimAzEntityNode::SetParamValueAz(float time, const UiAnimParamData& param, [[maybe_unused]] unsigned int value)
  662. {
  663. IUiAnimTrack* track = GetTrackForAzField(param);
  664. if (track)
  665. {
  666. track->CreateKey(time);
  667. return true;
  668. }
  669. return false;
  670. }
  671. //////////////////////////////////////////////////////////////////////////
  672. bool CUiAnimAzEntityNode::SetParamValueAz(float time, const UiAnimParamData& param, const AZ::Vector2& value)
  673. {
  674. IUiAnimTrack* track = GetTrackForAzField(param);
  675. if (track)
  676. {
  677. track->SetValue(time, value);
  678. return true;
  679. }
  680. return false;
  681. }
  682. //////////////////////////////////////////////////////////////////////////
  683. bool CUiAnimAzEntityNode::SetParamValueAz(float time, const UiAnimParamData& param, const AZ::Vector3& value)
  684. {
  685. IUiAnimTrack* track = GetTrackForAzField(param);
  686. if (track)
  687. {
  688. track->SetValue(time, value);
  689. return true;
  690. }
  691. return false;
  692. }
  693. //////////////////////////////////////////////////////////////////////////
  694. bool CUiAnimAzEntityNode::SetParamValueAz(float time, const UiAnimParamData& param, const AZ::Vector4& value)
  695. {
  696. IUiAnimTrack* track = GetTrackForAzField(param);
  697. if (track)
  698. {
  699. track->SetValue(time, value);
  700. return true;
  701. }
  702. return false;
  703. }
  704. //////////////////////////////////////////////////////////////////////////
  705. bool CUiAnimAzEntityNode::SetParamValueAz(float time, const UiAnimParamData& param, const AZ::Color& value)
  706. {
  707. IUiAnimTrack* track = GetTrackForAzField(param);
  708. if (track)
  709. {
  710. track->SetValue(time, value);
  711. return true;
  712. }
  713. return false;
  714. }
  715. //////////////////////////////////////////////////////////////////////////
  716. bool CUiAnimAzEntityNode::GetParamValueAz(float time, const UiAnimParamData& param, float& value)
  717. {
  718. IUiAnimTrack* track = GetTrackForAzField(param);
  719. if (track)
  720. {
  721. track->GetValue(time, value);
  722. return true;
  723. }
  724. return false;
  725. }
  726. //////////////////////////////////////////////////////////////////////////
  727. void CUiAnimAzEntityNode::Serialize(XmlNodeRef& xmlNode, bool bLoading, bool bLoadEmptyTracks)
  728. {
  729. CUiAnimNode::Serialize(xmlNode, bLoading, bLoadEmptyTracks);
  730. if (bLoading)
  731. {
  732. unsigned long idHi;
  733. unsigned long idLo;
  734. xmlNode->getAttr("EntityIdHi", idHi);
  735. xmlNode->getAttr("EntityIdLo", idLo);
  736. AZ::u64 id64 = ((AZ::u64)idHi) << 32 | idLo;
  737. m_entityId = AZ::EntityId(id64);
  738. }
  739. else
  740. {
  741. AZ::u64 id64 = static_cast<AZ::u64>(m_entityId);
  742. unsigned long idHi = id64 >> 32;
  743. unsigned long idLo = id64 & 0xFFFFFFFF;
  744. xmlNode->setAttr("EntityIdHi", idHi);
  745. xmlNode->setAttr("EntityIdLo", idLo);
  746. }
  747. }
  748. //////////////////////////////////////////////////////////////////////////
  749. void CUiAnimAzEntityNode::InitPostLoad(IUiAnimSequence* pSequence, bool remapIds, LyShine::EntityIdMap* entityIdMap)
  750. {
  751. // do base class init first
  752. CUiAnimNode::InitPostLoad(pSequence, remapIds, entityIdMap);
  753. if (remapIds)
  754. {
  755. // the UI element entityIDs were changed on load, so update the entityId of the
  756. // entity this node is animating using the given map
  757. AZ::EntityId newId = (*entityIdMap)[m_entityId];
  758. if (newId.IsValid())
  759. {
  760. m_entityId = newId;
  761. }
  762. }
  763. // We don't save the offset for each track in serialized data because, if they added or removed
  764. // fields in a component, the offset would be invalid. So we compute the offset on load using the
  765. // field name and type to find it in the class data
  766. ComputeOffsetsFromElementNames();
  767. }
  768. void CUiAnimAzEntityNode::PrecacheStatic([[maybe_unused]] float time)
  769. {
  770. }
  771. void CUiAnimAzEntityNode::PrecacheDynamic([[maybe_unused]] float time)
  772. {
  773. // Used to update durations of all character animations.
  774. }
  775. //////////////////////////////////////////////////////////////////////////
  776. Vec3 CUiAnimAzEntityNode::Noise::Get(float time) const
  777. {
  778. Vec3 noise;
  779. const float phase = time * m_freq;
  780. const Vec3 phase0 = Vec3(15.0f * m_freq, 55.1f * m_freq, 101.2f * m_freq);
  781. noise.x = gEnv->pSystem->GetNoiseGen()->Noise1D(phase + phase0.x) * m_amp;
  782. noise.y = gEnv->pSystem->GetNoiseGen()->Noise1D(phase + phase0.y) * m_amp;
  783. noise.z = gEnv->pSystem->GetNoiseGen()->Noise1D(phase + phase0.z) * m_amp;
  784. return noise;
  785. }
  786. IUiAnimTrack* CUiAnimAzEntityNode::CreateVectorTrack(const UiAnimParamData& param, EUiAnimValue valueType, int numElements)
  787. {
  788. // this is a compound type, create a compound track
  789. IUiAnimTrack* track = CreateTrackInternal(eUiAnimParamType_AzComponentField, eUiAnimCurveType_BezierFloat, valueType);
  790. track->SetParamData(param);
  791. track->SetSubTrackName(0, "X");
  792. track->SetSubTrackName(1, "Y");
  793. if (numElements > 2)
  794. {
  795. track->SetSubTrackName(2, "Z");
  796. if (numElements > 3)
  797. {
  798. track->SetSubTrackName(3, "W");
  799. }
  800. }
  801. for (int i = 0; i < numElements; ++i)
  802. {
  803. IUiAnimTrack* pSubTrack = track->GetSubTrack(i);
  804. pSubTrack->SetParameterType(eUiAnimParamType_Float); // subtracks are not actual component properties
  805. }
  806. return track;
  807. }