123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <AzCore/Casting/numeric_cast.h>
- #include <AzCore/Serialization/SerializeContext.h>
- #include <AzCore/RTTI/BehaviorContext.h>
- #include <AzFramework/StringFunc/StringFunc.h>
- #include <SceneAPI/SceneCore/Containers/SceneGraph.h>
- #include <SceneAPI/SceneCore/Containers/GraphObjectProxy.h>
- namespace AZ
- {
- namespace SceneAPI
- {
- namespace Containers
- {
- const SceneGraph::NodeIndex::IndexType SceneGraph::NodeIndex::INVALID_INDEX;
- static_assert(sizeof(SceneGraph::NodeIndex::IndexType) >= ((SceneGraph::NodeHeader::INDEX_BIT_COUNT / 8) + 1),
- "SceneGraph::NodeIndex is not big enough to store the parent index of a SceneGraph::NodeHeader");
- //
- // SceneGraph
- //
- SceneGraph::SceneGraph()
- {
- AddDefaultRoot();
- }
- void SceneGraph::Reflect(AZ::ReflectContext* context)
- {
- GraphObjectProxy::Reflect(context);
- AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
- if (behaviorContext)
- {
- behaviorContext->Class<SceneGraph::NodeIndex>("NodeIndex")
- ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
- ->Attribute(AZ::Script::Attributes::Module, "scene.graph")
- ->Constructor<>()
- ->Constructor<const SceneGraph::NodeIndex&>()
- ->Method("AsNumber", &SceneGraph::NodeIndex::AsNumber)
- ->Method("Distance", &SceneGraph::NodeIndex::Distance)
- ->Method("IsValid", &SceneGraph::NodeIndex::IsValid)
- ->Method("Equal", &SceneGraph::NodeIndex::operator==)
- ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::Equal)
- ->Method("ToString", [](const SceneGraph::NodeIndex& node) { return AZStd::string::format("%u", node.m_value); })
- ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)
- ;
- behaviorContext->Class<SceneGraph::Name>("SceneGraphName")
- ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
- ->Attribute(AZ::Script::Attributes::Module, "scene.graph")
- ->Constructor()
- ->Method("GetPath", &SceneGraph::Name::GetPath)
- ->Method("GetName", &SceneGraph::Name::GetName)
- ->Method("ToString", [](const SceneGraph::Name& self){ return self.GetName(); })
- ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)
- ;
- behaviorContext->Class<SceneGraph>()
- ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
- ->Attribute(AZ::Script::Attributes::Module, "scene.graph")
- // static methods
- ->Method("IsValidName", [](const char* name) { return SceneGraph::IsValidName(name); })
- ->Method("GetNodeSeperationCharacter", &SceneGraph::GetNodeSeperationCharacter)
- // instance methods
- ->Method("GetNodeName", &SceneGraph::GetNodeName)
- ->Method("GetRoot", &SceneGraph::GetRoot)
- ->Method("HasNodeContent", &SceneGraph::HasNodeContent)
- ->Method("HasNodeSibling", &SceneGraph::HasNodeSibling)
- ->Method("HasNodeChild", &SceneGraph::HasNodeChild)
- ->Method("HasNodeParent", &SceneGraph::HasNodeParent)
- ->Method("IsNodeEndPoint", &SceneGraph::IsNodeEndPoint)
- ->Method("GetNodeParent", [](const SceneGraph& self, NodeIndex node) { return self.GetNodeParent(node); })
- ->Method("GetNodeSibling", [](const SceneGraph& self, NodeIndex node) { return self.GetNodeSibling(node); })
- ->Method("GetNodeChild", [](const SceneGraph& self, NodeIndex node) { return self.GetNodeChild(node); })
- ->Method("GetNodeCount", &SceneGraph::GetNodeCount)
- ->Method("FindWithPath", [](const SceneGraph& self, const AZStd::string& path)
- {
- return self.Find(path);
- })
- ->Method("FindWithRootAndPath", [](const SceneGraph& self, NodeIndex root, const AZStd::string& path)
- {
- return self.Find(root, path);
- })
- ->Method("GetNodeContent", [](const SceneGraph& self, NodeIndex node) -> GraphObjectProxy
- {
- auto graphObject = self.GetNodeContent(node);
- if (graphObject)
- {
- return GraphObjectProxy(graphObject);
- }
- return GraphObjectProxy(nullptr);
- });
- }
- }
- SceneGraph::NodeIndex SceneGraph::Find(const char* path) const
- {
- auto location = FindNameLookupIterator(path);
- return NodeIndex(location != m_nameLookup.end() ? (*location).second : NodeIndex::INVALID_INDEX);
- }
- SceneGraph::NodeIndex SceneGraph::Find(NodeIndex root, const char* name) const
- {
- if (root.m_value < m_names.size())
- {
- AZStd::string fullname = CombineName(m_names[root.m_value].GetPath(), name);
- return Find(fullname);
- }
- return NodeIndex();
- }
- const SceneGraph::Name& SceneGraph::GetNodeName(NodeIndex node) const
- {
- if (node.m_value < m_names.size())
- {
- return m_names[node.m_value];
- }
- else
- {
- static Name invalidNodeName(AZStd::string("<Invalid>"), 0);
- return invalidNodeName;
- }
- }
- SceneGraph::NodeIndex SceneGraph::AddChild(NodeIndex parent, const char* name)
- {
- return AddChild(parent, name, AZStd::shared_ptr<DataTypes::IGraphObject>(nullptr));
- }
- SceneGraph::NodeIndex SceneGraph::AddChild(NodeIndex parent, const char* name, const AZStd::shared_ptr<DataTypes::IGraphObject>& content)
- {
- return AddChild(parent, name, AZStd::shared_ptr<DataTypes::IGraphObject>(content));
- }
- SceneGraph::NodeIndex SceneGraph::AddChild(NodeIndex parent, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
- {
- if (parent.m_value < m_hierarchy.size())
- {
- NodeHeader& parentNode = m_hierarchy[parent.m_value];
- if (parentNode.HasChild())
- {
- return AddSibling(NodeIndex(parentNode.m_childIndex), name, AZStd::move(content));
- }
- else
- {
- return NodeIndex(AppendChild(parent.m_value, name, AZStd::move(content)));
- }
- }
- return NodeIndex();
- }
- SceneGraph::NodeIndex SceneGraph::AddSibling(NodeIndex sibling, const char* name)
- {
- return AddSibling(sibling, name, AZStd::shared_ptr<DataTypes::IGraphObject>(nullptr));
- }
- SceneGraph::NodeIndex SceneGraph::AddSibling(NodeIndex sibling, const char* name, const AZStd::shared_ptr<DataTypes::IGraphObject>& content)
- {
- return AddSibling(sibling, name, AZStd::shared_ptr<DataTypes::IGraphObject>(content));
- }
- SceneGraph::NodeIndex SceneGraph::AddSibling(NodeIndex sibling, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
- {
- if (sibling.m_value < m_hierarchy.size())
- {
- NodeIndex::IndexType siblingIndex = sibling.m_value;
- while (m_hierarchy[siblingIndex].HasSibling())
- {
- siblingIndex = m_hierarchy[siblingIndex].m_siblingIndex;
- }
- return NodeIndex(AppendSibling(siblingIndex, name, AZStd::move(content)));
- }
- return NodeIndex();
- }
- bool SceneGraph::SetContent(NodeIndex node, const AZStd::shared_ptr<DataTypes::IGraphObject>& content)
- {
- if (node.m_value < m_content.size())
- {
- m_content[node.m_value] = content;
- return true;
- }
- return false;
- }
- bool SceneGraph::SetContent(NodeIndex node, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
- {
- if (node.m_value < m_content.size())
- {
- m_content[node.m_value] = AZStd::move(content);
- return true;
- }
- return false;
- }
- bool SceneGraph::MakeEndPoint(NodeIndex node)
- {
- if (node.m_value < m_hierarchy.size())
- {
- m_hierarchy[node.m_value].m_isEndPoint = 1;
- return true;
- }
- return false;
- }
- void SceneGraph::Clear()
- {
- m_nameLookup.clear();
- m_hierarchy.clear();
- m_names.clear();
- m_content.clear();
- AddDefaultRoot();
- }
- bool SceneGraph::IsValidName(const char* name)
- {
- if (!name)
- {
- return false;
- }
- if (name[0] == 0)
- {
- return false;
- }
- const char* current = name;
- while (*current)
- {
- if (*current++ == s_nodeSeperationCharacter)
- {
- return false;
- }
- }
- return true;
- }
- char SceneGraph::GetNodeSeperationCharacter()
- {
- return s_nodeSeperationCharacter;
- }
- SceneGraph::NodeIndex::IndexType SceneGraph::AppendChild(NodeIndex::IndexType parent, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
- {
- if (parent < m_hierarchy.size())
- {
- NodeHeader parentNode = m_hierarchy[parent];
- AZ_Assert(!parentNode.HasChild(), "Child '%s' couldn't be added as the target parent already contains a child.", name);
- AZ_Assert(!parentNode.IsEndPoint(), "Attempting to add a child '%s' to node which is marked as an end point.", name);
- if (!parentNode.HasChild() && !parentNode.IsEndPoint())
- {
- NodeIndex::IndexType nodeIndex = AppendNode(parent, name, AZStd::move(content));
- m_hierarchy[parent].m_childIndex = nodeIndex;
- return nodeIndex;
- }
- }
- return NodeIndex::INVALID_INDEX;
- }
- SceneGraph::NodeIndex::IndexType SceneGraph::AppendSibling(NodeIndex::IndexType sibling, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
- {
- if (sibling < m_hierarchy.size())
- {
- NodeHeader siblingNode = m_hierarchy[sibling];
- AZ_Assert(!siblingNode.HasSibling(), "Sibling '%s' couldn't be added as the target node already contains a sibling.", name);
- if (!siblingNode.HasSibling())
- {
- NodeIndex::IndexType nodeIndex = AppendNode(siblingNode.m_parentIndex, name, AZStd::move(content));
- m_hierarchy[sibling].m_siblingIndex = nodeIndex;
- return nodeIndex;
- }
- }
- return NodeIndex::INVALID_INDEX;
- }
- SceneGraph::NodeIndex::IndexType SceneGraph::AppendNode(NodeIndex::IndexType parentIndex, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content)
- {
- const bool isValidName = IsValidName(name);
- AZ_Assert(isValidName,
- "Name '%s' for SceneGraph sibling contains invalid characters. "
- "This is likely due to the name containing the node separation character '%c' ",
- name, s_nodeSeperationCharacter);
- if (!isValidName)
- {
- return NodeIndex::INVALID_INDEX;
- }
- NodeIndex::IndexType nodeIndex = aznumeric_caster(m_hierarchy.size());
- NodeHeader node;
- node.m_parentIndex = parentIndex;
- m_hierarchy.push_back(node);
- AZStd::string fullName;
- size_t nameOffset;
- if (parentIndex != NodeHeader::INVALID_INDEX)
- {
- const Name& parentName = m_names[parentIndex];
- fullName = CombineName(parentName.GetPath(), name);
- nameOffset = parentName.GetPathLength() + (parentName.GetPathLength() != 0 ? 1 : 0);
- }
- else
- {
- fullName = name;
- nameOffset = 0;
- }
- StringHash fullNameHash = StringHasher()(fullName);
- AZ_Assert(FindNameLookupIterator(fullNameHash, fullName.c_str()) == m_nameLookup.end(), "Duplicate name found in SceneGraph: %s", fullName.c_str());
- m_nameLookup.insert(NameLookup::value_type(fullNameHash, nodeIndex));
- m_names.emplace_back(AZStd::move(fullName), nameOffset);
- AZ_Assert(m_hierarchy.size() == m_names.size(),
- "Hierarchy and name lists in SceneGraph have gone out of sync. (%i vs. %i)", m_hierarchy.size(), m_names.size());
- m_content.push_back(AZStd::move(content));
- AZ_Assert(m_hierarchy.size() == m_content.size(),
- "Hierarchy and data lists in SceneGraph have gone out of sync. (%i vs. %i)", m_hierarchy.size(), m_content.size());
- return nodeIndex;
- }
- SceneGraph::NameLookup::const_iterator SceneGraph::FindNameLookupIterator(const char* name) const
- {
- StringHash hash = StringHasher()(name);
- return FindNameLookupIterator(hash, name);
- }
- SceneGraph::NameLookup::const_iterator SceneGraph::FindNameLookupIterator(StringHash hash, const char* name) const
- {
- auto range = m_nameLookup.equal_range(hash);
- // Always check the name, even if there's only one entry as the hash can be a clash with
- // the single entry.
- for (auto it = range.first; it != range.second; ++it)
- {
- if (AzFramework::StringFunc::Equal(m_names[it->second].GetPath(), name, true))
- {
- return it;
- }
- }
- return m_nameLookup.end();
- }
- AZStd::string SceneGraph::CombineName(const char* path, const char* name) const
- {
- AZStd::string result = path;
- if (result.length() > 0)
- {
- result += s_nodeSeperationCharacter;
- }
- result += name;
- return result;
- }
- void SceneGraph::AddDefaultRoot()
- {
- AZ_Assert(m_hierarchy.size() == 0, "Adding a default root node to a SceneGraph with content.");
- m_hierarchy.push_back(NodeHeader());
- m_nameLookup.insert(NameLookup::value_type(StringHasher()(""), 0));
- m_names.emplace_back("", 0);
- m_content.emplace_back(nullptr);
- }
- } // Containers
- } // SceneAPI
- } // AZ
|