Slot.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  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. // AZ
  9. #include <AzCore/IO/Path/Path.h>
  10. #include <AzCore/Math/Color.h>
  11. #include <AzCore/Math/Vector2.h>
  12. #include <AzCore/Math/Vector3.h>
  13. #include <AzCore/Math/Vector4.h>
  14. #include <AzCore/RTTI/BehaviorContext.h>
  15. #include <AzCore/Serialization/EditContext.h>
  16. #include <AzCore/Serialization/Json/RegistrationContext.h>
  17. #include <AzCore/Serialization/SerializeContext.h>
  18. #include <AzCore/std/smart_ptr/make_shared.h>
  19. // Graph Model
  20. #include <GraphModel/Model/Connection.h>
  21. #include <GraphModel/Model/Graph.h>
  22. #include <GraphModel/Model/GraphContext.h>
  23. #include <GraphModel/Model/Node.h>
  24. #include <GraphModel/Model/Slot.h>
  25. namespace GraphModel
  26. {
  27. void SlotIdData::Reflect(AZ::ReflectContext* context)
  28. {
  29. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  30. if (serializeContext)
  31. {
  32. serializeContext->Class<SlotIdData>()
  33. ->Version(0)
  34. ->Field("m_name", &SlotIdData::m_name)
  35. ->Field("m_subId", &SlotIdData::m_subId)
  36. ;
  37. }
  38. }
  39. SlotIdData::SlotIdData(const SlotName& name)
  40. : m_name(name)
  41. {
  42. }
  43. SlotIdData::SlotIdData(const SlotName& name, SlotSubId subId)
  44. : m_name(name)
  45. , m_subId(subId)
  46. {
  47. }
  48. bool SlotIdData::IsValid() const
  49. {
  50. return !m_name.empty() && (m_subId >= 0);
  51. }
  52. bool SlotIdData::operator==(const SlotIdData& rhs) const
  53. {
  54. return (m_name == rhs.m_name) && (m_subId == rhs.m_subId);
  55. }
  56. bool SlotIdData::operator!=(const SlotIdData& rhs) const
  57. {
  58. return (m_name != rhs.m_name) || (m_subId != rhs.m_subId);
  59. }
  60. bool SlotIdData::operator<(const SlotIdData& rhs) const
  61. {
  62. if (m_name < rhs.m_name)
  63. {
  64. return true;
  65. }
  66. if (m_name == rhs.m_name)
  67. {
  68. return m_subId < rhs.m_subId;
  69. }
  70. return false;
  71. }
  72. bool SlotIdData::operator>(const SlotIdData& rhs) const
  73. {
  74. if (m_name > rhs.m_name)
  75. {
  76. return true;
  77. }
  78. if (m_name == rhs.m_name)
  79. {
  80. return m_subId > rhs.m_subId;
  81. }
  82. return false;
  83. }
  84. AZStd::size_t SlotIdData::GetHash() const
  85. {
  86. AZStd::size_t result = 0;
  87. AZStd::hash_combine(result, m_name);
  88. AZStd::hash_combine(result, m_subId);
  89. return result;
  90. }
  91. /////////////////////////////////////////////////////////
  92. // SlotDefinition
  93. SlotDefinitionPtr SlotDefinition::CreateInputData(
  94. AZStd::string_view name,
  95. AZStd::string_view displayName,
  96. DataTypePtr dataType,
  97. AZStd::any defaultValue,
  98. AZStd::string_view description,
  99. ExtendableSlotConfiguration* extendableSlotConfiguration,
  100. const AZStd::vector<AZStd::string>& enumValues,
  101. bool visibleOnNode,
  102. bool editableOnNode)
  103. {
  104. return CreateInputData(
  105. name,
  106. displayName,
  107. DataTypeList{ dataType },
  108. defaultValue,
  109. description,
  110. extendableSlotConfiguration,
  111. enumValues,
  112. visibleOnNode,
  113. editableOnNode);
  114. }
  115. SlotDefinitionPtr SlotDefinition::CreateInputData(
  116. AZStd::string_view name,
  117. AZStd::string_view displayName,
  118. DataTypeList supportedDataTypes,
  119. AZStd::any defaultValue,
  120. AZStd::string_view description,
  121. ExtendableSlotConfiguration* extendableSlotConfiguration,
  122. const AZStd::vector<AZStd::string>& enumValues,
  123. bool visibleOnNode,
  124. bool editableOnNode)
  125. {
  126. AZStd::shared_ptr<SlotDefinition> slotDefinition = AZStd::make_shared<SlotDefinition>();
  127. slotDefinition->m_slotDirection = SlotDirection::Input;
  128. slotDefinition->m_slotType = SlotType::Data;
  129. slotDefinition->m_name = name;
  130. slotDefinition->m_displayName = displayName;
  131. slotDefinition->m_supportedDataTypes = supportedDataTypes;
  132. slotDefinition->m_defaultValue = defaultValue;
  133. slotDefinition->m_description = description;
  134. slotDefinition->m_enumValues = enumValues;
  135. slotDefinition->m_visibleOnNode = visibleOnNode;
  136. slotDefinition->m_editableOnNode = editableOnNode;
  137. HandleExtendableSlotRegistration(slotDefinition, extendableSlotConfiguration);
  138. return slotDefinition;
  139. }
  140. SlotDefinitionPtr SlotDefinition::CreateOutputData(
  141. AZStd::string_view name,
  142. AZStd::string_view displayName,
  143. DataTypePtr dataType,
  144. AZStd::string_view description,
  145. ExtendableSlotConfiguration* extendableSlotConfiguration,
  146. const AZStd::vector<AZStd::string>& enumValues,
  147. bool visibleOnNode,
  148. bool editableOnNode)
  149. {
  150. AZStd::shared_ptr<SlotDefinition> slotDefinition = AZStd::make_shared<SlotDefinition>();
  151. slotDefinition->m_slotDirection = SlotDirection::Output;
  152. slotDefinition->m_slotType = SlotType::Data;
  153. slotDefinition->m_name = name;
  154. slotDefinition->m_displayName = displayName;
  155. slotDefinition->m_supportedDataTypes = { dataType };
  156. slotDefinition->m_defaultValue = dataType->GetDefaultValue();
  157. slotDefinition->m_enumValues = enumValues;
  158. slotDefinition->m_description = description;
  159. slotDefinition->m_visibleOnNode = visibleOnNode;
  160. slotDefinition->m_editableOnNode = editableOnNode;
  161. HandleExtendableSlotRegistration(slotDefinition, extendableSlotConfiguration);
  162. return slotDefinition;
  163. }
  164. SlotDefinitionPtr SlotDefinition::CreateInputEvent(
  165. AZStd::string_view name,
  166. AZStd::string_view displayName,
  167. AZStd::string_view description,
  168. ExtendableSlotConfiguration* extendableSlotConfiguration,
  169. bool visibleOnNode,
  170. bool editableOnNode)
  171. {
  172. AZStd::shared_ptr<SlotDefinition> slotDefinition = AZStd::make_shared<SlotDefinition>();
  173. slotDefinition->m_slotDirection = SlotDirection::Input;
  174. slotDefinition->m_slotType = SlotType::Event;
  175. slotDefinition->m_name = name;
  176. slotDefinition->m_displayName = displayName;
  177. slotDefinition->m_description = description;
  178. slotDefinition->m_visibleOnNode = visibleOnNode;
  179. slotDefinition->m_editableOnNode = editableOnNode;
  180. HandleExtendableSlotRegistration(slotDefinition, extendableSlotConfiguration);
  181. return slotDefinition;
  182. }
  183. SlotDefinitionPtr SlotDefinition::CreateOutputEvent(
  184. AZStd::string_view name,
  185. AZStd::string_view displayName,
  186. AZStd::string_view description,
  187. ExtendableSlotConfiguration* extendableSlotConfiguration,
  188. bool visibleOnNode,
  189. bool editableOnNode)
  190. {
  191. AZStd::shared_ptr<SlotDefinition> slotDefinition = AZStd::make_shared<SlotDefinition>();
  192. slotDefinition->m_slotDirection = SlotDirection::Output;
  193. slotDefinition->m_slotType = SlotType::Event;
  194. slotDefinition->m_name = name;
  195. slotDefinition->m_displayName = displayName;
  196. slotDefinition->m_description = description;
  197. slotDefinition->m_visibleOnNode = visibleOnNode;
  198. slotDefinition->m_editableOnNode = editableOnNode;
  199. HandleExtendableSlotRegistration(slotDefinition, extendableSlotConfiguration);
  200. return slotDefinition;
  201. }
  202. SlotDefinitionPtr SlotDefinition::CreateProperty(
  203. AZStd::string_view name,
  204. AZStd::string_view displayName,
  205. DataTypePtr dataType,
  206. AZStd::any defaultValue,
  207. AZStd::string_view description,
  208. ExtendableSlotConfiguration* extendableSlotConfiguration,
  209. const AZStd::vector<AZStd::string>& enumValues,
  210. bool visibleOnNode,
  211. bool editableOnNode)
  212. {
  213. AZStd::shared_ptr<SlotDefinition> slotDefinition = AZStd::make_shared<SlotDefinition>();
  214. slotDefinition->m_slotDirection = SlotDirection::Input;
  215. slotDefinition->m_slotType = SlotType::Property;
  216. slotDefinition->m_name = name;
  217. slotDefinition->m_displayName = displayName;
  218. slotDefinition->m_supportedDataTypes = { dataType };
  219. slotDefinition->m_defaultValue = defaultValue;
  220. slotDefinition->m_enumValues = enumValues;
  221. slotDefinition->m_description = description;
  222. slotDefinition->m_visibleOnNode = visibleOnNode;
  223. slotDefinition->m_editableOnNode = editableOnNode;
  224. HandleExtendableSlotRegistration(slotDefinition, extendableSlotConfiguration);
  225. return slotDefinition;
  226. }
  227. void SlotDefinition::HandleExtendableSlotRegistration(
  228. AZStd::shared_ptr<SlotDefinition> slotDefinition, ExtendableSlotConfiguration* extendableSlotConfiguration)
  229. {
  230. if (extendableSlotConfiguration)
  231. {
  232. slotDefinition->m_extendableSlotConfiguration = *extendableSlotConfiguration;
  233. if (slotDefinition->m_extendableSlotConfiguration.m_minimumSlots > slotDefinition->m_extendableSlotConfiguration.m_maximumSlots)
  234. {
  235. AZ_Assert(false, "Invalid extendable slot configuration for %s, minimum slots greater than maximum slots", slotDefinition->GetName().c_str());
  236. return;
  237. }
  238. slotDefinition->m_extendableSlotConfiguration.m_isValid = true;
  239. }
  240. }
  241. SlotDirection SlotDefinition::GetSlotDirection() const
  242. {
  243. return m_slotDirection;
  244. }
  245. SlotType SlotDefinition::GetSlotType() const
  246. {
  247. return m_slotType;
  248. }
  249. bool SlotDefinition::SupportsValues() const
  250. {
  251. return (GetSlotType() == SlotType::Data && GetSlotDirection() == SlotDirection::Input) ||
  252. (GetSlotType() == SlotType::Property);
  253. }
  254. bool SlotDefinition::SupportsDataTypes() const
  255. {
  256. return GetSlotType() == SlotType::Data || GetSlotType() == SlotType::Property;
  257. }
  258. bool SlotDefinition::SupportsConnections() const
  259. {
  260. return GetSlotType() == SlotType::Data || GetSlotType() == SlotType::Event;
  261. }
  262. bool SlotDefinition::IsVisibleOnNode() const
  263. {
  264. return m_visibleOnNode;
  265. }
  266. bool SlotDefinition::IsEditableOnNode() const
  267. {
  268. return m_editableOnNode;
  269. }
  270. bool SlotDefinition::SupportsExtendability() const
  271. {
  272. return m_extendableSlotConfiguration.m_isValid;
  273. }
  274. bool SlotDefinition::Is(SlotDirection slotDirection, SlotType slotType) const
  275. {
  276. return GetSlotDirection() == slotDirection && GetSlotType() == slotType;
  277. }
  278. const DataTypeList& SlotDefinition::GetSupportedDataTypes() const
  279. {
  280. return m_supportedDataTypes;
  281. }
  282. const SlotName& SlotDefinition::GetName() const
  283. {
  284. return m_name;
  285. }
  286. const AZStd::string& SlotDefinition::GetDisplayName() const
  287. {
  288. return m_displayName;
  289. }
  290. const AZStd::string& SlotDefinition::GetDescription() const
  291. {
  292. return m_description;
  293. }
  294. AZStd::any SlotDefinition::GetDefaultValue() const
  295. {
  296. return m_defaultValue;
  297. }
  298. const AZStd::vector<AZStd::string>& SlotDefinition::GetEnumValues() const
  299. {
  300. return m_enumValues;
  301. }
  302. const int SlotDefinition::GetMinimumSlots() const
  303. {
  304. return m_extendableSlotConfiguration.m_minimumSlots;
  305. }
  306. const int SlotDefinition::GetMaximumSlots() const
  307. {
  308. return m_extendableSlotConfiguration.m_maximumSlots;
  309. }
  310. const AZStd::string& SlotDefinition::GetExtensionLabel() const
  311. {
  312. return m_extendableSlotConfiguration.m_addButtonLabel;
  313. }
  314. const AZStd::string& SlotDefinition::GetExtensionTooltip() const
  315. {
  316. return m_extendableSlotConfiguration.m_addButtonTooltip;
  317. }
  318. /////////////////////////////////////////////////////////
  319. // Slot
  320. void Slot::Reflect(AZ::ReflectContext* context)
  321. {
  322. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  323. {
  324. serializeContext->Class<Slot>()
  325. ->Version(1)
  326. ->Field("m_value", &Slot::m_value)
  327. ->Field("m_subId", &Slot::m_subId)
  328. ;
  329. }
  330. }
  331. Slot::Slot(GraphPtr graph, SlotDefinitionPtr slotDefinition, SlotSubId subId)
  332. : GraphElement(graph)
  333. , m_slotDefinition(slotDefinition)
  334. , m_subId(subId)
  335. {
  336. // The m_value must be initialized with an object of the appropriate type, or GetValue() will fail the first time its called.
  337. SetValue(m_slotDefinition->GetDefaultValue());
  338. }
  339. void Slot::PostLoadSetup(GraphPtr graph, SlotDefinitionPtr slotDefinition)
  340. {
  341. AZ_Assert(nullptr == GetGraph(), "This slot is not freshly loaded");
  342. m_graph = graph;
  343. m_slotDefinition = slotDefinition;
  344. ClearCachedData();
  345. if (SupportsValues())
  346. {
  347. AZ_Error(
  348. GetGraph()->GetSystemName(),
  349. GetDataType(),
  350. "Possible data corruption. Slot [%s] does not match any supported data type.",
  351. GetDisplayName().c_str());
  352. }
  353. }
  354. NodePtr Slot::GetParentNode() const
  355. {
  356. AZStd::scoped_lock lock(m_parentNodeMutex);
  357. if (m_parentNodeDirty)
  358. {
  359. m_parentNodeDirty = false;
  360. for (auto nodePair : GetGraph()->GetNodes())
  361. {
  362. if (nodePair.second->Contains(shared_from_this()))
  363. {
  364. m_parentNode = nodePair.second;
  365. return m_parentNode;
  366. }
  367. }
  368. }
  369. return m_parentNode;
  370. }
  371. AZStd::any Slot::GetValue() const
  372. {
  373. return !m_value.empty() ? m_value : GetDefaultValue();
  374. }
  375. const Slot::ConnectionList& Slot::GetConnections() const
  376. {
  377. AZStd::scoped_lock lock(m_connectionsMutex);
  378. if (m_connectionsDirty)
  379. {
  380. m_connectionsDirty = false;
  381. m_connections.clear();
  382. m_connections.reserve(GetGraph()->GetConnectionCount());
  383. for (const auto& connection : GetGraph()->GetConnections())
  384. {
  385. const auto& sourceSlot = connection->GetSourceSlot();
  386. const auto& targetSlot = connection->GetTargetSlot();
  387. if (targetSlot.get() == this || sourceSlot.get() == this)
  388. {
  389. m_connections.emplace_back(connection);
  390. }
  391. }
  392. }
  393. return m_connections;
  394. }
  395. SlotDefinitionPtr Slot::GetDefinition() const
  396. {
  397. return m_slotDefinition;
  398. }
  399. bool Slot::Is(SlotDirection slotDirection, SlotType slotType) const
  400. {
  401. return m_slotDefinition->Is(slotDirection, slotType);
  402. }
  403. SlotDirection Slot::GetSlotDirection() const
  404. {
  405. return m_slotDefinition->GetSlotDirection();
  406. }
  407. SlotType Slot::GetSlotType() const
  408. {
  409. return m_slotDefinition->GetSlotType();
  410. }
  411. bool Slot::SupportsValues() const
  412. {
  413. return m_slotDefinition->SupportsValues();
  414. }
  415. bool Slot::SupportsDataTypes() const
  416. {
  417. return m_slotDefinition->SupportsDataTypes();
  418. }
  419. bool Slot::SupportsConnections() const
  420. {
  421. return m_slotDefinition->SupportsConnections();
  422. }
  423. bool Slot::SupportsExtendability() const
  424. {
  425. return m_slotDefinition->SupportsExtendability();
  426. }
  427. bool Slot::IsVisibleOnNode() const
  428. {
  429. return m_slotDefinition->IsVisibleOnNode();
  430. }
  431. bool Slot::IsEditableOnNode() const
  432. {
  433. return m_slotDefinition->IsEditableOnNode();
  434. }
  435. const SlotName& Slot::GetName() const
  436. {
  437. return m_slotDefinition->GetName();
  438. }
  439. const AZStd::string& Slot::GetDisplayName() const
  440. {
  441. return m_slotDefinition->GetDisplayName();
  442. }
  443. const AZStd::string& Slot::GetDescription() const
  444. {
  445. return m_slotDefinition->GetDescription();
  446. }
  447. const AZStd::vector<AZStd::string>& Slot::GetEnumValues() const
  448. {
  449. return m_slotDefinition->GetEnumValues();
  450. }
  451. AZStd::any Slot::GetDefaultValue() const
  452. {
  453. return m_slotDefinition->GetDefaultValue();
  454. }
  455. const DataTypeList& Slot::GetSupportedDataTypes() const
  456. {
  457. return m_slotDefinition->GetSupportedDataTypes();
  458. }
  459. bool Slot::IsSupportedDataType(DataTypePtr dataType) const
  460. {
  461. for (DataTypePtr supportedDataType : GetSupportedDataTypes())
  462. {
  463. if (supportedDataType == dataType)
  464. {
  465. return true;
  466. }
  467. }
  468. return false;
  469. }
  470. const int Slot::GetMinimumSlots() const
  471. {
  472. return m_slotDefinition->GetMinimumSlots();
  473. }
  474. const int Slot::GetMaximumSlots() const
  475. {
  476. return m_slotDefinition->GetMaximumSlots();
  477. }
  478. SlotId Slot::GetSlotId() const
  479. {
  480. return SlotId(GetName(), m_subId);
  481. }
  482. SlotSubId Slot::GetSlotSubId() const
  483. {
  484. return m_subId;
  485. }
  486. DataTypePtr Slot::GetDataType() const
  487. {
  488. // Because some slots support multiple data types search for the one corresponding to the value
  489. return GetDataTypeForValue(GetValue());
  490. }
  491. DataTypePtr Slot::GetDefaultDataType() const
  492. {
  493. return GetDataTypeForValue(GetDefaultValue());
  494. }
  495. void Slot::SetValue(const AZStd::any& value)
  496. {
  497. if (SupportsValues())
  498. {
  499. #if defined(AZ_ENABLE_TRACING)
  500. DataTypePtr dataTypeRequested = GetDataTypeForValue(value);
  501. AssertWithTypeInfo(IsSupportedDataType(dataTypeRequested), dataTypeRequested, "Slot::SetValue Requested with the wrong type");
  502. #endif
  503. m_value = value;
  504. }
  505. }
  506. #if defined(AZ_ENABLE_TRACING)
  507. void Slot::AssertWithTypeInfo(bool expression, DataTypePtr dataTypeRequested, const char* message) const
  508. {
  509. DataTypePtr dataType = GetDataType();
  510. AZ_Assert(expression, "%s Slot %s (Current DataType=['%s', '%s', %s]. Requested DataType=['%s', '%s', %s]). Current Value TypeId=%s.",
  511. message,
  512. GetDisplayName().c_str(),
  513. !dataType ? "nullptr" : dataType->GetDisplayName().c_str(),
  514. !dataType ? "nullptr" : dataType->GetCppName().c_str(),
  515. !dataType ? "nullptr" : dataType->GetTypeUuidString().c_str(),
  516. !dataTypeRequested ? "nullptr" : dataTypeRequested->GetDisplayName().c_str(),
  517. !dataTypeRequested ? "nullptr" : dataTypeRequested->GetCppName().c_str(),
  518. !dataTypeRequested ? "nullptr" : dataTypeRequested->GetTypeUuidString().c_str(),
  519. GetValue().type().ToString<AZStd::string>().c_str()
  520. );
  521. }
  522. #endif // AZ_ENABLE_TRACING
  523. DataTypePtr Slot::GetDataTypeForTypeId(const AZ::Uuid& typeId) const
  524. {
  525. // Search for and return the first data type that supports the input type ID
  526. for (DataTypePtr dataType : GetSupportedDataTypes())
  527. {
  528. // If this slot does not support input values but has registered data types then the first data type will be returned.
  529. if (!SupportsDataTypes() || dataType->IsSupportedType(typeId))
  530. {
  531. return dataType;
  532. }
  533. }
  534. return {};
  535. }
  536. DataTypePtr Slot::GetDataTypeForValue(const AZStd::any& value) const
  537. {
  538. // Search for and return the first data type that supports the input value
  539. for (DataTypePtr dataType : GetSupportedDataTypes())
  540. {
  541. // If this slot does not support input values but has registered data types then the first data type will be returned.
  542. if (!SupportsValues() || dataType->IsSupportedValue(value))
  543. {
  544. return dataType;
  545. }
  546. }
  547. return {};
  548. }
  549. void Slot::ClearCachedData()
  550. {
  551. {
  552. AZStd::scoped_lock lock(m_parentNodeMutex);
  553. m_parentNodeDirty = true;
  554. m_parentNode = {};
  555. }
  556. {
  557. AZStd::scoped_lock lock(m_connectionsMutex);
  558. m_connectionsDirty = true;
  559. m_connections.clear();
  560. }
  561. }
  562. } // namespace GraphModel