SceneGraph.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  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. return GraphObjectProxy(graphObject);
  90. }
  91. return GraphObjectProxy(nullptr);
  92. });
  93. }
  94. }
  95. SceneGraph::NodeIndex SceneGraph::Find(const char* path) const
  96. {
  97. auto location = FindNameLookupIterator(path);
  98. return NodeIndex(location != m_nameLookup.end() ? (*location).second : NodeIndex::INVALID_INDEX);
  99. }
  100. SceneGraph::NodeIndex SceneGraph::Find(NodeIndex root, const char* name) const
  101. {
  102. if (root.m_value < m_names.size())
  103. {
  104. AZStd::string fullname = CombineName(m_names[root.m_value].GetPath(), name);
  105. return Find(fullname);
  106. }
  107. return NodeIndex();
  108. }
  109. const SceneGraph::Name& SceneGraph::GetNodeName(NodeIndex node) const
  110. {
  111. if (node.m_value < m_names.size())
  112. {
  113. return m_names[node.m_value];
  114. }
  115. else
  116. {
  117. static Name invalidNodeName(AZStd::string("<Invalid>"), 0);
  118. return invalidNodeName;
  119. }
  120. }
  121. SceneGraph::NodeIndex SceneGraph::AddChild(NodeIndex parent, const char* name)
  122. {
  123. return AddChild(parent, name, AZStd::shared_ptr<DataTypes::IGraphObject>(nullptr));
  124. }
  125. SceneGraph::NodeIndex SceneGraph::AddChild(NodeIndex parent, const char* name, const AZStd::shared_ptr<DataTypes::IGraphObject>& content)
  126. {
  127. return AddChild(parent, name, AZStd::shared_ptr<DataTypes::IGraphObject>(content));
  128. }
  129. SceneGraph::NodeIndex SceneGraph::AddChild(NodeIndex parent, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
  130. {
  131. if (parent.m_value < m_hierarchy.size())
  132. {
  133. NodeHeader& parentNode = m_hierarchy[parent.m_value];
  134. if (parentNode.HasChild())
  135. {
  136. return AddSibling(NodeIndex(parentNode.m_childIndex), name, AZStd::move(content));
  137. }
  138. else
  139. {
  140. return NodeIndex(AppendChild(parent.m_value, name, AZStd::move(content)));
  141. }
  142. }
  143. return NodeIndex();
  144. }
  145. SceneGraph::NodeIndex SceneGraph::AddSibling(NodeIndex sibling, const char* name)
  146. {
  147. return AddSibling(sibling, name, AZStd::shared_ptr<DataTypes::IGraphObject>(nullptr));
  148. }
  149. SceneGraph::NodeIndex SceneGraph::AddSibling(NodeIndex sibling, const char* name, const AZStd::shared_ptr<DataTypes::IGraphObject>& content)
  150. {
  151. return AddSibling(sibling, name, AZStd::shared_ptr<DataTypes::IGraphObject>(content));
  152. }
  153. SceneGraph::NodeIndex SceneGraph::AddSibling(NodeIndex sibling, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
  154. {
  155. if (sibling.m_value < m_hierarchy.size())
  156. {
  157. NodeIndex::IndexType siblingIndex = sibling.m_value;
  158. while (m_hierarchy[siblingIndex].HasSibling())
  159. {
  160. siblingIndex = m_hierarchy[siblingIndex].m_siblingIndex;
  161. }
  162. return NodeIndex(AppendSibling(siblingIndex, name, AZStd::move(content)));
  163. }
  164. return NodeIndex();
  165. }
  166. bool SceneGraph::SetContent(NodeIndex node, const AZStd::shared_ptr<DataTypes::IGraphObject>& content)
  167. {
  168. if (node.m_value < m_content.size())
  169. {
  170. m_content[node.m_value] = content;
  171. return true;
  172. }
  173. return false;
  174. }
  175. bool SceneGraph::SetContent(NodeIndex node, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
  176. {
  177. if (node.m_value < m_content.size())
  178. {
  179. m_content[node.m_value] = AZStd::move(content);
  180. return true;
  181. }
  182. return false;
  183. }
  184. bool SceneGraph::MakeEndPoint(NodeIndex node)
  185. {
  186. if (node.m_value < m_hierarchy.size())
  187. {
  188. m_hierarchy[node.m_value].m_isEndPoint = 1;
  189. return true;
  190. }
  191. return false;
  192. }
  193. void SceneGraph::Clear()
  194. {
  195. m_nameLookup.clear();
  196. m_hierarchy.clear();
  197. m_names.clear();
  198. m_content.clear();
  199. AddDefaultRoot();
  200. }
  201. bool SceneGraph::IsValidName(const char* name)
  202. {
  203. if (!name)
  204. {
  205. return false;
  206. }
  207. if (name[0] == 0)
  208. {
  209. return false;
  210. }
  211. const char* current = name;
  212. while (*current)
  213. {
  214. if (*current++ == s_nodeSeperationCharacter)
  215. {
  216. return false;
  217. }
  218. }
  219. return true;
  220. }
  221. char SceneGraph::GetNodeSeperationCharacter()
  222. {
  223. return s_nodeSeperationCharacter;
  224. }
  225. SceneGraph::NodeIndex::IndexType SceneGraph::AppendChild(NodeIndex::IndexType parent, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
  226. {
  227. if (parent < m_hierarchy.size())
  228. {
  229. NodeHeader parentNode = m_hierarchy[parent];
  230. AZ_Assert(!parentNode.HasChild(), "Child '%s' couldn't be added as the target parent already contains a child.", name);
  231. AZ_Assert(!parentNode.IsEndPoint(), "Attempting to add a child '%s' to node which is marked as an end point.", name);
  232. if (!parentNode.HasChild() && !parentNode.IsEndPoint())
  233. {
  234. NodeIndex::IndexType nodeIndex = AppendNode(parent, name, AZStd::move(content));
  235. m_hierarchy[parent].m_childIndex = nodeIndex;
  236. return nodeIndex;
  237. }
  238. }
  239. return NodeIndex::INVALID_INDEX;
  240. }
  241. SceneGraph::NodeIndex::IndexType SceneGraph::AppendSibling(NodeIndex::IndexType sibling, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
  242. {
  243. if (sibling < m_hierarchy.size())
  244. {
  245. NodeHeader siblingNode = m_hierarchy[sibling];
  246. AZ_Assert(!siblingNode.HasSibling(), "Sibling '%s' couldn't be added as the target node already contains a sibling.", name);
  247. if (!siblingNode.HasSibling())
  248. {
  249. NodeIndex::IndexType nodeIndex = AppendNode(siblingNode.m_parentIndex, name, AZStd::move(content));
  250. m_hierarchy[sibling].m_siblingIndex = nodeIndex;
  251. return nodeIndex;
  252. }
  253. }
  254. return NodeIndex::INVALID_INDEX;
  255. }
  256. SceneGraph::NodeIndex::IndexType SceneGraph::AppendNode(NodeIndex::IndexType parentIndex, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
  257. {
  258. const bool isValidName = IsValidName(name);
  259. AZ_Assert(isValidName,
  260. "Name '%s' for SceneGraph sibling contains invalid characters. "
  261. "This is likely due to the name containing the node separation character '%c' ",
  262. name, s_nodeSeperationCharacter);
  263. if (!isValidName)
  264. {
  265. return NodeIndex::INVALID_INDEX;
  266. }
  267. NodeIndex::IndexType nodeIndex = aznumeric_caster(m_hierarchy.size());
  268. NodeHeader node;
  269. node.m_parentIndex = parentIndex;
  270. m_hierarchy.push_back(node);
  271. AZStd::string fullName;
  272. size_t nameOffset;
  273. if (parentIndex != NodeHeader::INVALID_INDEX)
  274. {
  275. const Name& parentName = m_names[parentIndex];
  276. fullName = CombineName(parentName.GetPath(), name);
  277. nameOffset = parentName.GetPathLength() + (parentName.GetPathLength() != 0 ? 1 : 0);
  278. }
  279. else
  280. {
  281. fullName = name;
  282. nameOffset = 0;
  283. }
  284. StringHash fullNameHash = StringHasher()(fullName);
  285. AZ_Assert(FindNameLookupIterator(fullNameHash, fullName.c_str()) == m_nameLookup.end(), "Duplicate name found in SceneGraph: %s", fullName.c_str());
  286. m_nameLookup.insert(NameLookup::value_type(fullNameHash, nodeIndex));
  287. m_names.emplace_back(AZStd::move(fullName), nameOffset);
  288. AZ_Assert(m_hierarchy.size() == m_names.size(),
  289. "Hierarchy and name lists in SceneGraph have gone out of sync. (%i vs. %i)", m_hierarchy.size(), m_names.size());
  290. m_content.push_back(AZStd::move(content));
  291. AZ_Assert(m_hierarchy.size() == m_content.size(),
  292. "Hierarchy and data lists in SceneGraph have gone out of sync. (%i vs. %i)", m_hierarchy.size(), m_content.size());
  293. return nodeIndex;
  294. }
  295. SceneGraph::NameLookup::const_iterator SceneGraph::FindNameLookupIterator(const char* name) const
  296. {
  297. StringHash hash = StringHasher()(name);
  298. return FindNameLookupIterator(hash, name);
  299. }
  300. SceneGraph::NameLookup::const_iterator SceneGraph::FindNameLookupIterator(StringHash hash, const char* name) const
  301. {
  302. auto range = m_nameLookup.equal_range(hash);
  303. // Always check the name, even if there's only one entry as the hash can be a clash with
  304. // the single entry.
  305. for (auto it = range.first; it != range.second; ++it)
  306. {
  307. if (AzFramework::StringFunc::Equal(m_names[it->second].GetPath(), name, true))
  308. {
  309. return it;
  310. }
  311. }
  312. return m_nameLookup.end();
  313. }
  314. AZStd::string SceneGraph::CombineName(const char* path, const char* name) const
  315. {
  316. AZStd::string result = path;
  317. if (result.length() > 0)
  318. {
  319. result += s_nodeSeperationCharacter;
  320. }
  321. result += name;
  322. return result;
  323. }
  324. void SceneGraph::AddDefaultRoot()
  325. {
  326. AZ_Assert(m_hierarchy.size() == 0, "Adding a default root node to a SceneGraph with content.");
  327. m_hierarchy.push_back(NodeHeader());
  328. m_nameLookup.insert(NameLookup::value_type(StringHasher()(""), 0));
  329. m_names.emplace_back("", 0);
  330. m_content.emplace_back(nullptr);
  331. }
  332. } // Containers
  333. } // SceneAPI
  334. } // AZ