3
0

Graph.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  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/std/smart_ptr/make_shared.h>
  10. #include <AzCore/RTTI/BehaviorContext.h>
  11. #include <AzCore/Serialization/EditContext.h>
  12. #include <AzCore/Serialization/SerializeContext.h>
  13. // Graph Model
  14. #include <GraphModel/Model/Graph.h>
  15. #include <GraphModel/Model/GraphContext.h>
  16. #include <GraphModel/Model/Node.h>
  17. #include <GraphModel/Model/Slot.h>
  18. #include <GraphModel/Model/Connection.h>
  19. namespace GraphModel
  20. {
  21. void Graph::Reflect(AZ::ReflectContext* context)
  22. {
  23. if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  24. {
  25. serializeContext->Class<Graph>()
  26. ->Version(2)
  27. ->Field("m_nodes", &Graph::m_nodes)
  28. ->Field("m_connections", &Graph::m_connections)
  29. ->Field("m_uiMetadata", &Graph::m_uiMetadata)
  30. ->Field("m_nodeWrappings", &Graph::m_nodeWrappings)
  31. ;
  32. }
  33. if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
  34. {
  35. behaviorContext->Class<Graph>("GraphModelGraph")
  36. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  37. ->Attribute(AZ::Script::Attributes::Category, "Editor")
  38. ->Attribute(AZ::Script::Attributes::Module, "editor.graph")
  39. ->Method("GetContext", &Graph::GetContext)
  40. ->Method("GetSystemName", &Graph::GetSystemName)
  41. ->Method("AddNode", &Graph::AddNode)
  42. ->Method("RemoveNode", &Graph::RemoveNode)
  43. ->Method("WrapNode", &Graph::WrapNode)
  44. ->Method("UnwrapNode", &Graph::UnwrapNode)
  45. ->Method("IsNodeWrapped", &Graph::IsNodeWrapped)
  46. ->Method("GetNodeWrappings", &Graph::GetNodeWrappings)
  47. ->Method("GetNode", &Graph::GetNode)
  48. ->Method("GetNodes", static_cast<const Graph::NodeMap& (Graph::*)()>(&Graph::GetNodes))
  49. ->Method("GetNodeCount", &Graph::GetNodeCount)
  50. ->Method("AddConnection", &Graph::AddConnection)
  51. ->Method("RemoveConnection", &Graph::RemoveConnection)
  52. ->Method("GetConnections", &Graph::GetConnections)
  53. ->Method("GetConnectionCount", &Graph::GetConnectionCount)
  54. ->Method("FindSlot", &Graph::FindSlot)
  55. ->Method("ClearCachedData", &Graph::ClearCachedData)
  56. ->Method("Contains", &Graph::Contains)
  57. ->Method("FindConnection", &Graph::FindConnection)
  58. ;
  59. }
  60. }
  61. Graph::Graph(GraphContextPtr graphContext)
  62. : m_graphContext(graphContext)
  63. {
  64. }
  65. void Graph::PostLoadSetup(GraphContextPtr graphContext)
  66. {
  67. AZ_Assert(m_nextNodeId == 1, "This graph has been set up before");
  68. m_graphContext = graphContext;
  69. for (auto& [nodeId, node] : m_nodes)
  70. {
  71. node->PostLoadSetup(shared_from_this(), nodeId);
  72. // Find the highest NodeId in the graph so we can figure out what the next one should be
  73. m_nextNodeId = AZ::GetMax(m_nextNodeId, nodeId + 1);
  74. }
  75. for (auto& connection : m_connections)
  76. {
  77. connection->PostLoadSetup(shared_from_this());
  78. }
  79. AZStd::erase_if(m_connections, [](const auto& connection){
  80. return !connection || !connection->GetSourceSlot() || !connection->GetTargetSlot();
  81. });
  82. }
  83. NodeId Graph::PostLoadSetup(NodePtr node)
  84. {
  85. node->m_graph = shared_from_this();
  86. NodeId nodeId = AddNode(node);
  87. node->PostLoadSetup();
  88. return nodeId;
  89. }
  90. GraphContextPtr Graph::GetContext() const
  91. {
  92. AZ_Assert(m_graphContext, "Graph::m_graphContext is not set");
  93. return m_graphContext;
  94. }
  95. const char* Graph::GetSystemName() const
  96. {
  97. return GetContext()->GetSystemName();
  98. }
  99. ConnectionPtr Graph::FindConnection(ConstSlotPtr sourceSlot, ConstSlotPtr targetSlot)
  100. {
  101. if (sourceSlot && targetSlot)
  102. {
  103. for (ConnectionPtr connection : m_connections)
  104. {
  105. if (connection->GetSourceSlot() == sourceSlot && connection->GetTargetSlot() == targetSlot)
  106. {
  107. return connection;
  108. }
  109. }
  110. }
  111. return nullptr;
  112. }
  113. bool Graph::Contains(SlotPtr slot) const
  114. {
  115. if (slot)
  116. {
  117. for (const auto& nodePair : m_nodes)
  118. {
  119. if (nodePair.second->Contains(slot))
  120. {
  121. return true;
  122. }
  123. }
  124. }
  125. return false;
  126. }
  127. NodePtr Graph::GetNode(NodeId nodeId)
  128. {
  129. auto nodeIter = m_nodes.find(nodeId);
  130. return nodeIter != m_nodes.end() ? nodeIter->second : nullptr;
  131. }
  132. const Graph::NodeMap& Graph::GetNodes()
  133. {
  134. return m_nodes;
  135. }
  136. Graph::ConstNodeMap Graph::GetNodes() const
  137. {
  138. return Graph::ConstNodeMap(m_nodes.begin(), m_nodes.end());
  139. }
  140. size_t Graph::GetNodeCount() const
  141. {
  142. return m_nodes.size();
  143. }
  144. NodeId Graph::AddNode(NodePtr node)
  145. {
  146. AZ_Assert(Node::INVALID_NODE_ID == node->GetId(), "It appears this node already exists in a Graph");
  147. AZ_Assert(this == node->GetGraph().get(), "The Node was not created for this Graph");
  148. node->m_id = m_nextNodeId++;
  149. m_nodes.insert(AZStd::make_pair(node->m_id, node));
  150. ClearCachedData();
  151. return node->m_id;
  152. }
  153. bool Graph::RemoveNode(ConstNodePtr node)
  154. {
  155. // First delete any connections that are attached to the node.
  156. AZStd::erase_if(m_connections, [&](const auto& connection){
  157. return !connection || !connection->GetSourceSlot() || !connection->GetTargetSlot() || connection->GetSourceNode() == node || connection->GetTargetNode() == node;
  158. });
  159. // Also, remove any node wrapping stored for this node
  160. UnwrapNode(node);
  161. ClearCachedData();
  162. return m_nodes.erase(node->GetId()) > 0;
  163. }
  164. void Graph::WrapNode(NodePtr wrapperNode, NodePtr node, AZ::u32 layoutOrder)
  165. {
  166. AZ_Assert(m_nodes.find(wrapperNode->GetId()) != m_nodes.end(), "The wrapperNode must be in the graph before having a node wrapped on it");
  167. AZ_Assert(m_nodes.find(node->GetId()) != m_nodes.end(), "The node must be in the graph before being wrapped");
  168. AZ_Assert(wrapperNode->GetNodeType() == NodeType::WrapperNode, "The node containing the wrapped node must be of node type WrapperNode");
  169. AZ_Assert(node->GetNodeType() != NodeType::WrapperNode, "Nested WrapperNodes are not allowed");
  170. AZ_Assert(m_nodeWrappings.find(node->GetId()) == m_nodeWrappings.end(), "The specified node is already wrapped on another WrapperNode");
  171. m_nodeWrappings[node->GetId()] = AZStd::make_pair(wrapperNode->GetId(), layoutOrder);
  172. ClearCachedData();
  173. }
  174. void Graph::UnwrapNode(ConstNodePtr node)
  175. {
  176. ClearCachedData();
  177. m_nodeWrappings.erase(node->GetId());
  178. }
  179. bool Graph::IsNodeWrapped(NodePtr node) const
  180. {
  181. return m_nodeWrappings.contains(node->GetId());
  182. }
  183. const Graph::NodeWrappingMap& Graph::GetNodeWrappings()
  184. {
  185. return m_nodeWrappings;
  186. }
  187. const Graph::ConnectionList& Graph::GetConnections()
  188. {
  189. return m_connections;
  190. }
  191. size_t Graph::GetConnectionCount() const
  192. {
  193. return m_connections.size();
  194. }
  195. ConnectionPtr Graph::AddConnection(SlotPtr sourceSlot, SlotPtr targetSlot)
  196. {
  197. if (ConnectionPtr existingConnection = FindConnection(sourceSlot, targetSlot))
  198. {
  199. return existingConnection;
  200. }
  201. if (Contains(sourceSlot) && Contains(targetSlot))
  202. {
  203. m_connections.push_back(AZStd::make_shared<Connection>(shared_from_this(), sourceSlot, targetSlot));
  204. ClearCachedData();
  205. return m_connections.back();
  206. }
  207. AZ_Error(GetSystemName(), false, "Tried to add a connection between slots that don't exist in this Graph.");
  208. return nullptr;
  209. }
  210. bool Graph::RemoveConnection(ConstConnectionPtr connection)
  211. {
  212. if (AZStd::erase_if(m_connections, [&](const auto& existingConnection) {
  213. return existingConnection == connection ||
  214. (existingConnection && connection &&
  215. existingConnection->GetSourceSlot() == connection->GetSourceSlot() &&
  216. existingConnection->GetTargetSlot() == connection->GetTargetSlot());
  217. }) > 0)
  218. {
  219. ClearCachedData();
  220. return true;
  221. }
  222. return false;
  223. }
  224. AZStd::shared_ptr<Slot> Graph::FindSlot(const Endpoint& endpoint)
  225. {
  226. auto nodeIter = m_nodes.find(endpoint.first);
  227. return nodeIter != m_nodes.end() ? nodeIter->second->GetSlot(endpoint.second) : AZStd::shared_ptr<Slot>{};
  228. }
  229. void Graph::ClearCachedData()
  230. {
  231. for (auto& nodePair : m_nodes)
  232. {
  233. nodePair.second->ClearCachedData();
  234. }
  235. }
  236. void Graph::SetUiMetadata(const GraphModelIntegration::GraphCanvasMetadata& uiMetadata)
  237. {
  238. m_uiMetadata = uiMetadata;
  239. }
  240. const GraphModelIntegration::GraphCanvasMetadata& Graph::GetUiMetadata() const
  241. {
  242. return m_uiMetadata;
  243. }
  244. GraphModelIntegration::GraphCanvasMetadata& Graph::GetUiMetadata()
  245. {
  246. return m_uiMetadata;
  247. }
  248. } // namespace GraphModel