Slot.cpp 18 KB

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