SceneGraph.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  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 <AzCore/Casting/numeric_cast.h>
  9. #include <AzCore/Serialization/SerializeContext.h>
  10. #include <AzCore/RTTI/BehaviorContext.h>
  11. #include <AzFramework/StringFunc/StringFunc.h>
  12. #include <SceneAPI/SceneCore/Containers/SceneGraph.h>
  13. #include <SceneAPI/SceneCore/Containers/GraphObjectProxy.h>
  14. namespace AZ
  15. {
  16. namespace SceneAPI
  17. {
  18. namespace Containers
  19. {
  20. const SceneGraph::NodeIndex::IndexType SceneGraph::NodeIndex::INVALID_INDEX;
  21. static_assert(sizeof(SceneGraph::NodeIndex::IndexType) >= ((SceneGraph::NodeHeader::INDEX_BIT_COUNT / 8) + 1),
  22. "SceneGraph::NodeIndex is not big enough to store the parent index of a SceneGraph::NodeHeader");
  23. //
  24. // SceneGraph
  25. //
  26. SceneGraph::SceneGraph()
  27. {
  28. AddDefaultRoot();
  29. }
  30. void SceneGraph::Reflect(AZ::ReflectContext* context)
  31. {
  32. GraphObjectProxy::Reflect(context);
  33. AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
  34. if (behaviorContext)
  35. {
  36. behaviorContext->Class<SceneGraph::NodeIndex>("NodeIndex")
  37. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
  38. ->Attribute(AZ::Script::Attributes::Module, "scene.graph")
  39. ->Constructor<>()
  40. ->Constructor<const SceneGraph::NodeIndex&>()
  41. ->Method("AsNumber", &SceneGraph::NodeIndex::AsNumber)
  42. ->Method("Distance", &SceneGraph::NodeIndex::Distance)
  43. ->Method("IsValid", &SceneGraph::NodeIndex::IsValid)
  44. ->Method("Equal", &SceneGraph::NodeIndex::operator==)
  45. ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Equal)
  46. ->Method("ToString", [](const SceneGraph::NodeIndex& node) { return AZStd::string::format("%u", node.m_value); })
  47. ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)
  48. ;
  49. behaviorContext->Class<SceneGraph::Name>("SceneGraphName")
  50. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
  51. ->Attribute(AZ::Script::Attributes::Module, "scene.graph")
  52. ->Constructor()
  53. ->Method("GetPath", &SceneGraph::Name::GetPath)
  54. ->Method("GetName", &SceneGraph::Name::GetName)
  55. ->Method("ToString", [](const SceneGraph::Name& self){ return self.GetName(); })
  56. ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)
  57. ;
  58. behaviorContext->Class<SceneGraph>()
  59. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
  60. ->Attribute(AZ::Script::Attributes::Module, "scene.graph")
  61. // static methods
  62. ->Method("IsValidName", [](const char* name) { return SceneGraph::IsValidName(name); })
  63. ->Method("GetNodeSeperationCharacter", &SceneGraph::GetNodeSeperationCharacter)
  64. // instance methods
  65. ->Method("GetNodeName", &SceneGraph::GetNodeName)
  66. ->Method("GetRoot", &SceneGraph::GetRoot)
  67. ->Method("HasNodeContent", &SceneGraph::HasNodeContent)
  68. ->Method("HasNodeSibling", &SceneGraph::HasNodeSibling)
  69. ->Method("HasNodeChild", &SceneGraph::HasNodeChild)
  70. ->Method("HasNodeParent", &SceneGraph::HasNodeParent)
  71. ->Method("IsNodeEndPoint", &SceneGraph::IsNodeEndPoint)
  72. ->Method("GetNodeParent", [](const SceneGraph& self, NodeIndex node) { return self.GetNodeParent(node); })
  73. ->Method("GetNodeSibling", [](const SceneGraph& self, NodeIndex node) { return self.GetNodeSibling(node); })
  74. ->Method("GetNodeChild", [](const SceneGraph& self, NodeIndex node) { return self.GetNodeChild(node); })
  75. ->Method("GetNodeCount", &SceneGraph::GetNodeCount)
  76. ->Method("FindWithPath", [](const SceneGraph& self, const AZStd::string& path)
  77. {
  78. return self.Find(path);
  79. })
  80. ->Method("FindWithRootAndPath", [](const SceneGraph& self, NodeIndex root, const AZStd::string& path)
  81. {
  82. return self.Find(root, path);
  83. })
  84. ->Method("GetNodeContent", [](const SceneGraph& self, NodeIndex node) -> GraphObjectProxy*
  85. {
  86. auto graphObject = self.GetNodeContent(node);
  87. if (graphObject)
  88. {
  89. GraphObjectProxy* proxy = aznew GraphObjectProxy(graphObject);
  90. return proxy;
  91. }
  92. return aznew GraphObjectProxy(nullptr);
  93. });
  94. }
  95. }
  96. SceneGraph::NodeIndex SceneGraph::Find(const char* path) const
  97. {
  98. auto location = FindNameLookupIterator(path);
  99. return NodeIndex(location != m_nameLookup.end() ? (*location).second : NodeIndex::INVALID_INDEX);
  100. }
  101. SceneGraph::NodeIndex SceneGraph::Find(NodeIndex root, const char* name) const
  102. {
  103. if (root.m_value < m_names.size())
  104. {
  105. AZStd::string fullname = CombineName(m_names[root.m_value].GetPath(), name);
  106. return Find(fullname);
  107. }
  108. return NodeIndex();
  109. }
  110. const SceneGraph::Name& SceneGraph::GetNodeName(NodeIndex node) const
  111. {
  112. if (node.m_value < m_names.size())
  113. {
  114. return m_names[node.m_value];
  115. }
  116. else
  117. {
  118. static Name invalidNodeName(AZStd::string("<Invalid>"), 0);
  119. return invalidNodeName;
  120. }
  121. }
  122. SceneGraph::NodeIndex SceneGraph::AddChild(NodeIndex parent, const char* name)
  123. {
  124. return AddChild(parent, name, AZStd::shared_ptr<DataTypes::IGraphObject>(nullptr));
  125. }
  126. SceneGraph::NodeIndex SceneGraph::AddChild(NodeIndex parent, const char* name, const AZStd::shared_ptr<DataTypes::IGraphObject>& content)
  127. {
  128. return AddChild(parent, name, AZStd::shared_ptr<DataTypes::IGraphObject>(content));
  129. }
  130. SceneGraph::NodeIndex SceneGraph::AddChild(NodeIndex parent, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
  131. {
  132. if (parent.m_value < m_hierarchy.size())
  133. {
  134. NodeHeader& parentNode = m_hierarchy[parent.m_value];
  135. if (parentNode.HasChild())
  136. {
  137. return AddSibling(NodeIndex(parentNode.m_childIndex), name, AZStd::move(content));
  138. }
  139. else
  140. {
  141. return NodeIndex(AppendChild(parent.m_value, name, AZStd::move(content)));
  142. }
  143. }
  144. return NodeIndex();
  145. }
  146. SceneGraph::NodeIndex SceneGraph::AddSibling(NodeIndex sibling, const char* name)
  147. {
  148. return AddSibling(sibling, name, AZStd::shared_ptr<DataTypes::IGraphObject>(nullptr));
  149. }
  150. SceneGraph::NodeIndex SceneGraph::AddSibling(NodeIndex sibling, const char* name, const AZStd::shared_ptr<DataTypes::IGraphObject>& content)
  151. {
  152. return AddSibling(sibling, name, AZStd::shared_ptr<DataTypes::IGraphObject>(content));
  153. }
  154. SceneGraph::NodeIndex SceneGraph::AddSibling(NodeIndex sibling, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
  155. {
  156. if (sibling.m_value < m_hierarchy.size())
  157. {
  158. NodeIndex::IndexType siblingIndex = sibling.m_value;
  159. while (m_hierarchy[siblingIndex].HasSibling())
  160. {
  161. siblingIndex = m_hierarchy[siblingIndex].m_siblingIndex;
  162. }
  163. return NodeIndex(AppendSibling(siblingIndex, name, AZStd::move(content)));
  164. }
  165. return NodeIndex();
  166. }
  167. bool SceneGraph::SetContent(NodeIndex node, const AZStd::shared_ptr<DataTypes::IGraphObject>& content)
  168. {
  169. if (node.m_value < m_content.size())
  170. {
  171. m_content[node.m_value] = content;
  172. return true;
  173. }
  174. return false;
  175. }
  176. bool SceneGraph::SetContent(NodeIndex node, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
  177. {
  178. if (node.m_value < m_content.size())
  179. {
  180. m_content[node.m_value] = AZStd::move(content);
  181. return true;
  182. }
  183. return false;
  184. }
  185. bool SceneGraph::MakeEndPoint(NodeIndex node)
  186. {
  187. if (node.m_value < m_hierarchy.size())
  188. {
  189. m_hierarchy[node.m_value].m_isEndPoint = 1;
  190. return true;
  191. }
  192. return false;
  193. }
  194. void SceneGraph::Clear()
  195. {
  196. m_nameLookup.clear();
  197. m_hierarchy.clear();
  198. m_names.clear();
  199. m_content.clear();
  200. AddDefaultRoot();
  201. }
  202. bool SceneGraph::IsValidName(const char* name)
  203. {
  204. if (!name)
  205. {
  206. return false;
  207. }
  208. if (name[0] == 0)
  209. {
  210. return false;
  211. }
  212. const char* current = name;
  213. while (*current)
  214. {
  215. if (*current++ == s_nodeSeperationCharacter)
  216. {
  217. return false;
  218. }
  219. }
  220. return true;
  221. }
  222. char SceneGraph::GetNodeSeperationCharacter()
  223. {
  224. return s_nodeSeperationCharacter;
  225. }
  226. SceneGraph::NodeIndex::IndexType SceneGraph::AppendChild(NodeIndex::IndexType parent, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
  227. {
  228. if (parent < m_hierarchy.size())
  229. {
  230. NodeHeader parentNode = m_hierarchy[parent];
  231. AZ_Assert(!parentNode.HasChild(), "Child '%s' couldn't be added as the target parent already contains a child.", name);
  232. AZ_Assert(!parentNode.IsEndPoint(), "Attempting to add a child '%s' to node which is marked as an end point.", name);
  233. if (!parentNode.HasChild() && !parentNode.IsEndPoint())
  234. {
  235. NodeIndex::IndexType nodeIndex = AppendNode(parent, name, AZStd::move(content));
  236. m_hierarchy[parent].m_childIndex = nodeIndex;
  237. return nodeIndex;
  238. }
  239. }
  240. return NodeIndex::INVALID_INDEX;
  241. }
  242. SceneGraph::NodeIndex::IndexType SceneGraph::AppendSibling(NodeIndex::IndexType sibling, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
  243. {
  244. if (sibling < m_hierarchy.size())
  245. {
  246. NodeHeader siblingNode = m_hierarchy[sibling];
  247. AZ_Assert(!siblingNode.HasSibling(), "Sibling '%s' couldn't be added as the target node already contains a sibling.", name);
  248. if (!siblingNode.HasSibling())
  249. {
  250. NodeIndex::IndexType nodeIndex = AppendNode(siblingNode.m_parentIndex, name, AZStd::move(content));
  251. m_hierarchy[sibling].m_siblingIndex = nodeIndex;
  252. return nodeIndex;
  253. }
  254. }
  255. return NodeIndex::INVALID_INDEX;
  256. }
  257. SceneGraph::NodeIndex::IndexType SceneGraph::AppendNode(NodeIndex::IndexType parentIndex, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
  258. {
  259. NodeIndex::IndexType nodeIndex = aznumeric_caster(m_hierarchy.size());
  260. NodeHeader node;
  261. node.m_parentIndex = parentIndex;
  262. m_hierarchy.push_back(node);
  263. AZ_Assert(IsValidName(name), "Name '%s' for SceneGraph sibling contains invalid characters", name);
  264. AZStd::string fullName;
  265. size_t nameOffset;
  266. if (parentIndex != NodeHeader::INVALID_INDEX)
  267. {
  268. const Name& parentName = m_names[parentIndex];
  269. fullName = CombineName(parentName.GetPath(), name);
  270. nameOffset = parentName.GetPathLength() + (parentName.GetPathLength() != 0 ? 1 : 0);
  271. }
  272. else
  273. {
  274. fullName = name;
  275. nameOffset = 0;
  276. }
  277. StringHash fullNameHash = StringHasher()(fullName);
  278. AZ_Assert(FindNameLookupIterator(fullNameHash, fullName.c_str()) == m_nameLookup.end(), "Duplicate name found in SceneGraph: %s", fullName.c_str());
  279. m_nameLookup.insert(NameLookup::value_type(fullNameHash, nodeIndex));
  280. m_names.emplace_back(AZStd::move(fullName), nameOffset);
  281. AZ_Assert(m_hierarchy.size() == m_names.size(),
  282. "Hierarchy and name lists in SceneGraph have gone out of sync. (%i vs. %i)", m_hierarchy.size(), m_names.size());
  283. m_content.push_back(AZStd::move(content));
  284. AZ_Assert(m_hierarchy.size() == m_content.size(),
  285. "Hierarchy and data lists in SceneGraph have gone out of sync. (%i vs. %i)", m_hierarchy.size(), m_content.size());
  286. return nodeIndex;
  287. }
  288. SceneGraph::NameLookup::const_iterator SceneGraph::FindNameLookupIterator(const char* name) const
  289. {
  290. StringHash hash = StringHasher()(name);
  291. return FindNameLookupIterator(hash, name);
  292. }
  293. SceneGraph::NameLookup::const_iterator SceneGraph::FindNameLookupIterator(StringHash hash, const char* name) const
  294. {
  295. auto range = m_nameLookup.equal_range(hash);
  296. // Always check the name, even if there's only one entry as the hash can be a clash with
  297. // the single entry.
  298. for (auto it = range.first; it != range.second; ++it)
  299. {
  300. if (AzFramework::StringFunc::Equal(m_names[it->second].GetPath(), name, true))
  301. {
  302. return it;
  303. }
  304. }
  305. return m_nameLookup.end();
  306. }
  307. AZStd::string SceneGraph::CombineName(const char* path, const char* name) const
  308. {
  309. AZStd::string result = path;
  310. if (result.length() > 0)
  311. {
  312. result += s_nodeSeperationCharacter;
  313. }
  314. result += name;
  315. return result;
  316. }
  317. void SceneGraph::AddDefaultRoot()
  318. {
  319. AZ_Assert(m_hierarchy.size() == 0, "Adding a default root node to a SceneGraph with content.");
  320. m_hierarchy.push_back(NodeHeader());
  321. m_nameLookup.insert(NameLookup::value_type(StringHasher()(""), 0));
  322. m_names.emplace_back("", 0);
  323. m_content.emplace_back(nullptr);
  324. }
  325. } // Containers
  326. } // SceneAPI
  327. } // AZ