Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,227 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <SceneAPI/SceneCore/Containers/GraphObjectProxy.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/RTTI/BehaviorContext.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
void GraphObjectProxy::Reflect(AZ::ReflectContext* context)
{
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<GraphObjectProxy>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene.graph")
->Method("CastWithTypeName", &GraphObjectProxy::CastWithTypeName)
->Method("Invoke", &GraphObjectProxy::Invoke)
;
}
}
GraphObjectProxy::GraphObjectProxy(AZStd::shared_ptr<const DataTypes::IGraphObject> graphObject)
{
m_graphObject = graphObject;
}
GraphObjectProxy::~GraphObjectProxy()
{
m_graphObject.reset();
m_behaviorClass = nullptr;
}
bool GraphObjectProxy::CastWithTypeName(const AZStd::string& classTypeName)
{
const AZ::BehaviorClass* behaviorClass = BehaviorContextHelper::GetClass(classTypeName);
if (behaviorClass)
{
const void* baseClass = behaviorClass->m_azRtti->Cast(m_graphObject.get(), behaviorClass->m_azRtti->GetTypeId());
if (baseClass)
{
m_behaviorClass = behaviorClass;
}
return true;
}
return false;
}
AZStd::any GraphObjectProxy::Invoke(AZStd::string_view method, AZStd::vector<AZStd::any> argList)
{
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
if (!serializeContext)
{
AZ_Error("SceneAPI", false, "AZ::SerializeContext should be prepared.");
return AZStd::any(false);
}
if (!m_behaviorClass)
{
AZ_Warning("SceneAPI", false, "Use the CastWithTypeName() to assign the concrete type of IGraphObject to Invoke().");
return AZStd::any(false);
}
auto entry = m_behaviorClass->m_methods.find(method);
if (m_behaviorClass->m_methods.end() == entry)
{
AZ_Warning("SceneAPI", false, "Missing method %.*s from class %s",
aznumeric_cast<int>(method.size()),
method.data(),
m_behaviorClass->m_name.c_str());
return AZStd::any(false);
}
AZ::BehaviorMethod* behaviorMethod = entry->second;
constexpr size_t behaviorParamListSize = 8;
if (behaviorMethod->GetNumArguments() > behaviorParamListSize)
{
AZ_Error("SceneAPI", false, "Unsupported behavior method; supports max %zu but %s has %zu argument slots",
behaviorParamListSize,
behaviorMethod->m_name.c_str(),
behaviorMethod->GetNumArguments());
return AZStd::any(false);
}
AZ::BehaviorValueParameter behaviorParamList[behaviorParamListSize];
// detect if the method passes in a "this" pointer which can be true if the method is a member function
// or if the first argument is the same as the behavior class such as from a lambda function
bool hasSelfPointer = behaviorMethod->IsMember();
if (!hasSelfPointer)
{
hasSelfPointer = behaviorMethod->GetArgument(0)->m_typeId == m_behaviorClass->m_typeId;
}
// record the "this" pointer's metadata like its RTTI so that it can be
// down casted to a parent class type if needed to invoke a parent method
if (const AZ::BehaviorParameter* thisInfo = behaviorMethod->GetArgument(0); hasSelfPointer)
{
// avoiding the "Special handling for the generic object holder." since it assumes
// the BehaviorObject.m_value is a pointer; the reference version is already dereferenced
AZ::BehaviorValueParameter theThisPointer;
const void* self = reinterpret_cast<const void*>(m_graphObject.get());
if ((thisInfo->m_traits & AZ::BehaviorParameter::TR_POINTER) == AZ::BehaviorParameter::TR_POINTER)
{
theThisPointer.m_value = &self;
}
else
{
theThisPointer.m_value = const_cast<void*>(self);
}
theThisPointer.Set(*thisInfo);
behaviorParamList[0].Set(theThisPointer);
}
int paramCount = 0;
for (; paramCount < argList.size() && paramCount < behaviorMethod->GetNumArguments(); ++paramCount)
{
size_t behaviorArgIndex = hasSelfPointer ? paramCount + 1 : paramCount;
const AZ::BehaviorParameter* argBehaviorInfo = behaviorMethod->GetArgument(behaviorArgIndex);
if (!Convert(argList[paramCount], argBehaviorInfo, behaviorParamList[behaviorArgIndex]))
{
AZ_Error("SceneAPI", false, "Could not convert from %s to %s at index %zu",
argBehaviorInfo->m_typeId.ToString<AZStd::string>().c_str(),
behaviorParamList[behaviorArgIndex].m_typeId.ToString<AZStd::string>().c_str(),
paramCount);
return AZStd::any(false);
}
}
if (hasSelfPointer)
{
++paramCount;
}
AZ::BehaviorValueParameter returnBehaviorValue;
if (behaviorMethod->HasResult())
{
returnBehaviorValue.Set(*behaviorMethod->GetResult());
returnBehaviorValue.m_value =
returnBehaviorValue.m_tempData.allocate(returnBehaviorValue.m_azRtti->GetTypeSize(), 16);
}
if (!entry->second->Call(behaviorParamList, paramCount, &returnBehaviorValue))
{
return AZStd::any(false);
}
if (!behaviorMethod->HasResult())
{
return AZStd::any(true);
}
// Create temporary any to get its type info to construct a new AZStd::any with new data
AZStd::any tempAny = serializeContext->CreateAny(returnBehaviorValue.m_typeId);
return AZStd::move(AZStd::any(returnBehaviorValue.m_value, tempAny.get_type_info()));
}
template <typename FROM, typename TO>
bool ConvertFromTo(AZStd::any& input, const AZ::BehaviorParameter* argBehaviorInfo, AZ::BehaviorValueParameter& behaviorParam)
{
if (input.get_type_info().m_id != azrtti_typeid<FROM>())
{
return false;
}
if (argBehaviorInfo->m_typeId != azrtti_typeid<TO>())
{
return false;
}
TO* storage = reinterpret_cast<TO*>(behaviorParam.m_tempData.allocate(argBehaviorInfo->m_azRtti->GetTypeSize(), 16));
*storage = aznumeric_cast<TO>(*AZStd::any_cast<FROM>(&input));
behaviorParam.m_typeId = azrtti_typeid<TO>();
behaviorParam.m_value = storage;
return true;
}
bool GraphObjectProxy::Convert(AZStd::any& input, const AZ::BehaviorParameter* argBehaviorInfo, AZ::BehaviorValueParameter& behaviorParam)
{
if (input.get_type_info().m_id == argBehaviorInfo->m_typeId)
{
behaviorParam.m_typeId = input.get_type_info().m_id;
behaviorParam.m_value = AZStd::any_cast<void>(&input);
return true;
}
#define CONVERT_ANY_NUMERIC(TYPE) ( \
ConvertFromTo<TYPE, double>(input, argBehaviorInfo, behaviorParam) || \
ConvertFromTo<TYPE, float>(input, argBehaviorInfo, behaviorParam) || \
ConvertFromTo<TYPE, AZ::s8>(input, argBehaviorInfo, behaviorParam) || \
ConvertFromTo<TYPE, AZ::u8>(input, argBehaviorInfo, behaviorParam) || \
ConvertFromTo<TYPE, AZ::s16>(input, argBehaviorInfo, behaviorParam) || \
ConvertFromTo<TYPE, AZ::u16>(input, argBehaviorInfo, behaviorParam) || \
ConvertFromTo<TYPE, AZ::s32>(input, argBehaviorInfo, behaviorParam) || \
ConvertFromTo<TYPE, AZ::u32>(input, argBehaviorInfo, behaviorParam) || \
ConvertFromTo<TYPE, AZ::s64>(input, argBehaviorInfo, behaviorParam) || \
ConvertFromTo<TYPE, AZ::u64>(input, argBehaviorInfo, behaviorParam) )
if (CONVERT_ANY_NUMERIC(double) || CONVERT_ANY_NUMERIC(float) ||
CONVERT_ANY_NUMERIC(AZ::s8) || CONVERT_ANY_NUMERIC(AZ::u8) ||
CONVERT_ANY_NUMERIC(AZ::s16) || CONVERT_ANY_NUMERIC(AZ::u16) ||
CONVERT_ANY_NUMERIC(AZ::s32) || CONVERT_ANY_NUMERIC(AZ::u32) ||
CONVERT_ANY_NUMERIC(AZ::s64) || CONVERT_ANY_NUMERIC(AZ::u64) )
{
return true;
}
#undef CONVERT_ANY_NUMERIC
return false;
}
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,51 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Serialization/SerializeContext.h>
#include <SceneAPI/SceneCore/DataTypes/IGraphObject.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
//
// GraphObjectProxy wraps the smart pointer to IGraphObject privately
// so that scripts can access the "graph node content" inside the SceneGraph
//
class GraphObjectProxy final
{
public:
AZ_RTTI(GraphObjectProxy, "{3EF0DDEC-C734-4804-BE99-82058FEBDA71}");
AZ_CLASS_ALLOCATOR(GraphObjectProxy, AZ::SystemAllocator, 0);
static void Reflect(AZ::ReflectContext* context);
GraphObjectProxy(AZStd::shared_ptr<const DataTypes::IGraphObject> graphObject);
~GraphObjectProxy();
bool CastWithTypeName(const AZStd::string& classTypeName);
AZStd::any Invoke(AZStd::string_view method, AZStd::vector<AZStd::any> argList);
protected:
bool Convert(AZStd::any& input, const AZ::BehaviorParameter* argBehaviorInfo, AZ::BehaviorValueParameter& behaviorParam);
private:
AZStd::shared_ptr<const DataTypes::IGraphObject> m_graphObject;
const AZ::BehaviorClass* m_behaviorClass = nullptr;
};
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,159 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneCore/Containers/RuleContainer.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
size_t RuleContainer::GetRuleCount() const
{
return m_rules.size();
}
AZStd::shared_ptr<DataTypes::IRule> RuleContainer::GetRule(size_t index) const
{
AZ_Assert(index < m_rules.size(), "Cannot get rule. Index %i is out of range.", index);
if (index >= m_rules.size())
{
return nullptr;
}
return m_rules[index];
}
void RuleContainer::AddRule(const AZStd::shared_ptr<DataTypes::IRule>& rule)
{
AZ_Assert(AZStd::find(m_rules.begin(), m_rules.end(), rule) == m_rules.end(), "Unable to add rule as it's already been added.");
m_rules.push_back(rule);
}
void RuleContainer::AddRule(AZStd::shared_ptr<DataTypes::IRule>&& rule)
{
AZ_Assert(AZStd::find(m_rules.begin(), m_rules.end(), rule) == m_rules.end(), "Unable to add rule as it's already been added.");
m_rules.push_back(rule);
}
void RuleContainer::RemoveRule(size_t index)
{
if (index < m_rules.size())
{
m_rules.erase(m_rules.begin() + index);
}
}
void RuleContainer::RemoveRule(const AZStd::shared_ptr<DataTypes::IRule>& rule)
{
auto it = AZStd::find(m_rules.begin(), m_rules.end(), rule);
if (it != m_rules.end())
{
m_rules.erase(it);
}
}
void RuleContainer::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (!serializeContext)
{
return;
}
serializeContext->Class<RuleContainer>()
->Version(1)
->Field("rules", &RuleContainer::m_rules);
EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<RuleContainer>("Rule Container", "Description.")
->DataElement(AZ_CRC("ManifestVector", 0x895aa9aa), &RuleContainer::m_rules, "", "Add or remove entries to fine-tune source file processing.")
->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, false)
->Attribute(AZ_CRC("CollectionName", 0xbbc1c898), "Modifiers")
->Attribute(AZ_CRC("ObjectTypeName", 0x6559e0c0), "Modifier")
->ElementAttribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_Hide", 0x32ab90f7));
}
}
// Previously, groups stored the vector of shared pointers of rules. We moved the vector of shared pointers of rules to the RuleContainer and
// groups now have a RuleContainer as a member. This version converter converts from groups holding the vector
bool RuleContainer::VectorToRuleContainerConverter(SerializeContext& context, SerializeContext::DataElementNode& classElement)
{
int elementIndex = classElement.FindElement(AZ_CRC("rules", 0x899a993c));
if (elementIndex >= 0)
{
AZ::SerializeContext::DataElementNode& rulesElement = classElement.GetSubElement(elementIndex);
// Clone the rule elements.
AZStd::vector<AZ::SerializeContext::DataElementNode> rules;
const int numSubElements = rulesElement.GetNumSubElements();
rules.reserve(numSubElements);
for (int i = 0; i < numSubElements; i++)
{
AZ::SerializeContext::DataElementNode& sharedPtrElement = rulesElement.GetSubElement(i);
if (sharedPtrElement.GetNumSubElements() > 0)
{
AZ::SerializeContext::DataElementNode& ruleElement = sharedPtrElement.GetSubElement(0);
rules.push_back(ruleElement);
}
}
// Remove the original rule vector element.
classElement.RemoveElement(elementIndex);
// Add a new rule container element.
const int ruleContainerIndex = classElement.AddElement<RuleContainer>(context, "rules");
if (ruleContainerIndex >= 0)
{
AZ::SerializeContext::DataElementNode& ruleContainerElement = classElement.GetSubElement(ruleContainerIndex);
// Create a rule vector element.
const int rulesVectorIndex = ruleContainerElement.AddElement<AZStd::vector<AZStd::shared_ptr<DataTypes::IRule>>>(context, "rules");
AZ::SerializeContext::DataElementNode& ruleVectorElement = ruleContainerElement.GetSubElement(rulesVectorIndex);
// Add the copied rules to the rule vector element.
for (SerializeContext::DataElementNode& rule : rules)
{
int valueIndex = ruleVectorElement.AddElement<AZStd::shared_ptr<DataTypes::IRule>>(context, "element");
SerializeContext::DataElementNode& pointerNode = ruleVectorElement.GetSubElement(valueIndex);
pointerNode.AddElement(rule);
}
}
}
return true;
}
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,71 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IRule.h>
#include <SceneAPI/SceneCore/SceneCoreConfiguration.h>
namespace AZ
{
class ReflectContext;
namespace SceneAPI
{
namespace Containers
{
class RuleContainer
{
public:
AZ_RTTI(RuleContainer, "{2C20D3DF-57FF-4A31-8680-A4D45302B9CF}");
virtual ~RuleContainer() {}
SCENE_CORE_API size_t GetRuleCount() const;
SCENE_CORE_API AZStd::shared_ptr<DataTypes::IRule> GetRule(size_t index) const;
/**
* Find the first rule of the template type.
* @result The first rule of the template type. nullptr if not found.
*/
template<typename T>
AZStd::shared_ptr<T> FindFirstByType() const;
/**
* Check if there is a rule of the given template type.
* @result True in case a rule of the given template type got found, false if not.
*/
template<typename T>
bool ContainsRuleOfType() const;
SCENE_CORE_API void AddRule(const AZStd::shared_ptr<DataTypes::IRule>& rule);
SCENE_CORE_API void AddRule(AZStd::shared_ptr<DataTypes::IRule>&& rule);
SCENE_CORE_API void RemoveRule(size_t index);
SCENE_CORE_API void RemoveRule(const AZStd::shared_ptr<DataTypes::IRule>& rule);
static void Reflect(ReflectContext* context);
static SCENE_CORE_API bool VectorToRuleContainerConverter(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement);
private:
AZStd::vector<AZStd::shared_ptr<DataTypes::IRule>> m_rules;
};
} // Containers
} // SceneAPI
} // AZ
#include <SceneAPI/SceneCore/Containers/RuleContainer.inl>
@@ -0,0 +1,58 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <SceneAPI/SceneCore/Containers/RuleContainer.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
template<typename T>
AZStd::shared_ptr<T> RuleContainer::FindFirstByType() const
{
static_assert(AZStd::is_base_of<DataTypes::IRule, T>::value, "Specified type T is not derived from IRule.");
for (const AZStd::shared_ptr<DataTypes::IRule>& rule : m_rules)
{
if (rule && rule->RTTI_IsTypeOf(T::TYPEINFO_Uuid()))
{
return AZStd::static_pointer_cast<T>(rule);
}
}
return AZStd::shared_ptr<T>();
}
template<typename T>
bool RuleContainer::ContainsRuleOfType() const
{
static_assert(AZStd::is_base_of<DataTypes::IRule, T>::value, "Specified type T is not derived from IRule.");
for (const AZStd::shared_ptr<DataTypes::IRule>& rule : m_rules)
{
if (rule && rule->RTTI_IsTypeOf(T::TYPEINFO_Uuid()))
{
return true;
}
}
return false;
}
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,134 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <AzCore/RTTI/BehaviorContext.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
Scene::Scene(const AZStd::string& name)
: m_name(name)
{
}
Scene::Scene(AZStd::string&& name)
: m_name(AZStd::move(name))
{
}
void Scene::SetSource(const AZStd::string& filename, const Uuid& guid)
{
m_sourceFilename = filename;
m_sourceGuid = guid;
}
void Scene::SetSource(AZStd::string&& filename, const Uuid& guid)
{
m_sourceFilename = AZStd::move(filename);
m_sourceGuid = guid;
}
const AZStd::string& Scene::GetSourceFilename() const
{
return m_sourceFilename;
}
const Uuid& Scene::GetSourceGuid() const
{
return m_sourceGuid;
}
void Scene::SetManifestFilename(const AZStd::string& name)
{
m_manifestFilename = name;
}
void Scene::SetManifestFilename(AZStd::string&& name)
{
m_manifestFilename = AZStd::move(name);
}
const AZStd::string& Scene::GetManifestFilename() const
{
return m_manifestFilename;
}
SceneGraph& Scene::GetGraph()
{
return m_graph;
}
const SceneGraph& Scene::GetGraph() const
{
return m_graph;
}
SceneManifest& Scene::GetManifest()
{
return m_manifest;
}
const SceneManifest& Scene::GetManifest() const
{
return m_manifest;
}
const AZStd::string& Scene::GetName() const
{
return m_name;
}
void Scene::SetOriginalSceneOrientation(SceneOrientation orientation)
{
m_originalOrientation = orientation;
}
Scene::SceneOrientation Scene::GetOriginalSceneOrientation() const
{
return m_originalOrientation;
}
void Scene::Reflect(ReflectContext* context)
{
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<Scene>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Property("name", BehaviorValueGetter(&Scene::m_name), nullptr)
->Property("manifestFilename", BehaviorValueGetter(&Scene::m_manifestFilename), nullptr)
->Property("sourceFilename", BehaviorValueGetter(&Scene::m_sourceFilename), nullptr)
->Property("sourceGuid", BehaviorValueGetter(&Scene::m_sourceGuid), nullptr)
->Property("graph", BehaviorValueGetter(&Scene::m_graph), nullptr)
->Property("manifest", BehaviorValueGetter(&Scene::m_manifest), nullptr)
->Constant("SceneOrientation_YUp", BehaviorConstant(SceneOrientation::YUp))
->Constant("SceneOrientation_ZUp", BehaviorConstant(SceneOrientation::ZUp))
->Constant("SceneOrientation_XUp", BehaviorConstant(SceneOrientation::XUp))
->Constant("SceneOrientation_NegXUp", BehaviorConstant(SceneOrientation::NegXUp))
->Constant("SceneOrientation_NegYUp", BehaviorConstant(SceneOrientation::NegYUp))
->Constant("SceneOrientation_NegZUp", BehaviorConstant(SceneOrientation::NegZUp))
->Method("GetOriginalSceneOrientation", [](Scene* self) -> int
{
return aznumeric_cast<int>(self->GetOriginalSceneOrientation());
})
;
}
}
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,74 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/std/string/string.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/Containers/SceneManifest.h>
#include <SceneAPI/SceneCore/SceneCoreConfiguration.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
// Scenes are used to store the scene's graph the hierarchy and the manifest for meta data as well
// as a history of the files used to construct both.
class SCENE_CORE_API Scene
{
public:
AZ_TYPE_INFO(Scene, "{1F2E6142-B0D8-42C6-A6E5-CD726DAA9EF0}");
explicit Scene(const AZStd::string& name);
explicit Scene(AZStd::string&& name);
void SetSource(const AZStd::string& filename, const Uuid& guid);
void SetSource(AZStd::string&& filename, const Uuid& guid);
const AZStd::string& GetSourceFilename() const;
const Uuid& GetSourceGuid() const;
void SetManifestFilename(const AZStd::string& name);
void SetManifestFilename(AZStd::string&& name);
const AZStd::string& GetManifestFilename() const;
SceneGraph& GetGraph();
const SceneGraph& GetGraph() const;
SceneManifest& GetManifest();
const SceneManifest& GetManifest() const;
const AZStd::string& GetName() const;
enum class SceneOrientation {YUp, ZUp, XUp, NegYUp, NegZUp, NegXUp};
void SetOriginalSceneOrientation(SceneOrientation orientation);
SceneOrientation GetOriginalSceneOrientation() const;
static void Reflect(ReflectContext* context);
private:
// Disabling export warnings for private methods, clients wont have access to them
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option")
AZStd::string m_name;
AZStd::string m_manifestFilename;
AZStd::string m_sourceFilename;
Uuid m_sourceGuid;
SceneGraph m_graph;
SceneManifest m_manifest;
SceneOrientation m_originalOrientation = SceneOrientation::YUp;
AZ_POP_DISABLE_OVERRIDE_WARNING
};
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,369 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#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>()
->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)
{
GraphObjectProxy* proxy = aznew GraphObjectProxy(graphObject);
return proxy;
}
return nullptr;
})
;
behaviorContext->Class<SceneGraph::NodeIndex>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene.graph")
->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)
;
behaviorContext->Class<SceneGraph::Name>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene.graph")
->Method("GetPath", &SceneGraph::Name::GetPath)
->Method("GetName", &SceneGraph::Name::GetName)
;
}
}
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)
{
NodeIndex::IndexType nodeIndex = aznumeric_caster(m_hierarchy.size());
NodeHeader node;
node.m_parentIndex = parentIndex;
m_hierarchy.push_back(node);
AZ_Assert(IsValidName(name), "Name '%s' for SceneGraph sibling contains invalid characters", name);
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
@@ -0,0 +1,289 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <stdint.h>
#include <AzCore/std/hash.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/std/string/string.h>
#include <AzCore/RTTI/TypeInfo.h>
#include <AzCore/RTTI/ReflectContext.h>
#include <SceneAPI/SceneCore/SceneCoreConfiguration.h>
#include <SceneAPI/SceneCore/Containers/Views/View.h>
#include <SceneAPI/SceneCore/Containers/Views/ConvertIterator.h>
namespace AZ
{
namespace SceneAPI
{
namespace DataTypes
{
class IGraphObject;
}
namespace FbxSceneBuilder
{
struct QueueNode;
struct ImportContext;
}
namespace Containers
{
// The SceneGraph allows for hierarchical storage of arbitrary data in a tree like fashion.
// The internal storage is based on child-sibling representation: https://en.wikipedia.org/wiki/Left-child_right-sibling_binary_tree
//
// The SceneGraph uses a naming convention where the name of a node is concatenated with it's parent and separate by a dot ('.')
// such that child node B of parent node A will have the name "A.B". Note that by default the scene graph has a nameless root node.
//
// There are 2 approaches to manipulating the SceneGraph. The first is direct manipulation by using NodeIndex. This supports
// navigating the graph, manipulating the graph hierarchy and manipulating the stored values. This approach is the most
// flexible and allows for the most control, but requires a lot of code support. This approach is best use while constructing
// the graph for a scene.
// The second option is by combining views. This allows for navigating the graph and manipulating stored values, but not
// for manipulating the graph hierarchy. Views use iterators and can therefore be used in most STL(-like) algorithms as well
// as ranged based loops, but have restrictions in what they can do. This approach is best used while inspecting or exporting
// the graph for a scene.
class SceneGraph
{
public:
// Index for a node.
// Instead of using just a plain int, this is it's own type to reduce the
// risk of invalid indices being passed.
class NodeIndex
{
friend class SceneGraph;
friend struct FbxSceneBuilder::QueueNode;
friend struct FbxSceneBuilder::ImportContext;
public:
// Type needs to be able to store an index in a NodeHeader (currently 21-bits).
using IndexType = uint32_t;
NodeIndex(const NodeIndex& rhs) = default;
NodeIndex& operator=(const NodeIndex& rhs) = default;
// Returns whether or not the node index is valid.
// Note that this function reports explicit invalid nodes, such as the invalid node that's returned when a name can't be found, and
// whether it's valid before any changes are made. If changes to the SceneGraph are made it will not be able to detect that a
// previously valid index has become invalid.
inline bool IsValid() const;
inline bool operator==(NodeIndex rhs) const;
inline bool operator!=(NodeIndex rhs) const;
inline IndexType AsNumber() const;
inline s32 Distance(NodeIndex rhs) const;
private:
static const IndexType INVALID_INDEX = static_cast<IndexType>(-1);
inline NodeIndex();
inline explicit NodeIndex(IndexType value);
IndexType m_value;
};
// NodeHeader contains the relationship a node has with its surrounding nodes and additional information about a node.
// Note that this is always passed by value, so direct access to the member variables doesn't risk unwanted changes.
struct NodeHeader
{
// Number of bits used for storing an index into the stored data. Currently 21 bits, which will support about 2 million nodes.
static const uint32_t INDEX_BIT_COUNT = 21;
static const uint64_t INVALID_INDEX = (1 << INDEX_BIT_COUNT) - 1; // Largest possible value for the index bit count.
// End point nodes are nodes that are not allowed to have children.
uint64_t m_isEndPoint : 1;
uint64_t m_parentIndex: INDEX_BIT_COUNT;
uint64_t m_siblingIndex: INDEX_BIT_COUNT;
uint64_t m_childIndex: INDEX_BIT_COUNT;
inline bool HasParent() const;
inline bool HasSibling() const;
inline bool HasChild() const;
inline bool IsEndPoint() const;
inline NodeIndex GetParentIndex() const;
inline NodeIndex GetSiblingIndex() const;
inline NodeIndex GetChildIndex() const;
inline NodeHeader();
NodeHeader(const NodeHeader& rhs) = default;
NodeHeader& operator=(const NodeHeader& rhs) = default;
};
class Name
{
friend class SceneGraph;
public:
inline Name();
Name(const Name& rhs) = default;
inline Name(Name&& rhs);
inline Name(AZStd::string&& pathName, size_t nameOffset);
Name& operator=(const Name& rhs) = default;
inline Name& operator=(Name&& rhs);
inline bool operator==(const Name& rhs) const;
inline bool operator!=(const Name& rhs) const;
// Returns the full unique path for the SceneGraph node.
inline const char* GetPath() const;
// Returns the name for the SceneGraph Node.
inline const char* GetName() const;
inline size_t GetPathLength() const;
inline size_t GetNameLength() const;
private:
AZStd::string m_path;
size_t m_nameOffset;
};
inline static AZStd::shared_ptr<const DataTypes::IGraphObject> ConstDataConverter(const AZStd::shared_ptr<DataTypes::IGraphObject>& value);
using StringHasher = AZStd::hash<AZStd::string>;
using StringHash = size_t;
using NameLookup = AZStd::unordered_multimap<StringHash, uint32_t>;
using HierarchyStorageType = NodeHeader;
using HierarchyStorage = AZStd::vector<HierarchyStorageType>;
using HierarchyStorageConstIterator = HierarchyStorage::const_iterator;
using HierarchyStorageConstData = Views::View<HierarchyStorageConstIterator>;
using NameStorageType = Name;
using NameStorage = AZStd::vector<NameStorageType>;
using NameStorageConstData = Views::View<NameStorage::const_iterator>;
using ContentStorageType = AZStd::shared_ptr<DataTypes::IGraphObject>;
using ContentStorage = AZStd::vector<ContentStorageType>;
using ContentStorageData = Views::View<ContentStorage::const_iterator>;
using ContentStorageConstDataIteratorWrapper = Views::ConvertIterator<ContentStorage::const_iterator,
decltype(ConstDataConverter(nullptr))>;
using ContentStorageConstData = Views::View<ContentStorageConstDataIteratorWrapper>;
SCENE_CORE_API SceneGraph();
inline NodeIndex GetRoot() const;
SCENE_CORE_API NodeIndex Find(const char* path) const;
SCENE_CORE_API NodeIndex Find(NodeIndex root, const char* name) const;
inline NodeIndex Find(const Name& name);
inline NodeIndex Find(const AZStd::string& path) const;
inline NodeIndex Find(NodeIndex root, const AZStd::string& name) const;
inline bool HasNodeContent(NodeIndex node) const;
inline bool HasNodeSibling(NodeIndex node) const;
inline bool HasNodeChild(NodeIndex node) const;
inline bool HasNodeParent(NodeIndex node) const;
inline bool IsNodeEndPoint(NodeIndex node) const;
SCENE_CORE_API const Name& GetNodeName(NodeIndex node) const;
inline AZStd::shared_ptr<DataTypes::IGraphObject> GetNodeContent(NodeIndex node);
inline AZStd::shared_ptr<const DataTypes::IGraphObject> GetNodeContent(NodeIndex node) const;
inline NodeIndex GetNodeParent(NodeIndex node) const;
inline NodeIndex GetNodeParent(NodeHeader node) const;
inline NodeIndex GetNodeSibling(NodeIndex node) const;
inline NodeIndex GetNodeSibling(NodeHeader node) const;
inline NodeIndex GetNodeChild(NodeIndex node) const;
inline NodeIndex GetNodeChild(NodeHeader node) const;
inline size_t GetNodeCount() const;
// Used when switching from index based navigation to iterator based.
inline HierarchyStorageConstData::iterator ConvertToHierarchyIterator(NodeIndex node) const;
inline NameStorageConstData::iterator ConvertToNameIterator(NodeIndex node) const;
inline ContentStorageData::iterator ConvertToStorageIterator(NodeIndex node);
inline ContentStorageConstData::iterator ConvertToStorageIterator(NodeIndex node) const;
// Used when switching from iterator based navigation to index based.
// Note that any changes made to the SceneGraph using the node index will invalidate
// the original iterator.
inline NodeIndex ConvertToNodeIndex(HierarchyStorageConstData::iterator iterator) const;
inline NodeIndex ConvertToNodeIndex(NameStorageConstData::iterator iterator) const;
inline NodeIndex ConvertToNodeIndex(ContentStorageData::iterator iterator) const;
inline NodeIndex ConvertToNodeIndex(ContentStorageConstData::iterator iterator) const;
// Adds a child node to the given parent. If the parent already had a child, AddChild will search the sibling
// chain for an available spot.
SCENE_CORE_API NodeIndex AddChild(NodeIndex parent, const char* name);
SCENE_CORE_API NodeIndex AddChild(NodeIndex parent, const char* name, const AZStd::shared_ptr<DataTypes::IGraphObject>& content);
SCENE_CORE_API NodeIndex AddChild(NodeIndex parent, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content);
// Adds a sibling to given sibling. If the given sibling already has a sibling, the sibling chain is searched
// for an available spot. If the parent node is known AddChild can be used to achieve the same effect,
// however if index of the (last) added node is available this function can be used to reduce or skip
// the search within the sibling chain. This function can therefore be used as an optimization for AddChild,
// when more than 1 child is being added.
SCENE_CORE_API NodeIndex AddSibling(NodeIndex sibling, const char* name);
SCENE_CORE_API NodeIndex AddSibling(NodeIndex sibling, const char* name, const AZStd::shared_ptr<DataTypes::IGraphObject>& content);
SCENE_CORE_API NodeIndex AddSibling(NodeIndex sibling, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content);
SCENE_CORE_API bool SetContent(NodeIndex node, const AZStd::shared_ptr<DataTypes::IGraphObject>& content);
SCENE_CORE_API bool SetContent(NodeIndex node, AZStd::shared_ptr<DataTypes::IGraphObject>&& content);
// Marks a function to no longer accept child nodes.
SCENE_CORE_API bool MakeEndPoint(NodeIndex node);
inline HierarchyStorageConstData GetHierarchyStorage() const;
inline NameStorageConstData GetNameStorage() const;
inline ContentStorageData GetContentStorage();
inline ContentStorageConstData GetContentStorage() const;
// Clears all data stored inside and reads the default root node.
SCENE_CORE_API void Clear();
// Checks if the given name can be used as a valid name for a node. This only checks the name validity, not if it's
// already in use. Use Find(...) to check if a name is already in use.
SCENE_CORE_API static bool IsValidName(const char* name);
// Checks if the given name can be used as a valid name for a node. This only checks the name validity, not if it's
// already in use. Use Find(...) to check if a name is already in use.
inline static bool IsValidName(const AZStd::string& name);
SCENE_CORE_API static char GetNodeSeperationCharacter();
static void Reflect(AZ::ReflectContext* context);
private:
// Adds a child node to the given parent. AppendChild assumes that checks have already be done to guarantee the given parent
// doesn't already have a child.
NodeIndex::IndexType AppendChild(NodeIndex::IndexType parent, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content);
// Add a sibling after the given sibling. AppendSibling assumes that the correct insertion point was found before calling
// and the given sibling is the last in line with no siblings following.
NodeIndex::IndexType AppendSibling(NodeIndex::IndexType sibling, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content);
// Appends a new node to the graph and configures its heritage according to the given parent. Connections to the new node
// as identified by the returned index are assumed to be setup by either the calling function such as AppendChild or
// AppendSibling.
NodeIndex::IndexType AppendNode(NodeIndex::IndexType parentIndex, const char* name, AZStd::shared_ptr<DataTypes::IGraphObject>&& content);
NameLookup::const_iterator FindNameLookupIterator(const char* name) const;
NameLookup::const_iterator FindNameLookupIterator(StringHash hash, const char* name) const;
AZStd::string CombineName(const char* path, const char* name) const;
void AddDefaultRoot();
static const char s_nodeSeperationCharacter = '.';
NameLookup m_nameLookup;
HierarchyStorage m_hierarchy;
NameStorage m_names;
ContentStorage m_content;
};
} // Containers
} // SceneAPI
AZ_TYPE_INFO_SPECIALIZE(AZ::SceneAPI::Containers::SceneGraph, "{CAC6556D-D5FE-4D0E-BCCD-8940357C1D35}");
AZ_TYPE_INFO_SPECIALIZE(AZ::SceneAPI::Containers::SceneGraph::NodeHeader, "{888C32BB-FEE3-4FA1-ADA4-09A58B03562A}");
AZ_TYPE_INFO_SPECIALIZE(AZ::SceneAPI::Containers::SceneGraph::NodeIndex, "{4AD18037-E629-480D-8165-997A137327FD}");
AZ_TYPE_INFO_SPECIALIZE(AZ::SceneAPI::Containers::SceneGraph::Name, "{4077AC3C-B301-4F5A-BEA7-54D6511AEC2E}");
} // AZ
#include <SceneAPI/SceneCore/Containers/SceneGraph.inl>
@@ -0,0 +1,341 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/std/iterator.h>
#include <AzCore/Casting/numeric_cast.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
//
// NodeIndex
//
SceneGraph::NodeIndex::NodeIndex()
: m_value(NodeIndex::INVALID_INDEX)
{
}
bool SceneGraph::NodeIndex::IsValid() const
{
return m_value != NodeIndex::INVALID_INDEX;
}
bool SceneGraph::NodeIndex::operator==(NodeIndex rhs) const
{
return m_value == rhs.m_value;
}
bool SceneGraph::NodeIndex::operator!=(NodeIndex rhs) const
{
return m_value != rhs.m_value;
}
SceneGraph::NodeIndex::IndexType SceneGraph::NodeIndex::AsNumber() const
{
return m_value;
}
s32 SceneGraph::NodeIndex::Distance(NodeIndex rhs) const
{
return static_cast<s32>(rhs.m_value) - static_cast<s32>(m_value);
}
SceneGraph::NodeIndex::NodeIndex(IndexType value)
: m_value(value)
{
}
//
// SceneGraph NodeHeader
//
SceneGraph::NodeHeader::NodeHeader()
: m_isEndPoint(0)
, m_parentIndex(NodeHeader::INVALID_INDEX)
, m_siblingIndex(NodeHeader::INVALID_INDEX)
, m_childIndex(NodeHeader::INVALID_INDEX)
{
}
bool SceneGraph::NodeHeader::HasParent() const
{
return m_parentIndex != NodeHeader::INVALID_INDEX;
}
bool SceneGraph::NodeHeader::HasSibling() const
{
return m_siblingIndex != NodeHeader::INVALID_INDEX;
}
bool SceneGraph::NodeHeader::HasChild() const
{
return m_childIndex != NodeHeader::INVALID_INDEX;
}
bool SceneGraph::NodeHeader::IsEndPoint() const
{
return m_isEndPoint;
}
SceneGraph::NodeIndex SceneGraph::NodeHeader::GetParentIndex() const
{
return NodeIndex(m_parentIndex);
}
SceneGraph::NodeIndex SceneGraph::NodeHeader::GetSiblingIndex() const
{
return NodeIndex(m_siblingIndex);
}
SceneGraph::NodeIndex SceneGraph::NodeHeader::GetChildIndex() const
{
return NodeIndex(m_childIndex);
}
//
// Name
//
SceneGraph::Name::Name()
: m_nameOffset(0)
{
}
SceneGraph::Name::Name(Name&& rhs)
: m_path(AZStd::move(rhs.m_path))
, m_nameOffset(rhs.m_nameOffset)
{
}
SceneGraph::Name::Name(AZStd::string&& pathName, size_t nameOffset)
: m_path(AZStd::move(pathName))
, m_nameOffset(nameOffset)
{
if (m_nameOffset >= m_path.size())
{
m_nameOffset = m_path.size();
}
}
SceneGraph::Name& SceneGraph::Name::operator=(Name&& rhs)
{
m_path = AZStd::move(rhs.m_path);
m_nameOffset = rhs.m_nameOffset;
return *this;
}
bool SceneGraph::Name::operator==(const Name& rhs) const
{
return m_nameOffset == rhs.m_nameOffset && m_path == rhs.m_path;
}
bool SceneGraph::Name::operator!=(const Name& rhs) const
{
return m_nameOffset != rhs.m_nameOffset || m_path != rhs.m_path;
}
const char* SceneGraph::Name::GetPath() const
{
return m_path.c_str();
}
const char* SceneGraph::Name::GetName() const
{
AZ_Assert(m_nameOffset <= m_path.length(), "Offset to name in SceneGraph path is invalid.");
return m_path.c_str() + m_nameOffset;
}
size_t SceneGraph::Name::GetPathLength() const
{
return m_path.length();
}
size_t SceneGraph::Name::GetNameLength() const
{
AZ_Assert(m_nameOffset <= m_path.length(), "Offset to name in SceneGraph path is invalid.");
return m_path.length() - m_nameOffset;
}
//
// SceneGraph
//
AZStd::shared_ptr<const DataTypes::IGraphObject> SceneGraph::ConstDataConverter(const AZStd::shared_ptr<DataTypes::IGraphObject>& value)
{
return AZStd::shared_ptr<const DataTypes::IGraphObject>(value);
}
SceneGraph::NodeIndex SceneGraph::GetRoot() const
{
return NodeIndex(0);
}
SceneGraph::NodeIndex SceneGraph::Find(const AZStd::string& path) const
{
return Find(path.c_str());
}
SceneGraph::NodeIndex SceneGraph::Find(const Name& name)
{
return Find(name.GetPath());
}
SceneGraph::NodeIndex SceneGraph::Find(NodeIndex root, const AZStd::string& name) const
{
return Find(root, name.c_str());
}
bool SceneGraph::HasNodeContent(NodeIndex node) const
{
return node.m_value < m_content.size() ? m_content[node.m_value] != nullptr : false;
}
bool SceneGraph::HasNodeSibling(NodeIndex node) const
{
return node.m_value < m_hierarchy.size() ? m_hierarchy[node.m_value].HasSibling() : false;
}
bool SceneGraph::HasNodeChild(NodeIndex node) const
{
return node.m_value < m_hierarchy.size() ? m_hierarchy[node.m_value].HasChild() : false;
}
bool SceneGraph::HasNodeParent(NodeIndex node) const
{
return node.m_value < m_hierarchy.size() ? m_hierarchy[node.m_value].HasParent() : false;
}
bool SceneGraph::IsNodeEndPoint(NodeIndex node) const
{
return node.m_value < m_hierarchy.size() ? m_hierarchy[node.m_value].IsEndPoint() : true;
}
AZStd::shared_ptr<DataTypes::IGraphObject> SceneGraph::GetNodeContent(NodeIndex node)
{
return node.m_value < m_content.size() ? m_content[node.m_value] : nullptr;
}
AZStd::shared_ptr<const DataTypes::IGraphObject> SceneGraph::GetNodeContent(NodeIndex node) const
{
return node.m_value < m_content.size() ? m_content[node.m_value] : nullptr;
}
SceneGraph::NodeIndex SceneGraph::GetNodeParent(NodeIndex node) const
{
return node.m_value < m_hierarchy.size() ? GetNodeParent(m_hierarchy[node.m_value]) : NodeIndex();
}
SceneGraph::NodeIndex SceneGraph::GetNodeParent(NodeHeader node) const
{
return NodeIndex(node.m_parentIndex != NodeHeader::INVALID_INDEX ? static_cast<uint32_t>(node.m_parentIndex) : NodeIndex::INVALID_INDEX);
}
SceneGraph::NodeIndex SceneGraph::GetNodeSibling(NodeIndex node) const
{
return node.m_value < m_hierarchy.size() ? GetNodeSibling(m_hierarchy[node.m_value]) : NodeIndex();
}
SceneGraph::NodeIndex SceneGraph::GetNodeSibling(NodeHeader node) const
{
return NodeIndex(node.m_siblingIndex != NodeHeader::INVALID_INDEX ? static_cast<uint32_t>(node.m_siblingIndex) : NodeIndex::INVALID_INDEX);
}
SceneGraph::NodeIndex SceneGraph::GetNodeChild(NodeIndex node) const
{
return node.m_value < m_hierarchy.size() ? GetNodeChild(m_hierarchy[node.m_value]) : NodeIndex();
}
SceneGraph::NodeIndex SceneGraph::GetNodeChild(NodeHeader node) const
{
return NodeIndex(node.m_childIndex != NodeHeader::INVALID_INDEX ? static_cast<uint32_t>(node.m_childIndex) : NodeIndex::INVALID_INDEX);
}
size_t SceneGraph::GetNodeCount() const
{
return m_hierarchy.size();
}
SceneGraph::HierarchyStorageConstData::iterator SceneGraph::ConvertToHierarchyIterator(NodeIndex node) const
{
return node.m_value < m_hierarchy.size() ? m_hierarchy.cbegin() + node.m_value : m_hierarchy.cend();
}
SceneGraph::NameStorageConstData::iterator SceneGraph::ConvertToNameIterator(NodeIndex node) const
{
return node.m_value < m_names.size() ? m_names.cbegin() + node.m_value : m_names.cend();
}
SceneGraph::ContentStorageData::iterator SceneGraph::ConvertToStorageIterator(NodeIndex node)
{
return node.m_value < m_content.size() ? m_content.cbegin() + node.m_value : m_content.cend();
}
SceneGraph::ContentStorageConstData::iterator SceneGraph::ConvertToStorageIterator(NodeIndex node) const
{
return node.m_value < m_content.size() ?
Views::MakeConvertIterator(m_content.cbegin() + node.m_value, ConstDataConverter) :
Views::MakeConvertIterator(m_content.cend(), ConstDataConverter);
}
SceneGraph::NodeIndex SceneGraph::ConvertToNodeIndex(HierarchyStorageConstData::iterator iterator) const
{
return NodeIndex(iterator != m_hierarchy.cend() ? static_cast<uint32_t>(std::distance(m_hierarchy.cbegin(), iterator)) : NodeIndex::INVALID_INDEX);
}
SceneGraph::NodeIndex SceneGraph::ConvertToNodeIndex(NameStorageConstData::iterator iterator) const
{
return NodeIndex(iterator != m_names.cend() ? static_cast<uint32_t>(std::distance(m_names.cbegin(), iterator)) : NodeIndex::INVALID_INDEX);
}
SceneGraph::NodeIndex SceneGraph::ConvertToNodeIndex(ContentStorageData::iterator iterator) const
{
return NodeIndex(iterator != m_content.end() ? static_cast<uint32_t>(std::distance(m_content.begin(), iterator)) : NodeIndex::INVALID_INDEX);
}
SceneGraph::NodeIndex SceneGraph::ConvertToNodeIndex(ContentStorageConstData::iterator iterator) const
{
return NodeIndex(
iterator.GetBaseIterator() != m_content.cend() ?
aznumeric_caster(AZStd::distance(m_content.cbegin(), iterator.GetBaseIterator())) :
NodeIndex::INVALID_INDEX);
}
SceneGraph::HierarchyStorageConstData SceneGraph::GetHierarchyStorage() const
{
return HierarchyStorageConstData(m_hierarchy.begin(), m_hierarchy.end());
}
SceneGraph::NameStorageConstData SceneGraph::GetNameStorage() const
{
return NameStorageConstData(m_names.begin(), m_names.end());
}
SceneGraph::ContentStorageData SceneGraph::GetContentStorage()
{
return ContentStorageData(m_content.begin(), m_content.end());
}
SceneGraph::ContentStorageConstData SceneGraph::GetContentStorage() const
{
return ContentStorageConstData(
Views::MakeConvertIterator(m_content.cbegin(), ConstDataConverter),
Views::MakeConvertIterator(m_content.cend(), ConstDataConverter));
}
bool SceneGraph::IsValidName(const AZStd::string& name)
{
return name.size() > 0 ? IsValidName(name.c_str()) : false;
}
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,374 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <SceneAPI/SceneCore/Containers/SceneManifest.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Debug/Trace.h>
#include <AzCore/IO/GenericStreams.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/JSON/rapidjson.h>
#include <AzCore/JSON/document.h>
#include <AzCore/JSON/prettywriter.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Serialization/Json/RegistrationContext.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AzCore/Serialization/Json/JsonSerializationResult.h>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/Utils/Utils.h>
#include <AzFramework/FileFunc/FileFunc.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
//! Protects from allocating too much memory. The choice of a 5MB threshold is arbitrary.
const size_t MaxSceneManifestFileSizeInBytes = 5 * 1024 * 1024;
const char ErrorWindowName[] = "SceneManifest";
AZ_CLASS_ALLOCATOR_IMPL(SceneManifest, AZ::SystemAllocator, 0)
SceneManifest::~SceneManifest()
{
}
void SceneManifest::Clear()
{
m_storageLookup.clear();
m_values.clear();
}
bool SceneManifest::AddEntry(AZStd::shared_ptr<DataTypes::IManifestObject>&& value)
{
auto itValue = m_storageLookup.find(value.get());
if (itValue != m_storageLookup.end())
{
AZ_TracePrintf(Utilities::WarningWindow, "Manifest Object has already been registered with the manifest.");
return false;
}
Index index = aznumeric_caster(m_values.size());
m_storageLookup[value.get()] = index;
m_values.push_back(AZStd::move(value));
AZ_Assert(m_values.size() == m_storageLookup.size(),
"SceneManifest values and storage-lookup tables have gone out of lockstep (%i vs %i)",
m_values.size(), m_storageLookup.size());
return true;
}
bool SceneManifest::RemoveEntry(const DataTypes::IManifestObject* const value)
{
auto storageLookupIt = m_storageLookup.find(value);
if (storageLookupIt == m_storageLookup.end())
{
AZ_Assert(false, "Value not registered in SceneManifest.");
return false;
}
size_t index = storageLookupIt->second;
m_values.erase(m_values.begin() + index);
m_storageLookup.erase(storageLookupIt);
for (auto& entry : m_storageLookup)
{
if (entry.second > index)
{
entry.second--;
}
}
return true;
}
SceneManifest::Index SceneManifest::FindIndex(const DataTypes::IManifestObject* const value) const
{
auto it = m_storageLookup.find(value);
return it != m_storageLookup.end() ? (*it).second : s_invalidIndex;
}
bool SceneManifest::LoadFromFile(const AZStd::string& absoluteFilePath, SerializeContext* context)
{
if (absoluteFilePath.empty())
{
AZ_Error(ErrorWindowName, false, "Unable to load Scene Manifest: no file path was provided.");
return false;
}
auto readFileOutcome = Utils::ReadFile(absoluteFilePath, MaxSceneManifestFileSizeInBytes);
if (!readFileOutcome.IsSuccess())
{
AZ_Error(ErrorWindowName, false, readFileOutcome.GetError().c_str());
return false;
}
AZStd::string fileContents(readFileOutcome.TakeValue());
// Attempt to read the file as JSON
auto loadJsonOutcome = LoadFromString(fileContents, context);
if (loadJsonOutcome.IsSuccess())
{
return true;
}
// If JSON parsing failed, try to deserialize with XML
auto loadXmlOutcome = LoadFromString(fileContents, context, nullptr, true);
AZStd::string fileName;
AzFramework::StringFunc::Path::GetFileName(absoluteFilePath.c_str(), fileName);
if (loadXmlOutcome.IsSuccess())
{
AZ_TracePrintf(ErrorWindowName, "Scene Manifest ( %s ) is using the deprecated XML file format. It will be upgraded to JSON the next time it is modified.\n", fileName.c_str());
return true;
}
// If both failed, throw an error
AZ_Error(ErrorWindowName, false,
"Unable to deserialize ( %s ) using JSON or XML. \nJSON reported error: %s\nXML reported error: %s",
fileName.c_str(), loadJsonOutcome.GetError().c_str(), loadXmlOutcome.GetError().c_str());
return false;
}
bool SceneManifest::SaveToFile(const AZStd::string& absoluteFilePath, SerializeContext* context)
{
AZ_TraceContext(ErrorWindowName, absoluteFilePath);
if (absoluteFilePath.empty())
{
AZ_Error(ErrorWindowName, false, "Unable to save Scene Manifest: no file path was provided.");
return false;
}
AZStd::string errorMsg = AZStd::string::format("Unable to save Scene Manifest to ( %s ):\n", absoluteFilePath.c_str());
AZ::Outcome<rapidjson::Document, AZStd::string> saveToJsonOutcome = SaveToJsonDocument(context);
if (!saveToJsonOutcome.IsSuccess())
{
AZ_Error(ErrorWindowName, false, "%s%s", errorMsg.c_str(), saveToJsonOutcome.GetError().c_str());
return false;
}
AZ::IO::Path fileIoPath(absoluteFilePath);
auto saveToFileOutcome = AzFramework::FileFunc::WriteJsonFile(saveToJsonOutcome.GetValue(), fileIoPath);
if (!saveToFileOutcome.IsSuccess())
{
AZ_Error(ErrorWindowName, false, "%s%s", errorMsg.c_str(), saveToFileOutcome.GetError().c_str());
return false;
}
return true;
}
AZStd::shared_ptr<const DataTypes::IManifestObject> SceneManifest::SceneManifestConstDataConverter(
const AZStd::shared_ptr<DataTypes::IManifestObject>& value)
{
return AZStd::shared_ptr<const DataTypes::IManifestObject>(value);
}
void SceneManifest::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<SceneManifest>()
->Version(1, &SceneManifest::VersionConverter)
->Field("values", &SceneManifest::m_values);
}
BehaviorContext* behaviorContext = azrtti_cast<BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Class<SceneManifest>()
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Module, "scene")
->Method("ImportFromJson", [](SceneManifest& self, AZStd::string_view jsonBuffer) -> bool
{
auto outcome = self.LoadFromString(jsonBuffer);
if (outcome.IsSuccess())
{
return true;
}
AZ_Warning(ErrorWindowName, false, "LoadFromString outcome failure (%s)", outcome.GetError().c_str());
return true;
})
->Method("ExportToJson", [](SceneManifest& self) -> AZStd::string
{
auto outcome = self.SaveToJsonDocument();
if (outcome.IsSuccess())
{
// write the manifest to a UTF-8 string buffer and move return the string
rapidjson::StringBuffer sb;
rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<>> writer(sb);
rapidjson::Document& document = outcome.GetValue();
document.Accept(writer);
return AZStd::move(AZStd::string(sb.GetString()));
}
AZ_Warning(ErrorWindowName, false, "SaveToJsonDocument outcome failure (%s)", outcome.GetError().c_str());
return {};
});
}
}
bool SceneManifest::VersionConverter(SerializeContext& context, SerializeContext::DataElementNode& node)
{
if (node.GetVersion() != 0)
{
AZ_TracePrintf(ErrorWindowName, "Unable to upgrade SceneManifest from version %i.", node.GetVersion());
return false;
}
// Copy out the original values.
AZStd::vector<SerializeContext::DataElementNode> values;
values.reserve(node.GetNumSubElements());
for (int i = 0; i < node.GetNumSubElements(); ++i)
{
// The old format stored AZStd::pair<AZStd::string, AZStd::shared_ptr<IManifestObjets>>. All this
// data is still used, but needs to be move to the new location. The shared ptr needs to be
// moved into the new container, while the name needs to be moved to the group name.
SerializeContext::DataElementNode& pairNode = node.GetSubElement(i);
// This is the original content of the shared ptr. Using the shared pointer directly caused
// registration issues so it's extracting the data the shared ptr was storing instead.
SerializeContext::DataElementNode& elementNode = pairNode.GetSubElement(1).GetSubElement(0);
SerializeContext::DataElementNode& nameNode = pairNode.GetSubElement(0);
AZStd::string name;
if (nameNode.GetData(name))
{
elementNode.AddElementWithData<AZStd::string>(context, "name", name);
}
// It's better not to set a default name here as the default behaviors will take care of that
// will have more information to work with.
values.push_back(elementNode);
}
// Delete old values
for (int i = 0; i < node.GetNumSubElements(); ++i)
{
node.RemoveElement(i);
}
// Put stored values back
int vectorIndex = node.AddElement<ValueStorage>(context, "values");
SerializeContext::DataElementNode& vectorNode = node.GetSubElement(vectorIndex);
for (SerializeContext::DataElementNode& value : values)
{
value.SetName("element");
// Put in a blank shared ptr to be filled with a value stored from "values".
int valueIndex = vectorNode.AddElement<ValueStorageType>(context, "element");
SerializeContext::DataElementNode& pointerNode = vectorNode.GetSubElement(valueIndex);
// Type doesn't matter as it will be overwritten by the stored value.
pointerNode.AddElement<int>(context, "element");
pointerNode.GetSubElement(0) = value;
}
AZ_TracePrintf(Utilities::WarningWindow,
"The SceneManifest has been updated from version %i. It's recommended to save the updated file.", node.GetVersion());
return true;
}
AZ::Outcome<void, AZStd::string> SceneManifest::LoadFromString(const AZStd::string& fileContents, SerializeContext* context, JsonRegistrationContext* registrationContext, bool loadXml)
{
Clear();
AZStd::string failureMessage;
if (loadXml)
{
// Attempt to read the stream as XML (old format)
// Gems can be removed, causing the setting for manifest objects in the the Gem to not be registered. Instead of failing
// to load the entire manifest, just ignore those values.
ObjectStream::FilterDescriptor loadFilter(&AZ::Data::AssetFilterNoAssetLoading, ObjectStream::FILTERFLAG_IGNORE_UNKNOWN_CLASSES);
if (Utils::LoadObjectFromBufferInPlace<SceneManifest>(fileContents.data(), fileContents.size(), *this, context, loadFilter))
{
Init();
return AZ::Success();
}
failureMessage = "Unable to load Scene Manifest as XML";
}
else
{
// Attempt to read the stream as JSON
auto readJsonOutcome = AzFramework::FileFunc::ReadJsonFromString(fileContents);
AZStd::string errorMsg;
if (!readJsonOutcome.IsSuccess())
{
return AZ::Failure(readJsonOutcome.TakeError());
}
rapidjson::Document document = readJsonOutcome.TakeValue();
AZ::JsonDeserializerSettings settings;
settings.m_serializeContext = context;
settings.m_registrationContext = registrationContext;
AZ::JsonSerializationResult::ResultCode jsonResult = AZ::JsonSerialization::Load(*this, document, settings);
if (jsonResult.GetProcessing() != AZ::JsonSerializationResult::Processing::Halted)
{
Init();
return AZ::Success();
}
failureMessage = jsonResult.ToString("");
}
return AZ::Failure(failureMessage);
}
AZ::Outcome<rapidjson::Document, AZStd::string> SceneManifest::SaveToJsonDocument(SerializeContext* context, JsonRegistrationContext* registrationContext)
{
AZ::JsonSerializerSettings settings;
settings.m_serializeContext = context;
settings.m_registrationContext = registrationContext;
rapidjson::Document jsonDocument;
auto jsonResult = JsonSerialization::Store(jsonDocument, jsonDocument.GetAllocator(), *this, settings);
if (jsonResult.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted)
{
return AZ::Failure(AZStd::string::format("JSON serialization failed: %s", jsonResult.ToString("").c_str()));
}
return AZ::Success(AZStd::move(jsonDocument));
}
void SceneManifest::Init()
{
auto end = AZStd::remove_if(m_values.begin(), m_values.end(),
[](const ValueStorageType& entry) -> bool
{
return !entry;
});
m_values.erase(end, m_values.end());
for (size_t i = 0; i < m_values.size(); ++i)
{
Index index = aznumeric_caster(i);
m_storageLookup[m_values[i].get()] = index;
}
}
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,119 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <stdint.h>
#include <AzCore/JSON/rapidjson.h>
#include <AzCore/JSON/document.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/Outcome/Outcome.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/std/utils.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <SceneAPI/SceneCore/SceneCoreConfiguration.h>
#include <SceneAPI/SceneCore/Containers/Views/View.h>
#include <SceneAPI/SceneCore/Containers/Views/ConvertIterator.h>
#include <SceneAPI/SceneCore/DataTypes/IManifestObject.h>
namespace AZ
{
class JsonRegistrationContext;
namespace SceneAPI
{
namespace Containers
{
// Scene manifests hold arbitrary meta data about a scene in a dictionary-like fashion.
// This can include data such as export groups.
class SCENE_CORE_API SceneManifest
{
friend class SceneManifestContainer;
public:
AZ_CLASS_ALLOCATOR_DECL
AZ_RTTI(SceneManifest, "{9274AD17-3212-4651-9F3B-7DCCB080E467}");
virtual ~SceneManifest();
static AZStd::shared_ptr<const DataTypes::IManifestObject> SceneManifestConstDataConverter(
const AZStd::shared_ptr<DataTypes::IManifestObject>& value);
using Index = size_t;
static const Index s_invalidIndex = static_cast<Index>(-1);
using StorageHash = const DataTypes::IManifestObject *;
using StorageLookup = AZStd::unordered_map<StorageHash, Index>;
using ValueStorageType = AZStd::shared_ptr<DataTypes::IManifestObject>;
using ValueStorage = AZStd::vector<ValueStorageType>;
using ValueStorageData = Views::View<ValueStorage::const_iterator>;
using ValueStorageConstDataIteratorWrapper = Views::ConvertIterator<ValueStorage::const_iterator,
decltype(SceneManifestConstDataConverter(AZStd::shared_ptr<DataTypes::IManifestObject>()))>;
using ValueStorageConstData = Views::View<ValueStorageConstDataIteratorWrapper>;
void Clear();
inline bool IsEmpty() const;
inline bool AddEntry(const AZStd::shared_ptr<DataTypes::IManifestObject>& value);
bool AddEntry(AZStd::shared_ptr<DataTypes::IManifestObject>&& value);
inline bool RemoveEntry(const AZStd::shared_ptr<DataTypes::IManifestObject>& value);
bool RemoveEntry(const DataTypes::IManifestObject* const value);
inline size_t GetEntryCount() const;
inline AZStd::shared_ptr<DataTypes::IManifestObject> GetValue(Index index);
inline AZStd::shared_ptr<const DataTypes::IManifestObject> GetValue(Index index) const;
// Finds the index of the given manifest object. A nullptr or invalid object will return s_invalidIndex.
inline Index FindIndex(const AZStd::shared_ptr<DataTypes::IManifestObject>& value) const;
// Finds the index of the given manifest object. A nullptr or invalid object will return s_invalidIndex.
Index FindIndex(const DataTypes::IManifestObject* const value) const;
inline ValueStorageData GetValueStorage();
inline ValueStorageConstData GetValueStorage() const;
bool LoadFromFile(const AZStd::string& absoluteFilePath, SerializeContext* context = nullptr);
/**
* Save manifest to file. Overwrites the file in case it already exists and creates a new file if not.
* @param absoluteFilePath the absolute path of the file you want to save to.
* @param context If no serialize context was specified, it will get the serialize context from the application component bus.
* @result True in case saving went all fine, false if an error occured.
*/
bool SaveToFile(const AZStd::string& absoluteFilePath, SerializeContext* context = nullptr);
AZ::Outcome<void, AZStd::string> LoadFromString(
const AZStd::string& fileContents, SerializeContext* context = nullptr,
JsonRegistrationContext* registrationContext = nullptr, bool loadXml = false);
static void Reflect(ReflectContext* context);
static bool VersionConverter(SerializeContext& context, SerializeContext::DataElementNode& node);
protected:
AZ::Outcome<rapidjson::Document, AZStd::string> SaveToJsonDocument(SerializeContext* context = nullptr, JsonRegistrationContext* registrationContext = nullptr);
private:
void Init();
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option")
StorageLookup m_storageLookup;
ValueStorage m_values;
AZ_POP_DISABLE_OVERRIDE_WARNING
};
} // Containers
} // SceneAPI
} // AZ
#include <SceneAPI/SceneCore/Containers/SceneManifest.inl>
@@ -0,0 +1,75 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/Debug/Trace.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
bool SceneManifest::IsEmpty() const
{
// Any of the containers would do as they should be in-sync with each other, so pick one arbitrarily.
AZ_Assert(m_values.empty() == m_storageLookup.empty(), "SceneManifest values and storage-lookup tables have gone out of lockstep.");
return m_values.empty();
}
bool SceneManifest::AddEntry(const AZStd::shared_ptr<DataTypes::IManifestObject>& value)
{
return AddEntry(AZStd::shared_ptr<DataTypes::IManifestObject>(value));
}
bool SceneManifest::RemoveEntry(const AZStd::shared_ptr<DataTypes::IManifestObject>& value)
{
return RemoveEntry(value.get());
}
size_t SceneManifest::GetEntryCount() const
{
// Any of the containers would do as they should be in-sync with each other, so pick one randomly.
AZ_Assert(m_values.size() == m_storageLookup.size(),
"SceneManifest values and storage-lookup tables have gone out of lockstep. (%i vs. %i)",
m_values.size(), m_storageLookup.size());
return m_values.size();
}
AZStd::shared_ptr<DataTypes::IManifestObject> SceneManifest::GetValue(Index index)
{
return index < m_values.size() ? m_values[index] : AZStd::shared_ptr<DataTypes::IManifestObject>();
}
AZStd::shared_ptr<const DataTypes::IManifestObject> SceneManifest::GetValue(Index index) const
{
return index < m_values.size() ? m_values[index] : AZStd::shared_ptr<const DataTypes::IManifestObject>();
}
SceneManifest::Index SceneManifest::FindIndex(const AZStd::shared_ptr<DataTypes::IManifestObject>& value) const
{
return FindIndex(value.get());
}
SceneManifest::ValueStorageData SceneManifest::GetValueStorage()
{
return ValueStorageData(m_values.begin(), m_values.end());
}
SceneManifest::ValueStorageConstData SceneManifest::GetValueStorage() const
{
return ValueStorageConstData(
Views::MakeConvertIterator(m_values.cbegin(), SceneManifestConstDataConverter),
Views::MakeConvertIterator(m_values.cend(), SceneManifestConstDataConverter));
}
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,142 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/std/typetraits/is_base_of.h>
#include <AzCore/std/typetraits/conditional.h>
#include <AzCore/std/utils.h>
#include <SceneAPI/SceneCore/DataTypes/IManifestObject.h>
#include <SceneAPI/SceneCore/DataTypes/IGraphObject.h>
#include <SceneAPI/SceneCore/Containers/Views/FilterIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/ConvertIterator.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
// Utility classes to construct common filters for scenes. These can be used in
// algorithms such as find_if or the FilterIterator.
// Example:
// auto result = AZStd::find_if(view.begin(), view.end(), DerivedTypeFilter<IMeshData>());
namespace Internal
{
template<typename T, typename ObjectType, bool ExactType>
struct TypeFilter
{
bool operator()(const ObjectType& object) const;
bool operator()(const ObjectType* const object) const;
bool operator()(const AZStd::shared_ptr<const ObjectType>& object) const;
bool operator()(const AZStd::shared_ptr<ObjectType>& object) const;
template<typename T1>
bool operator()(const AZStd::pair<T1, AZStd::shared_ptr<const ObjectType>>& object) const;
template<typename T1>
bool operator()(const AZStd::pair<T1, AZStd::shared_ptr<ObjectType>>& object) const;
template<typename T1>
bool operator()(const AZStd::pair<T1, const AZStd::shared_ptr<const ObjectType>&>& object) const;
template<typename T1>
bool operator()(const AZStd::pair<T1, const AZStd::shared_ptr<ObjectType>&>& object) const;
template<typename T2>
bool operator()(const AZStd::pair<AZStd::shared_ptr<const ObjectType>, T2>& object) const;
template<typename T2>
bool operator()(const AZStd::pair<AZStd::shared_ptr<ObjectType>, T2>& object) const;
template<typename T2>
bool operator()(const AZStd::pair<const AZStd::shared_ptr<const ObjectType>&, T2>& object) const;
template<typename T2>
bool operator()(const AZStd::pair<const AZStd::shared_ptr<ObjectType>&, T2>& object) const;
};
template<typename T>
struct TypeFilterBaseType
{
static const bool s_isManifestObject = AZStd::is_base_of<DataTypes::IManifestObject, T>::value;
static const bool s_isGraphObject = AZStd::is_base_of<DataTypes::IGraphObject, T>::value;
static_assert(s_isManifestObject || s_isGraphObject, "Target type is not derived from IManifestObject or IGraphObject.");
using type = typename AZStd::conditional<s_isManifestObject, DataTypes::IManifestObject, DataTypes::IGraphObject>::type;
};
template<typename T> struct IsConstPayload { static const bool value = AZStd::is_const<T>::value; };
template<typename T> struct IsConstPayload<AZStd::shared_ptr<T>> { static const bool value = false; };
template<typename T> struct IsConstPayload<AZStd::unique_ptr<T>> { static const bool value = false; };
template<typename T> struct IsConstPayload<AZStd::shared_ptr<const T>> { static const bool value = true; };
template<typename T> struct IsConstPayload<AZStd::unique_ptr<const T>> { static const bool value = true; };
template<typename T, typename ViewType>
struct ConversionType
{
using type = typename AZStd::conditional<
IsConstPayload<typename AZStd::iterator_traits<typename ViewType::iterator>::value_type>::value,
const T, T>::type;
};
}
// Filter object for any type derived from the given type or the type itself. The given type must
// itself derive from either IManifestObject or IGraphObject.
// Example:
// auto result = AZStd::find_if(view.begin(), view.end(), DerivedTypeFilter<IMeshData>());
template<typename T>
struct DerivedTypeFilter
: public Internal::TypeFilter<T, typename Internal::TypeFilterBaseType<T>::type, false>
{
};
// Filter object for the given type. The given type must derive from either IManifestObject or
// IGraphObject.
// Example:
// auto view = Views::MakeFilterView(graph.GetContentStorage, ExactTypeFilter<MeshData>());
template<typename T>
struct ExactTypeFilter
: public Internal::TypeFilter<T, typename Internal::TypeFilterBaseType<T>::type, true>
{
};
// Compound view that returns all instances of the requested type and any types deriving from it.
// The given type must derive from either IManifestObject or IGraphObject.
// Example:
// auto view = MakeDerivedFilterView<IMeshData>(graph.GetContentStorage());
// for (IMeshData& mesh : view)
// {
// ...
// }
template<typename T, typename ViewType>
Views::View<Views::ConvertIterator<typename Views::FilterIterator<typename ViewType::iterator>,
typename Internal::ConversionType<T, ViewType>::type&>> MakeDerivedFilterView(ViewType& view);
template<typename T, typename ViewType>
Views::View<Views::ConvertIterator<typename Views::FilterIterator<typename ViewType::const_iterator>, const T&>> MakeDerivedFilterView(const ViewType& view);
// Compound view that returns all instances of the requested type.
// The given type must derive from either IManifestObject or IGraphObject.
// Example:
// auto view = MakeExactFilterView<MeshData>(graph.GetContentStorage());
// for (MeshData& mesh : view)
// {
// ...
// }
template<typename T, typename ViewType>
Views::View<Views::ConvertIterator<typename Views::FilterIterator<typename ViewType::iterator>,
typename Internal::ConversionType<T, ViewType>::type&>> MakeExactFilterView(ViewType& view);
template<typename T, typename ViewType>
Views::View<Views::ConvertIterator<typename Views::FilterIterator<typename ViewType::const_iterator>, const T&>> MakeExactFilterView(const ViewType& view);
} // Containers
} // SceneAPI
} // AZ
#include <SceneAPI/SceneCore/Containers/Utilities/Filters.inl>
@@ -0,0 +1,253 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Internal
{
template<typename T, typename ObjectType, bool ExactType>
bool TypeFilter<T, ObjectType, ExactType>::operator()(const ObjectType& object) const
{
if (ExactType)
{
return object.RTTI_GetType() == T::TYPEINFO_Uuid();
}
else
{
return object.RTTI_IsTypeOf(T::TYPEINFO_Uuid());
}
}
template<typename T, typename ObjectType, bool ExactType>
bool TypeFilter<T, ObjectType, ExactType>::operator()(const ObjectType* const object) const
{
if (ExactType)
{
return object && object->RTTI_GetType() == T::TYPEINFO_Uuid();
}
else
{
return object && object->RTTI_IsTypeOf(T::TYPEINFO_Uuid());
}
}
template<typename T, typename ObjectType, bool ExactType>
bool TypeFilter<T, ObjectType, ExactType>::operator()(const AZStd::shared_ptr<const ObjectType>& object) const
{
if (ExactType)
{
return object && object->RTTI_GetType() == T::TYPEINFO_Uuid();
}
else
{
return object && object->RTTI_IsTypeOf(T::TYPEINFO_Uuid());
}
}
template<typename T, typename ObjectType, bool ExactType>
bool TypeFilter<T, ObjectType, ExactType>::operator()(const AZStd::shared_ptr<ObjectType>& object) const
{
if (ExactType)
{
return object && object->RTTI_GetType() == T::TYPEINFO_Uuid();
}
else
{
return object && object->RTTI_IsTypeOf(T::TYPEINFO_Uuid());
}
}
template<typename T, typename ObjectType, bool ExactType> template<typename T1>
bool TypeFilter<T, ObjectType, ExactType>::operator()(const AZStd::pair<T1, AZStd::shared_ptr<const ObjectType>>& object) const
{
if (ExactType)
{
return object.second && object.second->RTTI_GetType() == T::TYPEINFO_Uuid();
}
else
{
return object.second && object.second->RTTI_IsTypeOf(T::TYPEINFO_Uuid());
}
}
template<typename T, typename ObjectType, bool ExactType> template<typename T1>
bool TypeFilter<T, ObjectType, ExactType>::operator()(const AZStd::pair<T1, AZStd::shared_ptr<ObjectType>>& object) const
{
if (ExactType)
{
return object.second && object.second->RTTI_GetType() == T::TYPEINFO_Uuid();
}
else
{
return object.second && object.second->RTTI_IsTypeOf(T::TYPEINFO_Uuid());
}
}
template<typename T, typename ObjectType, bool ExactType> template<typename T1>
bool TypeFilter<T, ObjectType, ExactType>::operator()(const AZStd::pair<T1, const AZStd::shared_ptr<const ObjectType>&>& object) const
{
if (ExactType)
{
return object.second && object.second->RTTI_GetType() == T::TYPEINFO_Uuid();
}
else
{
return object.second && object.second->RTTI_IsTypeOf(T::TYPEINFO_Uuid());
}
}
template<typename T, typename ObjectType, bool ExactType> template<typename T1>
bool TypeFilter<T, ObjectType, ExactType>::operator()(const AZStd::pair<T1, const AZStd::shared_ptr<ObjectType>&>& object) const
{
if (ExactType)
{
return object.second && object.second->RTTI_GetType() == T::TYPEINFO_Uuid();
}
else
{
return object.second && object.second->RTTI_IsTypeOf(T::TYPEINFO_Uuid());
}
}
template<typename T, typename ObjectType, bool ExactType> template<typename T2>
bool TypeFilter<T, ObjectType, ExactType>::operator()(const AZStd::pair<AZStd::shared_ptr<const ObjectType>, T2>& object) const
{
if (ExactType)
{
return object.first && object.first->RTTI_GetType() == T::TYPEINFO_Uuid();
}
else
{
return object.first && object.first->RTTI_IsTypeOf(T::TYPEINFO_Uuid());
}
}
template<typename T, typename ObjectType, bool ExactType> template<typename T2>
bool TypeFilter<T, ObjectType, ExactType>::operator()(const AZStd::pair<AZStd::shared_ptr<ObjectType>, T2>& object) const
{
if (ExactType)
{
return object.first && object.first->RTTI_GetType() == T::TYPEINFO_Uuid();
}
else
{
return object.first && object.first->RTTI_IsTypeOf(T::TYPEINFO_Uuid());
}
}
template<typename T, typename ObjectType, bool ExactType> template<typename T2>
bool TypeFilter<T, ObjectType, ExactType>::operator()(const AZStd::pair<const AZStd::shared_ptr<const ObjectType>&, T2>& object) const
{
if (ExactType)
{
return object.first && object.first->RTTI_GetType() == T::TYPEINFO_Uuid();
}
else
{
return object.first && object.first->RTTI_IsTypeOf(T::TYPEINFO_Uuid());
}
}
template<typename T, typename ObjectType, bool ExactType> template<typename T2>
bool TypeFilter<T, ObjectType, ExactType>::operator()(const AZStd::pair<const AZStd::shared_ptr<ObjectType>&, T2>& object) const
{
if (ExactType)
{
return object.first && object.first->RTTI_GetType() == T::TYPEINFO_Uuid();
}
else
{
return object.first && object.first->RTTI_IsTypeOf(T::TYPEINFO_Uuid());
}
}
} // Internal
template<typename T, typename ViewType>
Views::View<Views::ConvertIterator<typename Views::FilterIterator<typename ViewType::iterator>,
typename Internal::ConversionType<T, ViewType>::type&>> MakeDerivedFilterView(ViewType& view)
{
auto filterView = Views::MakeFilterView(view, DerivedTypeFilter<T>());
auto convertView = Views::MakeConvertView(filterView,
// Note that by default begin() returns a reference to the value, so the argument will
// already be by-reference so an extra reference doesn't need to be added and this
// function isn't being called by value.
[](decltype(*filterView.begin()) instance) -> typename Internal::ConversionType<T, ViewType>::type&
{
AZ_Assert(instance.get(), "Null pointer encountered.");
typename Internal::ConversionType<T, ViewType>::type* result =
azrtti_cast<typename Internal::ConversionType<T, ViewType>::type*>(instance.get());
AZ_Assert(result, "Unable to cast to target type.");
return *result;
}
);
return convertView;
}
template<typename T, typename ViewType>
Views::View<Views::ConvertIterator<typename Views::FilterIterator<typename ViewType::const_iterator>, const T&>> MakeDerivedFilterView(const ViewType& view)
{
auto filterView = Views::MakeFilterView(view, DerivedTypeFilter<T>());
auto convertView = Views::MakeConvertView(filterView,
// Note that by default begin() returns a reference to the value, so the argument will
// already be by-reference so an extra reference doesn't need to be added and this
// function isn't being called by value.
[](decltype(*filterView.begin()) instance) -> const T&
{
AZ_Assert(instance.get(), "Null pointer encountered.");
const T* result = azrtti_cast<const T*>(instance.get());
AZ_Assert(result, "Unable to cast to target type.");
return *result;
}
);
return convertView;
}
template<typename T, typename ViewType>
Views::View<Views::ConvertIterator<typename Views::FilterIterator<typename ViewType::iterator>,
typename Internal::ConversionType<T, ViewType>::type&>> MakeExactFilterView(ViewType& view)
{
auto filterView = Views::MakeFilterView(view, ExactTypeFilter<T>());
auto convertView = Views::MakeConvertView(filterView,
[](decltype(*filterView.begin()) instance) -> typename Internal::ConversionType<T, ViewType>::type&
{
AZ_Assert(instance.get(), "Null pointer encountered.");
typename Internal::ConversionType<T, ViewType>::type* result =
azrtti_cast<typename Internal::ConversionType<T, ViewType>::type*>(instance.get());
AZ_Assert(result, "Unable to cast to target type.");
return *result;
}
);
return convertView;
}
template<typename T, typename ViewType>
Views::View<Views::ConvertIterator<typename Views::FilterIterator<typename ViewType::const_iterator>, const T&>> MakeExactFilterView(const ViewType& view)
{
auto filterView = Views::MakeFilterView(view, ExactTypeFilter<T>());
auto convertView = Views::MakeConvertView(filterView,
[](decltype(*filterView.begin())& instance) -> const T&
{
AZ_Assert(instance.get(), "Null pointer encountered.");
const T* result = azrtti_cast<const T*>(instance.get());
AZ_Assert(result, "Unable to cast to target type.");
return *result;
}
);
return convertView;
}
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,53 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
// Utility class that stores (or references if possible) the given value
// but otherwise acts as a pointer. This can be useful for functions
// that require returning a pointer but don't store a local copy to
// return.
template<typename Type>
class ProxyPointer
{
public:
ProxyPointer(const Type& value);
Type& operator*();
Type* operator->();
private:
Type m_value;
};
template<typename Type>
class ProxyPointer<Type&>
{
public:
ProxyPointer(Type& value);
Type& operator*();
Type* operator->();
private:
Type& m_value;
};
} // Containers
} // SceneAPI
} // AZ
#include <SceneAPI/SceneCore/Containers/Utilities/ProxyPointer.inl>
@@ -0,0 +1,56 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
template<typename Type>
ProxyPointer<Type>::ProxyPointer(const Type& value)
: m_value(value)
{
}
template<typename Type>
Type& ProxyPointer<Type>::operator*()
{
return m_value;
}
template<typename Type>
Type* ProxyPointer<Type>::operator->()
{
return &m_value;
}
template<typename Type>
ProxyPointer<Type&>::ProxyPointer(Type& value)
: m_value(value)
{
}
template<typename Type>
Type& ProxyPointer<Type&>::operator*()
{
return m_value;
}
template<typename Type>
Type* ProxyPointer<Type&>::operator->()
{
return &m_value;
}
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,69 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/Math/Matrix3x4.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/typetraits/is_base_of.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/Containers/Views/FilterIterator.h>
#include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
#include <SceneAPI/SceneCore/Containers/Utilities/SceneGraphUtilities.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphChildIterator.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/ITransform.h>
#include <SceneAPI/SceneCore/Events/GraphMetaInfoBus.h>
namespace AZ
{
namespace SceneAPI
{
namespace Utilities
{
DataTypes::MatrixType BuildWorldTransform(const Containers::SceneGraph& graph, Containers::SceneGraph::NodeIndex nodeIndex)
{
DataTypes::MatrixType outTransform = DataTypes::MatrixType::Identity();
while (nodeIndex.IsValid())
{
auto view = Containers::Views::MakeSceneGraphChildView<Containers::Views::AcceptEndPointsOnly>(graph, nodeIndex,
graph.GetContentStorage().begin(), true);
auto result = AZStd::find_if(view.begin(), view.end(), Containers::DerivedTypeFilter<DataTypes::ITransform>());
if (result != view.end())
{
// Check if the node has any child transform node
const DataTypes::MatrixType& azTransform = azrtti_cast<const DataTypes::ITransform*>(result->get())->GetMatrix();
outTransform = azTransform * outTransform;
}
else
{
// Check if the node itself is a transform node.
AZStd::shared_ptr<const DataTypes::ITransform> transformData = azrtti_cast<const DataTypes::ITransform*>(graph.GetNodeContent(nodeIndex));
if (transformData)
{
outTransform = transformData->GetMatrix() * outTransform;
}
}
if (graph.HasNodeParent(nodeIndex))
{
nodeIndex = graph.GetNodeParent(nodeIndex);
}
else
{
break;
}
}
return outTransform;
}
} // Utilities
} // SceneAPI
} // AZ
@@ -0,0 +1,38 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/DataTypes/MatrixType.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
class Scene;
}
namespace Utilities
{
// Searches for any entries in the scene graph that are derived or match the given type.
// If "checkVirtualTypes" is true, a matching entry is also checked if it's not a
// virtual type.
template<typename T>
bool DoesSceneGraphContainDataLike(const Containers::Scene& scene, bool checkVirtualTypes);
SCENE_CORE_API DataTypes::MatrixType BuildWorldTransform(const Containers::SceneGraph& graph, Containers::SceneGraph::NodeIndex nodeIndex);
} // Utilities
} // SceneAPI
} // AZ
#include <SceneAPI/SceneCore/Containers/Utilities/SceneGraphUtilities.inl>
@@ -0,0 +1,58 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/std/algorithm.h>
#include <AzCore/std/typetraits/is_base_of.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/Containers/Views/FilterIterator.h>
#include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
#include <SceneAPI/SceneCore/Events/GraphMetaInfoBus.h>
namespace AZ
{
namespace SceneAPI
{
namespace Utilities
{
template<typename T>
bool DoesSceneGraphContainDataLike(const Containers::Scene& scene, bool checkVirtualTypes)
{
static_assert(AZStd::is_base_of<DataTypes::IGraphObject, T>::value, "Specified type T is not derived from IGraphObject.");
const Containers::SceneGraph& graph = scene.GetGraph();
if (checkVirtualTypes)
{
auto contentStorage = graph.GetContentStorage();
auto view = Containers::Views::MakeFilterView(contentStorage, Containers::DerivedTypeFilter<T>());
for (auto it = view.begin(); it != view.end(); ++it)
{
AZStd::set<Crc32> types;
EBUS_EVENT(Events::GraphMetaInfoBus, GetVirtualTypes, types, scene, graph.ConvertToNodeIndex(it.GetBaseIterator()));
// Check if the type is not a virtual type. If it is, this isn't a valid type for T.
if (types.empty())
{
return true;
}
}
return false;
}
else
{
Containers::SceneGraph::ContentStorageConstData graphContent = graph.GetContentStorage();
auto data = AZStd::find_if(graphContent.begin(), graphContent.end(), Containers::DerivedTypeFilter<T>());
return data != graphContent.end();
}
}
} // Utilities
} // SceneAPI
} // AZ
@@ -0,0 +1,234 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/std/iterator.h>
#include <AzCore/std/typetraits/is_pointer.h>
#include <AzCore/std/typetraits/is_reference.h>
#include <AzCore/std/typetraits/remove_reference.h>
#include <AzCore/std/utils.h>
#include <SceneAPI/SceneCore/Containers/Views/View.h>
#include <SceneAPI/SceneCore/Containers/Utilities/ProxyPointer.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
// Transform allows the value of the given iterator to be converted to the assigned TransformType when dereferencing.
// A typical use case would be to change a "const shared_ptr<type>" to "const shared<const type>" for read-only
// iteration of a vector<shared_ptr<type>>.
// template argument Iterator: the base iterator which will be used as the given iterator.
// template argument TransformType: the target type the value of base iterator will be converted to.
// This requires the type stored in iterator to have conversion to this type.
// template argument Category: the iterator classification. ConvertIterator will automatically derive this
// from the given iterator and match its behavior.
// Example:
// ConvertIterator<Vector<shared_ptr<Object>>::iterator, shared_ptr<const Object>>;
//
// WARNING
// Types used for conversion that are not convertible through a reference and pointer will return their result
// by-value instead of by-reference. This may cause some unexpected behavior the user should be aware of.
template<typename Iterator>
struct ConvertIteratorArgumentHelper
{
using ArgumentType = typename AZStd::conditional<AZStd::is_pointer<
typename AZStd::iterator_traits<Iterator>::value_type>::value,
typename AZStd::iterator_traits<Iterator>::value_type,
typename AZStd::iterator_traits<Iterator>::reference>::type;
};
template<typename Iterator, typename Function>
struct ConvertIteratorFunctionHelper
{
using ArgumentType = typename ConvertIteratorArgumentHelper<Iterator>::ArgumentType;
using ReturnType = AZStd::invoke_result_t<Function, ArgumentType>;
};
template<typename Iterator, typename ReturnType>
struct ConvertIteratorTypeHelper
{
using ArgumentType = typename ConvertIteratorArgumentHelper<Iterator>::ArgumentType;
using Function = ReturnType(*)(ArgumentType);
using PointerConditionType = typename AZStd::is_reference<ReturnType>::type;
using reference = ReturnType;
using pointer = typename AZStd::conditional<AZStd::is_reference<ReturnType>::value,
typename AZStd::remove_reference<ReturnType>::type*, ProxyPointer<ReturnType> >::type;
using value_type = typename AZStd::remove_reference<ReturnType>::type;
};
template<typename Iterator, typename ReturnType, typename Category = typename AZStd::iterator_traits<Iterator>::iterator_category>
class ConvertIterator
{
};
//
// Base iterator
//
template<typename Iterator, typename ReturnType>
class ConvertIterator<Iterator, ReturnType, void>
{
public:
using value_type = typename ConvertIteratorTypeHelper<Iterator, ReturnType>::value_type;
using difference_type = typename AZStd::iterator_traits<Iterator>::difference_type;
using pointer = typename ConvertIteratorTypeHelper<Iterator, ReturnType>::pointer;
using reference = typename ConvertIteratorTypeHelper<Iterator, ReturnType>::reference;
using iterator_category = typename AZStd::iterator_traits<Iterator>::iterator_category;
using Function = typename ConvertIteratorTypeHelper<Iterator, ReturnType>::Function;
using RootIterator = ConvertIterator<Iterator, ReturnType, iterator_category>;
ConvertIterator(Iterator iterator, Function converter);
ConvertIterator(const ConvertIterator&) = default;
ConvertIterator& operator=(const ConvertIterator&) = default;
RootIterator& operator++();
RootIterator operator++(int);
const Iterator& GetBaseIterator();
protected:
Iterator m_iterator;
Function m_converter;
};
//
// input_iterator_tag
//
template<typename Iterator, typename ReturnType>
class ConvertIterator<Iterator, ReturnType, AZStd::input_iterator_tag>
: public ConvertIterator<Iterator, ReturnType, void>
{
public:
using super = ConvertIterator<Iterator, ReturnType, void>;
ConvertIterator(Iterator iterator, typename super::Function converter);
ConvertIterator(const ConvertIterator&) = default;
typename super::reference operator*() const;
typename super::pointer operator->() const;
bool operator==(const typename super::RootIterator& rhs) const;
bool operator!=(const typename super::RootIterator& rhs) const;
protected:
// Used for pointer casts that don't require an intermediate value.
typename super::pointer GetPointer(AZStd::true_type castablePointer) const;
// Used for pointer casts that require an intermediate proxy object.
typename super::pointer GetPointer(AZStd::false_type intermediateValue) const;
};
//
// forward_iterator_tag
//
template<typename Iterator, typename ReturnType>
class ConvertIterator<Iterator, ReturnType, AZStd::forward_iterator_tag>
: public ConvertIterator<Iterator, ReturnType, AZStd::input_iterator_tag>
{
public:
using super = ConvertIterator<Iterator, ReturnType, AZStd::input_iterator_tag>;
ConvertIterator(Iterator iterator, typename super::Function converter);
ConvertIterator(const ConvertIterator&) = default;
ConvertIterator();
};
//
// bidirectional_iterator_tag
//
template<typename Iterator, typename ReturnType>
class ConvertIterator<Iterator, ReturnType, AZStd::bidirectional_iterator_tag>
: public ConvertIterator<Iterator, ReturnType, AZStd::forward_iterator_tag>
{
public:
using super = ConvertIterator<Iterator, ReturnType, AZStd::forward_iterator_tag>;
ConvertIterator(Iterator iterator, typename super::Function converter);
ConvertIterator(const ConvertIterator&) = default;
ConvertIterator();
typename super::RootIterator& operator--();
typename super::RootIterator operator--(int);
};
//
// random_access_iterator_tag
//
template<typename Iterator, typename ReturnType>
class ConvertIterator<Iterator, ReturnType, AZStd::random_access_iterator_tag>
: public ConvertIterator<Iterator, ReturnType, AZStd::bidirectional_iterator_tag>
{
public:
using super = ConvertIterator<Iterator, ReturnType, AZStd::bidirectional_iterator_tag>;
ConvertIterator(Iterator iterator, typename super::Function converter);
ConvertIterator(const ConvertIterator&) = default;
ConvertIterator();
typename super::reference operator[](size_t index);
bool operator<(const typename super::RootIterator& rhs) const;
bool operator>(const typename super::RootIterator& rhs) const;
bool operator<=(const typename super::RootIterator& rhs) const;
bool operator>=(const typename super::RootIterator& rhs) const;
typename super::RootIterator operator+(size_t n) const;
typename super::RootIterator operator-(size_t n) const;
typename super::difference_type operator-(const typename super::RootIterator& rhs) const;
typename super::RootIterator& operator+=(size_t n);
typename super::RootIterator& operator-=(size_t n);
};
// contiguous_iterator_tag
template<typename Iterator, typename ReturnType>
class ConvertIterator<Iterator, ReturnType, AZStd::contiguous_iterator_tag>
: public ConvertIterator<Iterator, ReturnType, AZStd::random_access_iterator_tag>
{
public:
using super = ConvertIterator<Iterator, ReturnType, AZStd::random_access_iterator_tag>;
ConvertIterator(Iterator iterator, typename super::Function converter);
ConvertIterator(const ConvertIterator&) = default;
ConvertIterator();
};
// Utility functions
template<typename Iterator, typename Function>
ConvertIterator<Iterator, typename ConvertIteratorFunctionHelper<Iterator, Function>::ReturnType>
MakeConvertIterator(Iterator iterator, Function converter);
template<typename Iterator, typename Function>
View<ConvertIterator<Iterator, typename ConvertIteratorFunctionHelper<Iterator, Function>::ReturnType>>
MakeConvertView(Iterator begin, Iterator end, Function converter);
template<typename ViewType, typename Function>
View<ConvertIterator<typename ViewType::iterator, typename ConvertIteratorFunctionHelper<typename ViewType::iterator, Function>::ReturnType>>
MakeConvertView(ViewType& view, Function converter);
template<typename ViewType, typename Function>
View<ConvertIterator<typename ViewType::const_iterator, typename ConvertIteratorFunctionHelper<typename ViewType::const_iterator, Function>::ReturnType>>
MakeConvertView(const ViewType& view, Function converter);
} // Views
} // Containers
} // SceneAPI
} // AZ
#include <SceneAPI/SceneCore/Containers/Views/ConvertIterator.inl>
@@ -0,0 +1,277 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/Debug/Trace.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
//
// Base iterator
//
template<typename Iterator, typename ReturnType>
ConvertIterator<Iterator, ReturnType, void>::ConvertIterator(Iterator iterator, Function converter)
: m_iterator(iterator)
, m_converter(converter)
{
}
template<typename Iterator, typename ReturnType>
auto ConvertIterator<Iterator, ReturnType, void>::operator++()->RootIterator &
{
++m_iterator;
return *static_cast<RootIterator*>(this);
}
template<typename Iterator, typename ReturnType>
auto ConvertIterator<Iterator, ReturnType, void>::operator++(int)->RootIterator
{
RootIterator result = *static_cast<RootIterator*>(this);
++m_iterator;
return result;
}
template<typename Iterator, typename ReturnType>
const Iterator& ConvertIterator<Iterator, ReturnType, void>::GetBaseIterator()
{
return m_iterator;
}
//
// input_iterator_tag
//
template<typename Iterator, typename ReturnType>
ConvertIterator<Iterator, ReturnType, AZStd::input_iterator_tag>::ConvertIterator(Iterator iterator, typename super::Function converter)
: super(iterator, converter)
{
}
template<typename Iterator, typename ReturnType>
auto ConvertIterator<Iterator, ReturnType, AZStd::input_iterator_tag>::operator*() const->typename super::reference
{
AZ_Assert(super::m_converter, "No valid conversion function set for ConvertIterator.");
return super::m_converter(*super::m_iterator);
}
template<typename Iterator, typename ReturnType>
auto ConvertIterator<Iterator, ReturnType, AZStd::input_iterator_tag>::GetPointer(
[[maybe_unused]] AZStd::true_type castablePointer) const->typename super::pointer
{
AZ_Assert(super::m_converter, "No valid conversion function set for ConvertIterator.");
return &(super::m_converter(*super::m_iterator));
}
template<typename Iterator, typename ReturnType>
auto ConvertIterator<Iterator, ReturnType, AZStd::input_iterator_tag>::GetPointer(
[[maybe_unused]] AZStd::false_type intermediateValue) const->typename super::pointer
{
AZ_Assert(super::m_converter, "No valid conversion function set for ConvertIterator.");
return typename super::pointer(super::m_converter(*super::m_iterator));
}
template<typename Iterator, typename ReturnType>
auto ConvertIterator<Iterator, ReturnType, AZStd::input_iterator_tag>::operator->() const->typename super::pointer
{
return GetPointer(typename ConvertIteratorTypeHelper<Iterator, ReturnType>::PointerConditionType());
}
template<typename Iterator, typename ReturnType>
bool ConvertIterator<Iterator, ReturnType, AZStd::input_iterator_tag>::operator==(const typename super::RootIterator& rhs) const
{
return super::m_iterator == rhs.m_iterator;
}
template<typename Iterator, typename ReturnType>
bool ConvertIterator<Iterator, ReturnType, AZStd::input_iterator_tag>::operator!=(const typename super::RootIterator& rhs) const
{
return super::m_iterator != rhs.m_iterator;
}
//
// forward_iterator_tag
//
template<typename Iterator, typename ReturnType>
ConvertIterator<Iterator, ReturnType, AZStd::forward_iterator_tag>::ConvertIterator(Iterator iterator, typename super::Function converter)
: super(iterator, converter)
{
}
template<typename Iterator, typename ReturnType>
ConvertIterator<Iterator, ReturnType, AZStd::forward_iterator_tag>::ConvertIterator()
: super(Iterator(), nullptr)
{
}
//
// bidirectional_iterator_tag
//
template<typename Iterator, typename ReturnType>
ConvertIterator<Iterator, ReturnType, AZStd::bidirectional_iterator_tag>::ConvertIterator(Iterator iterator, typename super::Function converter)
: super(iterator, converter)
{
}
template<typename Iterator, typename ReturnType>
ConvertIterator<Iterator, ReturnType, AZStd::bidirectional_iterator_tag>::ConvertIterator()
: super()
{
}
template<typename Iterator, typename ReturnType>
auto ConvertIterator<Iterator, ReturnType, AZStd::bidirectional_iterator_tag>::operator--()->typename super::RootIterator &
{
--super::m_iterator;
return *static_cast<typename super::RootIterator*>(this);
}
template<typename Iterator, typename ReturnType>
auto ConvertIterator<Iterator, ReturnType, AZStd::bidirectional_iterator_tag>::operator--(int)->typename super::RootIterator
{
typename super::RootIterator result = *static_cast<typename super::RootIterator*>(this);
--super::m_iterator;
return result;
}
//
// random_access_iterator_tag
//
template<typename Iterator, typename ReturnType>
ConvertIterator<Iterator, ReturnType, AZStd::random_access_iterator_tag>::ConvertIterator(Iterator iterator, typename super::Function converter)
: super(iterator, converter)
{
}
template<typename Iterator, typename ReturnType>
ConvertIterator<Iterator, ReturnType, AZStd::random_access_iterator_tag>::ConvertIterator()
: super()
{
}
template<typename Iterator, typename ReturnType>
auto ConvertIterator<Iterator, ReturnType, AZStd::random_access_iterator_tag>::operator[](size_t index)->typename super::reference
{
AZ_Assert(super::m_converter, "No valid conversion function set for ConvertIterator.");
return super::m_converter(super::m_iterator[index]);
}
template<typename Iterator, typename ReturnType>
bool ConvertIterator<Iterator, ReturnType, AZStd::random_access_iterator_tag>::operator<(const typename super::RootIterator& rhs) const
{
return super::m_iterator < rhs.m_iterator;
}
template<typename Iterator, typename ReturnType>
bool ConvertIterator<Iterator, ReturnType, AZStd::random_access_iterator_tag>::operator>(const typename super::RootIterator& rhs) const
{
return super::m_iterator > rhs.m_iterator;
}
template<typename Iterator, typename ReturnType>
bool ConvertIterator<Iterator, ReturnType, AZStd::random_access_iterator_tag>::operator<=(const typename super::RootIterator& rhs) const
{
return super::m_iterator <= rhs.m_iterator;
}
template<typename Iterator, typename ReturnType>
bool ConvertIterator<Iterator, ReturnType, AZStd::random_access_iterator_tag>::operator>=(const typename super::RootIterator& rhs) const
{
return super::m_iterator >= rhs.m_iterator;
}
template<typename Iterator, typename ReturnType>
auto ConvertIterator<Iterator, ReturnType, AZStd::random_access_iterator_tag>::operator+(size_t n) const->typename super::RootIterator
{
typename super::RootIterator result = *static_cast<const typename super::RootIterator*>(this);
result.m_iterator += n;
return result;
}
template<typename Iterator, typename ReturnType>
auto ConvertIterator<Iterator, ReturnType, AZStd::random_access_iterator_tag>::operator-(size_t n) const->typename super::RootIterator
{
typename super::RootIterator result = *static_cast<const typename super::RootIterator*>(this);
result.m_iterator -= n;
return result;
}
template<typename Iterator, typename ReturnType>
auto ConvertIterator<Iterator, ReturnType, AZStd::random_access_iterator_tag>::operator-(const typename super::RootIterator& rhs) const->typename super::difference_type
{
return super::m_iterator - rhs.m_iterator;
}
template<typename Iterator, typename ReturnType>
auto ConvertIterator<Iterator, ReturnType, AZStd::random_access_iterator_tag>::operator+=(size_t n)->typename super::RootIterator &
{
super::m_iterator += n;
return *static_cast<typename super::RootIterator*>(this);
}
template<typename Iterator, typename ReturnType>
auto ConvertIterator<Iterator, ReturnType, AZStd::random_access_iterator_tag>::operator-=(size_t n)->typename super::RootIterator &
{
super::m_iterator -= n;
return *static_cast<typename super::RootIterator*>(this);
}
//
// contiguous_iterator_tag
//
template<typename Iterator, typename ReturnType>
ConvertIterator<Iterator, ReturnType, AZStd::contiguous_iterator_tag>::ConvertIterator(Iterator iterator, typename super::Function converter)
: super(iterator, converter)
{
}
template<typename Iterator, typename ReturnType>
ConvertIterator<Iterator, ReturnType, AZStd::contiguous_iterator_tag>::ConvertIterator()
: super()
{
}
// Utility functions
template<typename Iterator, typename Function>
ConvertIterator<Iterator, typename ConvertIteratorFunctionHelper<Iterator, Function>::ReturnType>
MakeConvertIterator(Iterator iterator, Function converter)
{
using ReturnType = typename ConvertIteratorFunctionHelper<Iterator, Function>::ReturnType;
return ConvertIterator<Iterator, ReturnType>(iterator, converter);
}
template<typename Iterator, typename Function>
View<ConvertIterator<Iterator, typename ConvertIteratorFunctionHelper<Iterator, Function>::ReturnType>>
MakeConvertView(Iterator begin, Iterator end, Function converter)
{
using ReturnType = typename ConvertIteratorFunctionHelper<Iterator, Function>::ReturnType;
return View<ConvertIterator<Iterator, ReturnType>>(
MakeConvertIterator(begin, converter),
MakeConvertIterator(end, converter));
}
template<typename ViewType, typename Function>
View<ConvertIterator<typename ViewType::iterator, typename ConvertIteratorFunctionHelper<typename ViewType::iterator, Function>::ReturnType>>
MakeConvertView(ViewType& view, Function converter)
{
return MakeConvertView(view.begin(), view.end(), converter);
}
template<typename ViewType, typename Function>
View<ConvertIterator<typename ViewType::const_iterator, typename ConvertIteratorFunctionHelper<typename ViewType::const_iterator, Function>::ReturnType>>
MakeConvertView(const ViewType& view, Function converter)
{
return MakeConvertView(view.begin(), view.end(), converter);
}
} // Views
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,244 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/std/utils.h>
#include <AzCore/std/iterator.h>
#include <AzCore/std/functional.h>
#include <AzCore/std/typetraits/is_base_of.h>
#include <SceneAPI/SceneCore/Containers/Views/View.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
// Skips values in the iterator it wraps based on a given function's result.
// The predicate function takes the reference of the value of iterator as its
// argument and must return a boolean, where true means to accept the given
// iterator value and false if FilterIterator needs to skip to the next value.
// For complex iterators it's often easier to use decltype to derive the argument
// to the predicate function instead of fully specifying it. (See example below)
// Note:
// Because skipping happens while iterating, random access iterators will degrade
// to bidirectional iterators.
// Example:
// vector<int> list = { 10, 20, 30, 40, 50 };
// auto view = MakeFilterView(list.begin(), list.end(),
// [](int value) -> bool
// {
// return value >= 25;
// });
// for (auto it : view)
// {
// printf( "%i ", it );
// }
// result: 30 40 50
// Example:
// vector<int> list = { 10, 20, 30, 40, 50 };
// auto convertView = MakeConvertView<uint64_t>(list.begin(), list.end());
// auto filteredView = MakeFilterView(convertView,
// // Easier to read and automatically reflects any changes made in the view stack.
// [](const decltype(*convertView.begin())& object) -> bool
// {
// return value >= 25;
// });
template<typename Iterator, typename Category = typename AZStd::iterator_traits<Iterator>::iterator_category>
class FilterIterator
{
};
//
// Base iterator
//
template<typename Iterator>
class FilterIterator<Iterator, void>
{
public:
using value_type = typename AZStd::iterator_traits<Iterator>::value_type;
using difference_type = typename AZStd::iterator_traits<Iterator>::difference_type;
using pointer = typename AZStd::iterator_traits<Iterator>::pointer;
using reference = typename AZStd::iterator_traits<Iterator>::reference;
using iterator_category = typename AZStd::iterator_traits<Iterator>::iterator_category;
using RootIterator = FilterIterator<Iterator, iterator_category>;
using Predicate = AZStd::function<bool(const reference)>;
FilterIterator(Iterator iterator, Iterator end, const Predicate& predicate);
FilterIterator(const FilterIterator&) = default;
FilterIterator& operator=(const FilterIterator&) = default;
RootIterator& operator++();
RootIterator operator++(int);
const Iterator& GetBaseIterator();
protected:
// Pseudo default constructor.
// This is used because default constructing later on would trigger a predicate
// on an default constructed iterator, causing a crash when either using the
// predicate or dereferencing the iterator when trying to move forward.
explicit FilterIterator(Iterator defaultIterator);
void MoveToNext();
Iterator m_iterator;
Iterator m_end;
Predicate m_predicate;
};
//
// Input iterator
//
template<typename Iterator>
class FilterIterator<Iterator, AZStd::input_iterator_tag>
: public FilterIterator<Iterator, void>
{
public:
using super = FilterIterator<Iterator, void>;
FilterIterator(Iterator iterator, Iterator end, const typename super::Predicate& predicate);
FilterIterator(const FilterIterator& rhs) = default;
bool operator==(const typename super::RootIterator& rhs) const;
bool operator!=(const typename super::RootIterator& rhs) const;
typename super::reference operator*() const;
typename super::pointer operator->() const;
protected:
// Used when iterator is raw pointer
typename super::pointer GetPointer(AZStd::true_type) const;
// Used when iterator is an object
typename super::pointer GetPointer(AZStd::false_type) const;
// Pseudo default constructor.
explicit FilterIterator(Iterator defaultIterator);
};
//
// Forward iterator
//
template<typename Iterator>
class FilterIterator<Iterator, AZStd::forward_iterator_tag>
: public FilterIterator<Iterator, AZStd::input_iterator_tag>
{
public:
using super = FilterIterator<Iterator, AZStd::input_iterator_tag>;
FilterIterator(Iterator iterator, Iterator end, const typename super::Predicate& predicate);
FilterIterator(const FilterIterator& rhs) = default;
FilterIterator();
};
//
// Bidirectional iterator
//
template<typename Iterator>
class FilterIterator<Iterator, AZStd::bidirectional_iterator_tag>
: public FilterIterator<Iterator, AZStd::forward_iterator_tag>
{
public:
using super = FilterIterator<Iterator, AZStd::forward_iterator_tag>;
FilterIterator(Iterator iterator, Iterator end, const typename super::Predicate& predicate);
FilterIterator(Iterator iterator, Iterator begin, Iterator end, const typename super::Predicate& predicate);
FilterIterator(const FilterIterator& rhs) = default;
FilterIterator();
typename super::RootIterator& operator--();
typename super::RootIterator operator--(int);
protected:
void MoveToPrevious();
Iterator m_begin;
};
//
// Random Access iterator
// Because individual elements have to be inspected to know if they should be accepted, treat the random access iterator
// as a bidirectional iterator to force algorithms to inspect individual elements.
//
template<typename Iterator>
class FilterIterator<Iterator, AZStd::random_access_iterator_tag>
: public FilterIterator<Iterator, AZStd::bidirectional_iterator_tag>
{
public:
using super = FilterIterator<Iterator, AZStd::bidirectional_iterator_tag>;
using iterator_category = AZStd::bidirectional_iterator_tag;
FilterIterator(Iterator iterator, Iterator end, const typename super::Predicate& predicate);
FilterIterator(Iterator iterator, Iterator begin, Iterator end, const typename super::Predicate& predicate);
FilterIterator(const FilterIterator& rhs) = default;
FilterIterator();
};
//
// Contiguous Random Access iterator
// See Random Access iterator
//
template<typename Iterator>
class FilterIterator<Iterator, AZStd::contiguous_iterator_tag>
: public FilterIterator<Iterator, AZStd::bidirectional_iterator_tag>
{
public:
using super = FilterIterator<Iterator, AZStd::bidirectional_iterator_tag>;
using iterator_category = AZStd::bidirectional_iterator_tag;
FilterIterator(Iterator iterator, Iterator end, const typename super::Predicate& predicate);
FilterIterator(Iterator iterator, Iterator begin, Iterator end, const typename super::Predicate& predicate);
FilterIterator(const FilterIterator& rhs) = default;
FilterIterator();
};
//
// Utility functions
//
namespace Internal
{
template<typename Iterator>
struct FilterIteratorNeedsFullRange
{
// True if the Iterator can move backwards, which requires an end and a begin iterator, otherwise false and only
// an end iterator is needed.
static const bool value = AZStd::is_base_of<AZStd::bidirectional_iterator_tag, typename Iterator::iterator_category>::value;
};
}
template<typename Iterator>
FilterIterator<Iterator> MakeFilterIterator(Iterator current, Iterator end, const typename FilterIterator<Iterator, void>::Predicate& predicate);
template<typename Iterator, typename AZStd::enable_if<Internal::FilterIteratorNeedsFullRange<Iterator>::value>::type>
FilterIterator<Iterator> MakeFilterIterator(Iterator current, Iterator begin, Iterator end, const typename FilterIterator<Iterator, void>::Predicate& predicate);
template<typename Iterator>
View<FilterIterator<Iterator> > MakeFilterView(Iterator current, Iterator end, const typename FilterIterator<Iterator, void>::Predicate& predicate);
template<typename Iterator, typename AZStd::enable_if<Internal::FilterIteratorNeedsFullRange<Iterator>::value>::type>
View<FilterIterator<Iterator> > MakeFilterView(Iterator current, Iterator begin, Iterator end, const typename FilterIterator<Iterator>::Predicate& predicate);
template<typename ViewType>
View<FilterIterator<typename ViewType::iterator> > MakeFilterView(ViewType& view, const typename FilterIterator<typename ViewType::iterator>::Predicate& predicate);
template<typename ViewType>
const View<FilterIterator<typename ViewType::const_iterator> > MakeFilterView(const ViewType& view, const typename FilterIterator<typename ViewType::const_iterator>::Predicate& predicate);
} // Views
} // Containers
} // SceneAPI
} // AZ
#include <SceneAPI/SceneCore/Containers/Views/FilterIterator.inl>
@@ -0,0 +1,316 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/std/typetraits/is_pointer.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
//
// Base iterator
//
template<typename Iterator>
FilterIterator<Iterator, void>::FilterIterator(Iterator iterator, Iterator end, const Predicate& predicate)
: m_iterator(iterator)
, m_end(end)
, m_predicate(predicate)
{
while (m_iterator != m_end && !m_predicate(*m_iterator))
{
AZStd::advance(m_iterator, 1);
}
}
template<typename Iterator>
FilterIterator<Iterator, void>::FilterIterator(Iterator defaultIterator)
: m_iterator(defaultIterator)
, m_end(defaultIterator)
, m_predicate()
{
}
template<typename Iterator>
auto FilterIterator<Iterator, void>::operator++()->RootIterator &
{
MoveToNext();
return *static_cast<RootIterator*>(this);
}
template<typename Iterator>
auto FilterIterator<Iterator, void>::operator++(int)->RootIterator
{
RootIterator result = *static_cast<RootIterator*>(this);
MoveToNext();
return result;
}
template<typename Iterator>
auto FilterIterator<Iterator, void>::GetBaseIterator()->const Iterator&
{
return m_iterator;
}
template<typename Iterator>
void FilterIterator<Iterator, void>::MoveToNext()
{
if (m_iterator != m_end)
{
AZStd::advance(m_iterator, 1);
}
while (m_iterator != m_end && !m_predicate(*m_iterator))
{
AZStd::advance(m_iterator, 1);
}
}
//
// Input iterator
//
template<typename Iterator>
FilterIterator<Iterator, AZStd::input_iterator_tag>::FilterIterator(Iterator iterator, Iterator end, const typename super::Predicate& predicate)
: super(iterator, end, predicate)
{
}
template<typename Iterator>
FilterIterator<Iterator, AZStd::input_iterator_tag>::FilterIterator(Iterator defaultIterator)
: super(defaultIterator)
{
}
template<typename Iterator>
bool FilterIterator<Iterator, AZStd::input_iterator_tag>::operator==(const typename super::RootIterator& rhs) const
{
return super::m_iterator == rhs.m_iterator;
}
template<typename Iterator>
bool FilterIterator<Iterator, AZStd::input_iterator_tag>::operator!=(const typename super::RootIterator& rhs) const
{
return super::m_iterator != rhs.m_iterator;
}
template<typename Iterator>
auto FilterIterator<Iterator, AZStd::input_iterator_tag>::operator*() const->typename super::reference
{
return static_cast<typename super::reference>(*super::m_iterator);
}
// Used when iterator is raw pointer
template<typename Iterator>
auto FilterIterator<Iterator, AZStd::input_iterator_tag>::GetPointer(AZStd::true_type) const->typename super::pointer
{
return super::m_iterator;
}
// Used when iterator is an object
template<typename Iterator>
auto FilterIterator<Iterator, AZStd::input_iterator_tag>::GetPointer(AZStd::false_type) const->typename super::pointer
{
return super::m_iterator.operator->();
}
template<typename Iterator>
auto FilterIterator<Iterator, AZStd::input_iterator_tag>::operator->() const->typename super::pointer
{
return GetPointer(typename AZStd::is_pointer<Iterator>::type());
}
//
// Forward iterator
//
template<typename Iterator>
FilterIterator<Iterator, AZStd::forward_iterator_tag>::FilterIterator(Iterator iterator, Iterator end, const typename super::Predicate& predicate)
: super(iterator, end, predicate)
{
}
template<typename Iterator>
FilterIterator<Iterator, AZStd::forward_iterator_tag>::FilterIterator()
: super(Iterator())
{
}
//
// Bidirectional iterator
//
template<typename Iterator>
FilterIterator<Iterator, AZStd::bidirectional_iterator_tag>::FilterIterator(Iterator iterator, Iterator end, const typename super::Predicate& predicate)
: super(iterator, end, predicate)
{
// Matches the iterator that's been moved forward to the first element that passes the predicate.
m_begin = super::m_iterator;
}
template<typename Iterator>
FilterIterator<Iterator, AZStd::bidirectional_iterator_tag>::FilterIterator(Iterator iterator, Iterator begin, Iterator end, const typename super::Predicate& predicate)
: super(iterator, end, predicate)
, m_begin(begin)
{
while (m_begin != super::m_end && !super::m_predicate(*m_begin))
{
AZStd::advance(m_begin, 1);
}
}
template<typename Iterator>
FilterIterator<Iterator, AZStd::bidirectional_iterator_tag>::FilterIterator()
: super()
{
}
template<typename Iterator>
auto FilterIterator<Iterator, AZStd::bidirectional_iterator_tag>::operator--()->typename super::RootIterator &
{
MoveToPrevious();
return *static_cast<typename super::RootIterator*>(this);
}
template<typename Iterator>
auto FilterIterator<Iterator, AZStd::bidirectional_iterator_tag>::operator--(int)->typename super::RootIterator
{
typename super::RootIterator result = *static_cast<typename super::RootIterator*>(this);
MoveToPrevious();
return result;
}
template<typename Iterator>
void FilterIterator<Iterator, AZStd::bidirectional_iterator_tag>::MoveToPrevious()
{
if (super::m_iterator != m_begin)
{
AZStd::advance(super::m_iterator, -1);
}
while (super::m_iterator != m_begin && !super::m_predicate(*super::m_iterator))
{
AZStd::advance(super::m_iterator, -1);
}
}
//
// Random Access iterator
//
template<typename Iterator>
FilterIterator<Iterator, AZStd::random_access_iterator_tag>::FilterIterator(Iterator iterator, Iterator end, const typename super::Predicate& predicate)
: super(iterator, end, predicate)
{
}
template<typename Iterator>
FilterIterator<Iterator, AZStd::random_access_iterator_tag>::FilterIterator(Iterator iterator, Iterator begin, Iterator end, const typename super::Predicate& predicate)
: super(iterator, begin, end, predicate)
{
}
template<typename Iterator>
FilterIterator<Iterator, AZStd::random_access_iterator_tag>::FilterIterator()
: super()
{
}
//
// Continuous Random Access iterator
//
template<typename Iterator>
FilterIterator<Iterator, AZStd::contiguous_iterator_tag>::FilterIterator(
Iterator iterator, Iterator end, const typename super::Predicate& predicate)
: super(iterator, end, predicate)
{
}
template<typename Iterator>
FilterIterator<Iterator, AZStd::contiguous_iterator_tag>::FilterIterator(
Iterator iterator, Iterator begin, Iterator end, const typename super::Predicate& predicate)
: super(iterator, begin, end, predicate)
{
}
template<typename Iterator>
FilterIterator<Iterator, AZStd::contiguous_iterator_tag>::FilterIterator()
: super()
{
}
//
// Utility functions
//
namespace Internal
{
template<typename Iterator>
View<FilterIterator<Iterator> > MakeFilterView(Iterator current, Iterator end,
const typename FilterIterator<Iterator>::Predicate& predicate, AZStd::false_type)
{
return View<FilterIterator<Iterator> >(
FilterIterator<Iterator>(current, end, predicate),
FilterIterator<Iterator>(end, end, predicate));
}
template<typename Iterator>
View<FilterIterator<Iterator> > MakeFilterView(Iterator current, Iterator end,
const typename FilterIterator<Iterator>::Predicate& predicate, AZStd::true_type)
{
return View<FilterIterator<Iterator> >(
FilterIterator<Iterator>(current, current, end, predicate),
FilterIterator<Iterator>(end, current, end, predicate));
}
}
template<typename Iterator>
FilterIterator<Iterator> MakeFilterIterator(Iterator current, Iterator end, const typename FilterIterator<Iterator, void>::Predicate& predicate)
{
return FilterIterator<Iterator>(current, end, predicate);
}
template<typename Iterator, typename AZStd::enable_if<Internal::FilterIteratorNeedsFullRange<Iterator>::value>::type>
FilterIterator<Iterator> MakeFilterIterator(Iterator current, Iterator begin, Iterator end, const typename FilterIterator<Iterator, void>::Predicate& predicate)
{
return FilterIterator<Iterator>(current, begin, end, predicate);
}
template<typename Iterator>
View<FilterIterator<Iterator> > MakeFilterView(Iterator current, Iterator end, const typename FilterIterator<Iterator, void>::Predicate& predicate)
{
return Internal::MakeFilterView(current, end, predicate,
typename AZStd::is_base_of<AZStd::bidirectional_iterator_tag, typename AZStd::iterator_traits<Iterator>::iterator_category>::type());
}
template<typename Iterator, typename AZStd::enable_if<Internal::FilterIteratorNeedsFullRange<Iterator>::value>::type>
View<FilterIterator<Iterator> > MakeFilterView(Iterator current, Iterator begin, Iterator end, const typename FilterIterator<Iterator>::Predicate& predicate)
{
return View<FilterIterator<Iterator> >(
FilterIterator<Iterator>(current, begin, end, predicate),
FilterIterator<Iterator>(end, begin, end, predicate));
}
template<typename ViewType>
View<FilterIterator<typename ViewType::iterator> > MakeFilterView(ViewType& view, const typename FilterIterator<typename ViewType::iterator>::Predicate& predicate)
{
return MakeFilterView(view.begin(), view.end(), predicate);
}
template<typename ViewType>
const View<FilterIterator<typename ViewType::const_iterator> > MakeFilterView(const ViewType& view, const typename FilterIterator<typename ViewType::const_iterator>::Predicate& predicate)
{
return MakeFilterView(view.begin(), view.end(), predicate);
}
} // Views
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,249 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <utility>
#include <AzCore/std/utils.h>
#include <AzCore/std/typetraits/is_same.h>
#include <AzCore/std/typetraits/is_base_of.h>
#include <AzCore/std/iterator.h>
#include <SceneAPI/SceneCore/Containers/Views/View.h>
#include <SceneAPI/SceneCore/Containers/Utilities/ProxyPointer.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
// Merges two iterators together that have a pair relation.
// Both iterators must point to the same relative entry and must contain
// the same amount of remaining increments (and decrements if appropriate).
// If the categories of the given iterators differ the PairIterator
// will only support functionality shared between them. The categories
// must be implementations of or be related to the categories defined by
// the C++ standard.
// Example:
// vector<string> names;
// vector<int> values;
// auto view = MakePairView(names.begin(), names.end(), values.begin(), values.end());
// for(auto it : view)
// {
// printf("%s has value %i\n", it.first.c_str(), it.second);
// }
namespace Internal
{
template<typename FirstIterator, typename SecondIterator>
struct PairIteratorCategory
{
static const bool s_sameCategory = AZStd::is_same<
typename AZStd::iterator_traits<FirstIterator>::iterator_category,
typename AZStd::iterator_traits<SecondIterator>::iterator_category>::value;
// True if both categories are the same.
// True if FirstIterator has the lower category in the hierarchy
// False if ValueItator has the lower category or is unrelated.
static const bool s_firstIteratorCategoryIsBaseOfSecondIterator = AZStd::is_base_of<
typename AZStd::iterator_traits<FirstIterator>::iterator_category,
typename AZStd::iterator_traits<SecondIterator>::iterator_category>::value;
// True if both categories are the same.
// True if SecondIterator has the lower category in the hierarchy
// False if FirstItator has the lower category or is unrelated.
static const bool s_SecondIteratorCategoryIsBaseOfFirstIterator = AZStd::is_base_of<
typename AZStd::iterator_traits<SecondIterator>::iterator_category,
typename AZStd::iterator_traits<FirstIterator>::iterator_category>::value;
static_assert(s_sameCategory || (s_firstIteratorCategoryIsBaseOfSecondIterator != s_SecondIteratorCategoryIsBaseOfFirstIterator),
"The iterator categories for the first and second in the PairIterator are unrelated categories.");
using Category = typename AZStd::conditional<s_firstIteratorCategoryIsBaseOfSecondIterator,
typename AZStd::iterator_traits<FirstIterator>::iterator_category,
typename AZStd::iterator_traits<SecondIterator>::iterator_category>::type;
};
}
template<typename FirstIterator, typename SecondIterator,
typename Category = typename Internal::PairIteratorCategory<FirstIterator, SecondIterator>::Category>
class PairIterator
{
};
//
// Base iterator
//
template<typename FirstIterator, typename SecondIterator>
class PairIterator<FirstIterator, SecondIterator, void>
{
public:
using value_type = AZStd::pair<typename AZStd::iterator_traits<FirstIterator>::value_type, typename AZStd::iterator_traits<SecondIterator>::value_type>;
using difference_type = AZStd::ptrdiff_t;
using reference = AZStd::pair<typename AZStd::iterator_traits<FirstIterator>::reference, typename AZStd::iterator_traits<SecondIterator>::reference>;
using pointer = ProxyPointer<reference>;
using iterator_category = typename Internal::PairIteratorCategory<FirstIterator, SecondIterator>::Category;
using RootIterator = PairIterator<FirstIterator, SecondIterator, iterator_category>;
PairIterator(FirstIterator First, SecondIterator second);
PairIterator(const PairIterator&) = default;
PairIterator& operator=(const PairIterator&) = default;
RootIterator& operator++();
RootIterator operator++(int);
const FirstIterator& GetFirstIterator();
const SecondIterator& GetSecondIterator();
protected:
FirstIterator m_first;
SecondIterator m_second;
};
//
// Input iterator
//
template<typename FirstIterator, typename SecondIterator>
class PairIterator<FirstIterator, SecondIterator, AZStd::input_iterator_tag>
: public PairIterator<FirstIterator, SecondIterator, void>
{
public:
using super = PairIterator<FirstIterator, SecondIterator, void>;
PairIterator(FirstIterator first, SecondIterator second);
PairIterator(const PairIterator& rhs) = default;
bool operator==(const typename super::RootIterator& rhs) const;
bool operator!=(const typename super::RootIterator& rhs) const;
typename super::reference operator*() const;
typename super::pointer operator->() const;
};
//
// Forward iterator
//
template<typename FirstIterator, typename SecondIterator>
class PairIterator<FirstIterator, SecondIterator, AZStd::forward_iterator_tag>
: public PairIterator<FirstIterator, SecondIterator, AZStd::input_iterator_tag>
{
public:
using super = PairIterator<FirstIterator, SecondIterator, AZStd::input_iterator_tag>;
PairIterator(FirstIterator first, SecondIterator second);
PairIterator(const PairIterator& rhs) = default;
PairIterator();
};
//
// Bidirectional iterator
//
template<typename FirstIterator, typename SecondIterator>
class PairIterator<FirstIterator, SecondIterator, AZStd::bidirectional_iterator_tag>
: public PairIterator<FirstIterator, SecondIterator, AZStd::forward_iterator_tag>
{
public:
using super = PairIterator<FirstIterator, SecondIterator, AZStd::forward_iterator_tag>;
PairIterator(FirstIterator first, SecondIterator second);
PairIterator(const PairIterator& rhs) = default;
PairIterator();
typename super::RootIterator& operator--();
typename super::RootIterator operator--(int);
};
//
// Random Access iterator
//
template<typename FirstIterator, typename SecondIterator>
class PairIterator<FirstIterator, SecondIterator, AZStd::random_access_iterator_tag>
: public PairIterator<FirstIterator, SecondIterator, AZStd::bidirectional_iterator_tag>
{
public:
using super = PairIterator<FirstIterator, SecondIterator, AZStd::bidirectional_iterator_tag>;
PairIterator(FirstIterator first, SecondIterator second);
PairIterator(const PairIterator& rhs) = default;
PairIterator();
typename super::reference operator[](size_t index);
bool operator<(const typename super::RootIterator& rhs) const;
bool operator>(const typename super::RootIterator& rhs) const;
bool operator<=(const typename super::RootIterator& rhs) const;
bool operator>=(const typename super::RootIterator& rhs) const;
typename super::RootIterator operator+(size_t n) const;
typename super::RootIterator operator-(size_t n) const;
typename super::difference_type operator-(const typename super::RootIterator& rhs) const;
typename super::RootIterator& operator+=(size_t n);
typename super::RootIterator& operator-=(size_t n);
};
//
// Contiguous Random Access iterator
//
template<typename FirstIterator, typename SecondIterator>
class PairIterator<FirstIterator, SecondIterator, AZStd::contiguous_iterator_tag>
: public PairIterator<FirstIterator, SecondIterator, AZStd::random_access_iterator_tag>
{
public:
using super = PairIterator<FirstIterator, SecondIterator, AZStd::random_access_iterator_tag>;
PairIterator(FirstIterator first, SecondIterator second);
PairIterator(const PairIterator& rhs) = default;
PairIterator();
};
//
// Utility functions
//
template<typename FirstIterator, typename SecondIterator>
PairIterator<FirstIterator, SecondIterator> MakePairIterator(FirstIterator first, SecondIterator second);
template<typename FirstIterator, typename SecondIterator>
View<PairIterator<FirstIterator, SecondIterator>>
MakePairView(FirstIterator firstBegin, FirstIterator firstEnd, SecondIterator secondBegin, SecondIterator secondEnd);
template<typename FirstView, typename SecondView>
View<PairIterator<typename FirstView::iterator, typename SecondView::iterator>>
MakePairView(FirstView& firstView, SecondView& secondView);
template<typename FirstView, typename SecondView>
View<PairIterator<typename FirstView::const_iterator, typename SecondView::iterator>>
MakePairView(const FirstView& firstView, SecondView& secondView);
template<typename FirstView, typename SecondView>
View<PairIterator<typename FirstView::iterator, typename SecondView::const_iterator>>
MakePairView(FirstView& firstView, const SecondView& secondView);
template<typename FirstView, typename SecondView>
View<PairIterator<typename FirstView::const_iterator, typename SecondView::const_iterator>>
MakePairView(const FirstView& firstView, const SecondView& secondView);
} // Views
} // Containers
} // SceneAPI
} // AZ
namespace AZStd
{
// iterator swap
template<typename First, typename Second>
void iter_swap(AZ::SceneAPI::Containers::Views::PairIterator<First, Second> lhs, AZ::SceneAPI::Containers::Views::PairIterator<First, Second> rhs);
}
#include <SceneAPI/SceneCore/Containers/Views/PairIterator.inl>
@@ -0,0 +1,318 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/Debug/Trace.h>
#include <AzCore/std/typetraits/remove_pointer.h>
#include <AzCore/std/typetraits/remove_reference.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
//
// Base iterator
//
template<typename FirstIterator, typename SecondIterator>
PairIterator<FirstIterator, SecondIterator, void>::PairIterator(FirstIterator first, SecondIterator second)
: m_first(first)
, m_second(second)
{
}
template<typename FirstIterator, typename SecondIterator>
auto PairIterator<FirstIterator, SecondIterator, void>::operator++()->RootIterator &
{
++m_first;
++m_second;
return *static_cast<RootIterator*>(this);
}
template<typename FirstIterator, typename SecondIterator>
auto PairIterator<FirstIterator, SecondIterator, void>::operator++(int)->RootIterator
{
RootIterator result = *static_cast<RootIterator*>(this);
++m_first;
++m_second;
return result;
}
template<typename FirstIterator, typename SecondIterator>
auto PairIterator<FirstIterator, SecondIterator, void>::GetFirstIterator()->const FirstIterator&
{
return m_first;
}
template<typename FirstIterator, typename SecondIterator>
auto PairIterator<FirstIterator, SecondIterator, void>::GetSecondIterator()->const SecondIterator&
{
return m_second;
}
//
// Input iterator
//
template<typename FirstIterator, typename SecondIterator>
PairIterator<FirstIterator, SecondIterator, AZStd::input_iterator_tag>::PairIterator(FirstIterator first, SecondIterator second)
: super(first, second)
{
}
template<typename FirstIterator, typename SecondIterator>
bool PairIterator<FirstIterator, SecondIterator, AZStd::input_iterator_tag>::operator==(const typename super::RootIterator& rhs) const
{
return super::m_first == rhs.m_first && super::m_second == rhs.m_second;
}
template<typename FirstIterator, typename SecondIterator>
bool PairIterator<FirstIterator, SecondIterator, AZStd::input_iterator_tag>::operator!=(const typename super::RootIterator& rhs) const
{
return super::m_first != rhs.m_first || super::m_second != rhs.m_second;
}
template<typename FirstIterator, typename SecondIterator>
auto PairIterator<FirstIterator, SecondIterator, AZStd::input_iterator_tag>::operator*() const ->typename super::reference
{
return typename super::reference(*super::m_first, *super::m_second);
}
template<typename FirstIterator, typename SecondIterator>
auto PairIterator<FirstIterator, SecondIterator, AZStd::input_iterator_tag>::operator->() const ->typename super::pointer
{
return typename super::pointer(operator*());
}
//
// Forward iterator
//
template<typename FirstIterator, typename SecondIterator>
PairIterator<FirstIterator, SecondIterator, AZStd::forward_iterator_tag>::PairIterator(FirstIterator first, SecondIterator second)
: super(first, second)
{
}
template<typename FirstIterator, typename SecondIterator>
PairIterator<FirstIterator, SecondIterator, AZStd::forward_iterator_tag>::PairIterator()
: super(FirstIterator(), SecondIterator())
{
}
//
// Bidirectional iterator
//
template<typename FirstIterator, typename SecondIterator>
PairIterator<FirstIterator, SecondIterator, AZStd::bidirectional_iterator_tag>::PairIterator(FirstIterator first, SecondIterator second)
: super(first, second)
{
}
template<typename FirstIterator, typename SecondIterator>
PairIterator<FirstIterator, SecondIterator, AZStd::bidirectional_iterator_tag>::PairIterator()
: super()
{
}
template<typename FirstIterator, typename SecondIterator>
auto PairIterator<FirstIterator, SecondIterator, AZStd::bidirectional_iterator_tag>::operator--()->typename super::RootIterator &
{
--super::m_first;
--super::m_second;
return *static_cast<typename super::RootIterator*>(this);
}
template<typename FirstIterator, typename SecondIterator>
auto PairIterator<FirstIterator, SecondIterator, AZStd::bidirectional_iterator_tag>::operator--(int)->typename super::RootIterator
{
typename super::RootIterator result = *static_cast<typename super::RootIterator*>(this);
--super::m_first;
--super::m_second;
return result;
}
//
// Random Access iterator
//
template<typename FirstIterator, typename SecondIterator>
PairIterator<FirstIterator, SecondIterator, AZStd::random_access_iterator_tag>::PairIterator(FirstIterator first, SecondIterator second)
: super(first, second)
{
}
template<typename FirstIterator, typename SecondIterator>
PairIterator<FirstIterator, SecondIterator, AZStd::random_access_iterator_tag>::PairIterator()
: super()
{
}
template<typename FirstIterator, typename SecondIterator>
auto PairIterator<FirstIterator, SecondIterator, AZStd::random_access_iterator_tag>::operator[](size_t index)->typename super::reference
{
return typename super::reference(super::m_first[index], super::m_second[index]);
}
template<typename FirstIterator, typename SecondIterator>
bool IsSmaller(const FirstIterator& lhsFirst, const FirstIterator& lhsSecond, const SecondIterator& rhsFirst, const SecondIterator& rhsSecond)
{
return (lhsFirst < rhsFirst || (!(rhsFirst < lhsFirst) && lhsSecond < rhsSecond));
}
template<typename FirstIterator, typename SecondIterator>
bool PairIterator<FirstIterator, SecondIterator, AZStd::random_access_iterator_tag>::operator<(const typename super::RootIterator& rhs) const
{
return IsSmaller(super::m_first, super::m_second, rhs.m_first, rhs.m_second);
}
template<typename FirstIterator, typename SecondIterator>
bool PairIterator<FirstIterator, SecondIterator, AZStd::random_access_iterator_tag>::operator>(const typename super::RootIterator& rhs) const
{
return IsSmaller(rhs.m_first, rhs.m_second, super::m_first, super::m_second);
}
template<typename FirstIterator, typename SecondIterator>
bool PairIterator<FirstIterator, SecondIterator, AZStd::random_access_iterator_tag>::operator<=(const typename super::RootIterator& rhs) const
{
return !IsSmaller(rhs.m_first, rhs.m_second, super::m_first, super::m_second);
}
template<typename FirstIterator, typename SecondIterator>
bool PairIterator<FirstIterator, SecondIterator, AZStd::random_access_iterator_tag>::operator>=(const typename super::RootIterator& rhs) const
{
return !IsSmaller(super::m_first, super::m_second, rhs.m_first, rhs.m_second);
}
template<typename FirstIterator, typename SecondIterator>
auto PairIterator<FirstIterator, SecondIterator, AZStd::random_access_iterator_tag>::operator+(size_t n) const->typename super::RootIterator
{
typename super::RootIterator result = *static_cast<const typename super::RootIterator*>(this);
result.m_first += n;
result.m_second += n;
return result;
}
template<typename FirstIterator, typename SecondIterator>
auto PairIterator<FirstIterator, SecondIterator, AZStd::random_access_iterator_tag>::operator-(size_t n) const->typename super::RootIterator
{
typename super::RootIterator result = *static_cast<const typename super::RootIterator*>(this);
result.m_first -= n;
result.m_second -= n;
return result;
}
template<typename FirstIterator, typename SecondIterator>
auto PairIterator<FirstIterator, SecondIterator, AZStd::random_access_iterator_tag>::operator-(const typename super::RootIterator& rhs) const->typename super::difference_type
{
typename super::difference_type result = super::m_first - rhs.m_first;
AZ_Assert((super::m_second - rhs.m_second) == result, "First and second in PairIterator have gone out of lockstep.");
return result;
}
template<typename FirstIterator, typename SecondIterator>
auto PairIterator<FirstIterator, SecondIterator, AZStd::random_access_iterator_tag>::operator+=(size_t n)->typename super::RootIterator &
{
super::m_first += n;
super::m_second += n;
return *static_cast<typename super::RootIterator*>(this);
}
template<typename FirstIterator, typename SecondIterator>
auto PairIterator<FirstIterator, SecondIterator, AZStd::random_access_iterator_tag>::operator-=(size_t n)->typename super::RootIterator &
{
super::m_first -= n;
super::m_second -= n;
return *static_cast<typename super::RootIterator*>(this);
}
//
// Contiguous Random Access iterator
//
template<typename FirstIterator, typename SecondIterator>
PairIterator<FirstIterator, SecondIterator, AZStd::contiguous_iterator_tag>::PairIterator(
FirstIterator first, SecondIterator second)
: super(first, second)
{
}
template<typename FirstIterator, typename SecondIterator>
PairIterator<FirstIterator, SecondIterator, AZStd::contiguous_iterator_tag>::PairIterator()
: super()
{
}
//
// Utility functions
//
template<typename FirstIterator, typename SecondIterator>
PairIterator<FirstIterator, SecondIterator> MakePairIterator(FirstIterator first, SecondIterator second)
{
return PairIterator<FirstIterator, SecondIterator>(first, second);
}
template<typename FirstIterator, typename SecondIterator>
View<PairIterator<FirstIterator, SecondIterator>>
MakePairView(FirstIterator firstBegin, FirstIterator firstEnd, SecondIterator secondBegin, SecondIterator secondEnd)
{
return View<PairIterator<FirstIterator, SecondIterator>>(
PairIterator<FirstIterator, SecondIterator>(firstBegin, secondBegin),
PairIterator<FirstIterator, SecondIterator>(firstEnd, secondEnd));
}
template<typename FirstView, typename SecondView>
View<PairIterator<typename FirstView::iterator, typename SecondView::iterator>>
MakePairView(FirstView& firstView, SecondView& secondView)
{
return MakePairView(firstView.begin(), firstView.end(), secondView.begin(), secondView.end());
}
template<typename FirstView, typename SecondView>
View<PairIterator<typename FirstView::const_iterator, typename SecondView::iterator>>
MakePairView(const FirstView& firstView, SecondView& secondView)
{
return MakePairView(firstView.begin(), firstView.end(), secondView.begin(), secondView.end());
}
template<typename FirstView, typename SecondView>
View<PairIterator<typename FirstView::iterator, typename SecondView::const_iterator>>
MakePairView(FirstView& firstView, const SecondView& secondView)
{
return MakePairView(firstView.begin(), firstView.end(), secondView.begin(), secondView.end());
}
template<typename FirstView, typename SecondView>
View<PairIterator<typename FirstView::const_iterator, typename SecondView::const_iterator>>
MakePairView(const FirstView& firstView, const SecondView& secondView)
{
return MakePairView(firstView.begin(), firstView.end(), secondView.begin(), secondView.end());
}
} // Views
} // Containers
} // SceneAPI
} // AZ
namespace AZStd
{
// iterator swap
template<typename First, typename Second>
void iter_swap(AZ::SceneAPI::Containers::Views::PairIterator<First, Second> lhs, AZ::SceneAPI::Containers::Views::PairIterator<First, Second> rhs)
{
typename remove_pointer<typename remove_reference<First>::type>::type tmpFirst = (*lhs).first;
typename remove_pointer<typename remove_reference<Second>::type>::type tmpSecond = (*lhs).second;
(*lhs).first = (*rhs).first;
(*lhs).second = (*rhs).second;
(*rhs).first = tmpFirst;
(*rhs).second = tmpSecond;
}
}
@@ -0,0 +1,156 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <iterator>
#include <type_traits>
#include <AzCore/std/iterator.h>
#include <AzCore/std/typetraits/is_base_of.h>
#include <SceneAPI/SceneCore/Containers/Views/View.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
struct FilterAcceptanceTag {};
// Filter tag to only show regular nodes.
struct AcceptNodesOnly : public FilterAcceptanceTag {};
// Filter tag to only show end points.
struct AcceptEndPointsOnly : public FilterAcceptanceTag {};
// Filter tag to show all nodes.
struct AcceptAll : public FilterAcceptanceTag {};
// Iterator to traverse a SceneGraph from a given node by listing all the direct children. The given node will not be included in the
// iteration. By default all children are listed, but optionally only regular nodes or only end points can be returned by
// specifying the appropriate tag (see example below).
// Example:
// auto view = MakeSceneGraphChildView(graph, graph.ConvertToHierarchyIterator(nodeIndex), graph.GetNameStorage().begin(), true);
// for (auto& it : view)
// {
// printf("Node: %s\n", it.c_str());
// }
//
// Example:
// auto view = MakeSceneGraphChildView<AcceptEndPointsOnly>(graph, nodeIndex, graph.GetNameStorage().begin(), true);
// for (auto& it : view)
// {
// printf("End point: %s\n", it.c_str());
// }
template<typename Iterator, typename Filter = AcceptAll>
class SceneGraphChildIterator
{
static_assert(AZStd::is_base_of<FilterAcceptanceTag, Filter>::value,
"Filter for SceneGraphChildIterator is not a valid tag. Use AcceptNodesOnly, AcceptEndPointsOnly, AcceptAll or leave blank.");
static_assert(AZStd::is_base_of<AZStd::bidirectional_iterator_tag, typename AZStd::iterator_traits<Iterator>::iterator_category>::value,
"SceneGraphChildIterator needs at least a bidirectional iterator for its data iterator.");
public:
using value_type = typename AZStd::iterator_traits<Iterator>::value_type;
using difference_type = AZStd::ptrdiff_t;
using pointer = typename AZStd::iterator_traits<Iterator>::pointer;
using reference = typename AZStd::iterator_traits<Iterator>::reference;
using iterator_category = AZStd::forward_iterator_tag;
// Creates an iterator at a specified node in the hierarchy.
// graph: SceneGraph that will traversed.
// graphIterator: The node to start traversing from.
// iterator: The data iterator to be dereferenced from.
// rootIterator: If true the data iterator will be the first iterator from the data and
// this iterator will be moved forward to match the graph iterator. If false
// the graph iterator and the data iterator should be pointing to the same relative
// element.
SceneGraphChildIterator(const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator);
SceneGraphChildIterator(const SceneGraphChildIterator&) = default;
SceneGraphChildIterator();
SceneGraphChildIterator& operator=(const SceneGraphChildIterator&) = default;
SceneGraphChildIterator& operator++();
SceneGraphChildIterator operator++(int);
bool operator==(const SceneGraphChildIterator& rhs) const;
bool operator!=(const SceneGraphChildIterator& rhs) const;
reference operator*() const;
pointer operator->() const;
SceneGraph::HierarchyStorageConstIterator GetHierarchyIterator() const;
private:
// For iterators that are raw pointers.
pointer GetPointer(AZStd::true_type) const;
// For all other types of iterator.
pointer GetPointer(AZStd::false_type) const;
void MoveToNext();
bool ShouldAcceptNode(AcceptNodesOnly) const;
bool ShouldAcceptNode(AcceptEndPointsOnly) const;
bool ShouldAcceptNode(AcceptAll) const;
const SceneGraph* m_graph;
Iterator m_iterator;
int32_t m_index;
};
//
// Iterator construction
//
template<typename Filter, typename Iterator>
SceneGraphChildIterator<Iterator, Filter> MakeSceneGraphChildIterator(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator);
template<typename Filter, typename Iterator>
SceneGraphChildIterator<Iterator, Filter> MakeSceneGraphChildIterator(
const SceneGraph& graph, SceneGraph::NodeIndex node, Iterator iterator, bool rootIterator);
template<typename Iterator>
SceneGraphChildIterator<Iterator> MakeSceneGraphChildIterator(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator);
template<typename Iterator>
SceneGraphChildIterator<Iterator> MakeSceneGraphChildIterator(
const SceneGraph& graph, SceneGraph::NodeIndex node, Iterator iterator, bool rootIterator);
//
// View construction
//
template<typename Filter, typename Iterator>
View<SceneGraphChildIterator<Iterator, Filter> > MakeSceneGraphChildView(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator);
template<typename Filter, typename Iterator>
View<SceneGraphChildIterator<Iterator, Filter> > MakeSceneGraphChildView(
const SceneGraph& graph, SceneGraph::NodeIndex node, Iterator iterator, bool rootIterator);
template<typename Iterator>
View<SceneGraphChildIterator<Iterator> > MakeSceneGraphChildView(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator);
template<typename Iterator>
View<SceneGraphChildIterator<Iterator> > MakeSceneGraphChildView(
const SceneGraph& graph, SceneGraph::NodeIndex node, Iterator iterator, bool rootIterator);
} // Views
} // Containers
} // SceneAPI
} // AZ
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphChildIterator.inl>
@@ -0,0 +1,222 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
template<typename Iterator, typename Filter>
SceneGraphChildIterator<Iterator, Filter>::SceneGraphChildIterator(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator)
: m_index(-1)
, m_graph(nullptr)
{
if (graph.GetHierarchyStorage().end() != graphIterator)
{
if (graphIterator->HasChild())
{
m_graph = &graph;
m_index = graphIterator->m_childIndex;
s32 delta = rootIterator ? static_cast<s32>(m_index) : graph.ConvertToNodeIndex(graphIterator).Distance(graphIterator->GetChildIndex());
m_iterator = AZStd::next(iterator, delta);
if (!ShouldAcceptNode(Filter()))
{
MoveToNext();
}
}
}
}
template<typename Iterator, typename Filter>
SceneGraphChildIterator<Iterator, Filter>::SceneGraphChildIterator()
: m_graph(nullptr)
, m_index(-1)
{
}
template<typename Iterator, typename Filter>
auto SceneGraphChildIterator<Iterator, Filter>::operator++()->SceneGraphChildIterator &
{
MoveToNext();
return *this;
}
template<typename Iterator, typename Filter>
auto SceneGraphChildIterator<Iterator, Filter>::operator++(int)->SceneGraphChildIterator
{
SceneGraphChildIterator result = *this;
MoveToNext();
return result;
}
template<typename Iterator, typename Filter>
bool SceneGraphChildIterator<Iterator, Filter>::operator==(const SceneGraphChildIterator& rhs) const
{
return m_graph == rhs.m_graph && m_index == rhs.m_index;
}
template<typename Iterator, typename Filter>
bool SceneGraphChildIterator<Iterator, Filter>::operator!=(const SceneGraphChildIterator& rhs) const
{
return m_graph != rhs.m_graph || m_index != rhs.m_index;
}
template<typename Iterator, typename Filter>
auto SceneGraphChildIterator<Iterator, Filter>::operator*() const->reference
{
return *m_iterator;
}
template<typename Iterator, typename Filter>
auto SceneGraphChildIterator<Iterator, Filter>::GetPointer(AZStd::true_type) const->pointer
{
return m_iterator;
}
template<typename Iterator, typename Filter>
auto SceneGraphChildIterator<Iterator, Filter>::GetPointer(AZStd::false_type) const->pointer
{
return m_iterator.operator->();
}
template<typename Iterator, typename Filter>
auto SceneGraphChildIterator<Iterator, Filter>::operator->() const->pointer
{
return GetPointer(typename AZStd::is_pointer<Iterator>::type());
}
template<typename Iterator, typename Filter>
SceneGraph::HierarchyStorageConstIterator SceneGraphChildIterator<Iterator, Filter>::GetHierarchyIterator() const
{
if (m_index >= 0)
{
return AZStd::next(m_graph->GetHierarchyStorage().begin(), m_index);
}
else
{
return SceneGraph::HierarchyStorageConstIterator();
}
}
template<typename Iterator, typename Filter>
void SceneGraphChildIterator<Iterator, Filter>::MoveToNext()
{
do
{
SceneGraph::NodeHeader header = m_graph->GetHierarchyStorage().begin()[m_index];
if (header.HasSibling())
{
AZStd::advance(m_iterator, header.m_siblingIndex - m_index);
m_index = header.m_siblingIndex;
}
else
{
m_index = -1;
m_graph = nullptr;
return;
}
} while (!ShouldAcceptNode(Filter()));
}
template<typename Iterator, typename Filter>
bool SceneGraphChildIterator<Iterator, Filter>::ShouldAcceptNode(AcceptNodesOnly) const
{
SceneGraph::NodeHeader header = m_graph->GetHierarchyStorage().begin()[m_index];
return !header.IsEndPoint();
}
template<typename Iterator, typename Filter>
bool SceneGraphChildIterator<Iterator, Filter>::ShouldAcceptNode(AcceptEndPointsOnly) const
{
SceneGraph::NodeHeader header = m_graph->GetHierarchyStorage().begin()[m_index];
return header.IsEndPoint();
}
template<typename Iterator, typename Filter>
bool SceneGraphChildIterator<Iterator, Filter>::ShouldAcceptNode(AcceptAll) const
{
return true;
}
template<typename Filter, typename Iterator>
SceneGraphChildIterator<Iterator, Filter> MakeSceneGraphChildIterator(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator)
{
return SceneGraphChildIterator<Iterator, Filter>(graph, graphIterator, iterator, rootIterator);
}
template<typename Filter, typename Iterator>
SceneGraphChildIterator<Iterator, Filter> MakeSceneGraphChildIterator(
const SceneGraph& graph, SceneGraph::NodeIndex node, Iterator iterator, bool rootIterator)
{
return SceneGraphChildIterator<Iterator, Filter>(graph, graph.ConvertToHierarchyIterator(node), iterator, rootIterator);
}
template<typename Iterator>
SceneGraphChildIterator<Iterator> MakeSceneGraphChildIterator(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator)
{
return SceneGraphChildIterator<Iterator>(graph, graphIterator, iterator, rootIterator);
}
template<typename Iterator>
SceneGraphChildIterator<Iterator> MakeSceneGraphChildIterator(
const SceneGraph& graph, SceneGraph::NodeIndex node, Iterator iterator, bool rootIterator)
{
return SceneGraphChildIterator<Iterator>(graph, graph.ConvertToHierarchyIterator(node), iterator, rootIterator);
}
template<typename Filter, typename Iterator>
View<SceneGraphChildIterator<Iterator, Filter> > MakeSceneGraphChildView(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator)
{
return View<SceneGraphChildIterator<Iterator, Filter> >(
SceneGraphChildIterator<Iterator, Filter>(graph, graphIterator, iterator, rootIterator),
SceneGraphChildIterator<Iterator, Filter>());
}
template<typename Filter, typename Iterator>
View<SceneGraphChildIterator<Iterator, Filter> > MakeSceneGraphChildView(
const SceneGraph& graph, SceneGraph::NodeIndex node, Iterator iterator, bool rootIterator)
{
return View<SceneGraphChildIterator<Iterator, Filter> >(
SceneGraphChildIterator<Iterator, Filter>(graph, graph.ConvertToHierarchyIterator(node), iterator, rootIterator),
SceneGraphChildIterator<Iterator, Filter>());
}
template<typename Iterator>
View<SceneGraphChildIterator<Iterator> > MakeSceneGraphChildView(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator)
{
return View<SceneGraphChildIterator<Iterator> >(
SceneGraphChildIterator<Iterator>(graph, graphIterator, iterator, rootIterator),
SceneGraphChildIterator<Iterator>());
}
template<typename Iterator>
View<SceneGraphChildIterator<Iterator> > MakeSceneGraphChildView(
const SceneGraph& graph, SceneGraph::NodeIndex node, Iterator iterator, bool rootIterator)
{
return View<SceneGraphChildIterator<Iterator> >(
SceneGraphChildIterator<Iterator>(graph, graph.ConvertToHierarchyIterator(node), iterator, rootIterator),
SceneGraphChildIterator<Iterator>());
}
} // Views
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,135 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <deque>
#include <iterator>
#include <type_traits>
#include <AzCore/std/iterator.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/Containers/Views/View.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
// Tag for depth-first traversal
struct DepthFirst {};
// Tag for breadth-first traversal
struct BreadthFirst {};
// Iterator to traverse a SceneGraph downwards from the root or a given hierarchy iterator either
// depth-first or breadth-first. If a hierarchy iterator is specified it will be the first
// entry returned, otherwise the root.
// Example:
// auto view = MakeSceneGraphDownwardsView<DepthFirst>(graph, graph.GetNameStorage().begin());
// for (auto it : view)
// {
// printf("Node: %s\n", it.c_str());
// }
// Example:
// SceneGraph::NodeIndex search = graph.Find("A.C");
// auto view = MakeSceneGraphDownwardsView<BreadthFirst>(graph, graph.ConvertToHierarchyIterator(search), graph.GetNameStorage().begin(), true);
// for (auto it : view)
// {
// printf("Node: %s\n", it.c_str());
// }
template<typename Iterator, typename Traversal>
class SceneGraphDownwardsIterator
{
static_assert(std::is_base_of<AZStd::bidirectional_iterator_tag, typename AZStd::iterator_traits<Iterator>::iterator_category>::value,
"SceneGraphDownwardsIterator needs at least a bidrectional iterator for its data iterator.");
public:
using value_type = typename AZStd::iterator_traits<Iterator>::value_type;
using difference_type = std::ptrdiff_t;
using pointer = typename AZStd::iterator_traits<Iterator>::pointer;
using reference = typename AZStd::iterator_traits<Iterator>::reference;
using iterator_category = AZStd::forward_iterator_tag;
// Creates an iterator at the root node in the hierarchy.
SceneGraphDownwardsIterator(const SceneGraph& graph, Iterator iterator);
// Creates an iterator at a specified node in the hierarchy.
// graph: SceneGraph that will traversed.
// graphIterator: The node to start traversing from.
// iterator: The data iterator to be dereferenced from.
// rootIterator: If true the data iterator will be the first iterator from the data and
// this iterator will be moved forward to match the graph iterator. If false
// the graph iterator and the data iterator should be pointing to the same relative
// element.
SceneGraphDownwardsIterator(const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator);
SceneGraphDownwardsIterator(const SceneGraphDownwardsIterator&) = default;
SceneGraphDownwardsIterator();
SceneGraphDownwardsIterator& operator=(const SceneGraphDownwardsIterator&) = default;
SceneGraphDownwardsIterator& operator++();
SceneGraphDownwardsIterator operator++(int);
bool operator==(const SceneGraphDownwardsIterator& rhs) const;
bool operator!=(const SceneGraphDownwardsIterator& rhs) const;
reference operator*() const;
pointer operator->() const;
SceneGraph::HierarchyStorageConstIterator GetHierarchyIterator() const;
// Stops the iterator from descending into the children of the current node. Pending nodes and their children will be processed as normal.
// This call can be made multiple times for different nodes.
void IgnoreNodeDescendants();
private:
// For iterators that are raw pointers.
pointer GetPointer(AZStd::true_type) const;
// For all other types of iterator.
pointer GetPointer(AZStd::false_type) const;
void MoveToNext(DepthFirst);
void MoveToNext(BreadthFirst);
void JumpTo(int32_t index);
std::deque<int32_t> m_pending;
const SceneGraph* m_graph;
Iterator m_iterator;
int32_t m_index : 30;
int32_t m_firstNode : 1;
int32_t m_ignoreDescendants : 1;
};
template<typename Traversal, typename Iterator>
SceneGraphDownwardsIterator<Iterator, Traversal> MakeSceneGraphDownwardsIterator(const SceneGraph& graph, Iterator iterator);
template<typename Traversal, typename Iterator>
SceneGraphDownwardsIterator<Iterator, Traversal> MakeSceneGraphDownwardsIterator(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator);
template<typename Traversal, typename Iterator>
SceneGraphDownwardsIterator<Iterator, Traversal> MakeSceneGraphDownwardsIterator(
const SceneGraph& graph, SceneGraph::NodeIndex node, Iterator iterator, bool rootIterator);
template<typename Traversal, typename Iterator>
View<SceneGraphDownwardsIterator<Iterator, Traversal> > MakeSceneGraphDownwardsView(const SceneGraph& graph, Iterator iterator);
template<typename Traversal, typename Iterator>
View<SceneGraphDownwardsIterator<Iterator, Traversal> > MakeSceneGraphDownwardsView(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator);
template<typename Traversal, typename Iterator>
View<SceneGraphDownwardsIterator<Iterator, Traversal> > MakeSceneGraphDownwardsView(
const SceneGraph& graph, SceneGraph::NodeIndex node, Iterator iterator, bool rootIterator);
} // Views
} // Containers
} // SceneAPI
} // AZ
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphDownwardsIterator.inl>
@@ -0,0 +1,242 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/std/typetraits/is_pointer.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
template<typename Iterator, typename Traversal>
SceneGraphDownwardsIterator<Iterator, Traversal>::SceneGraphDownwardsIterator(const SceneGraph& graph, Iterator iterator)
: m_graph(&graph)
, m_iterator(iterator)
, m_index(0)
, m_ignoreDescendants(false)
, m_firstNode(true)
{
}
template<typename Iterator, typename Traversal>
SceneGraphDownwardsIterator<Iterator, Traversal>::SceneGraphDownwardsIterator(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator)
: m_ignoreDescendants(false)
, m_firstNode(true)
{
if (graph.GetHierarchyStorage().end() == graphIterator)
{
m_index = -1;
m_graph = nullptr;
}
else
{
m_graph = &graph;
m_index = static_cast<int32_t>(AZStd::distance(graph.GetHierarchyStorage().begin(), graphIterator));
m_iterator = rootIterator ? AZStd::next(iterator, m_index) : iterator;
}
}
template<typename Iterator, typename Traversal>
SceneGraphDownwardsIterator<Iterator, Traversal>::SceneGraphDownwardsIterator()
: m_graph(nullptr)
, m_index(-1)
, m_ignoreDescendants(false)
, m_firstNode(false)
{
}
template<typename Iterator, typename Traversal>
auto SceneGraphDownwardsIterator<Iterator, Traversal>::operator++()->SceneGraphDownwardsIterator &
{
MoveToNext(Traversal());
return *this;
}
template<typename Iterator, typename Traversal>
auto SceneGraphDownwardsIterator<Iterator, Traversal>::operator++(int)->SceneGraphDownwardsIterator
{
SceneGraphDownwardsIterator result = *this;
MoveToNext(Traversal());
return result;
}
template<typename Iterator, typename Traversal>
bool SceneGraphDownwardsIterator<Iterator, Traversal>::operator==(const SceneGraphDownwardsIterator& rhs) const
{
return m_graph == rhs.m_graph && m_index == rhs.m_index && m_firstNode == rhs.m_firstNode;
}
template<typename Iterator, typename Traversal>
bool SceneGraphDownwardsIterator<Iterator, Traversal>::operator!=(const SceneGraphDownwardsIterator& rhs) const
{
return m_graph != rhs.m_graph || m_index != rhs.m_index || m_firstNode != rhs.m_firstNode;
}
template<typename Iterator, typename Traversal>
auto SceneGraphDownwardsIterator<Iterator, Traversal>::operator*() const->reference
{
return *m_iterator;
}
template<typename Iterator, typename Traversal>
auto SceneGraphDownwardsIterator<Iterator, Traversal>::GetPointer(AZStd::true_type) const->pointer
{
return m_iterator;
}
template<typename Iterator, typename Traversal>
auto SceneGraphDownwardsIterator<Iterator, Traversal>::GetPointer(AZStd::false_type) const->pointer
{
return m_iterator.operator->();
}
template<typename Iterator, typename Traversal>
auto SceneGraphDownwardsIterator<Iterator, Traversal>::operator->() const->pointer
{
return GetPointer(typename AZStd::is_pointer<Iterator>::type());
}
template<typename Iterator, typename Traversal>
SceneGraph::HierarchyStorageConstIterator SceneGraphDownwardsIterator<Iterator, Traversal>::GetHierarchyIterator() const
{
if (m_index >= 0)
{
return AZStd::next(m_graph->GetHierarchyStorage().begin(), m_index);
}
else
{
return SceneGraph::HierarchyStorageConstIterator();
}
}
template<typename Iterator, typename Traversal>
void SceneGraphDownwardsIterator<Iterator, Traversal>::IgnoreNodeDescendants()
{
m_ignoreDescendants = true;
}
template<typename Iterator, typename Traversal>
void SceneGraphDownwardsIterator<Iterator, Traversal>::MoveToNext(DepthFirst)
{
AZ_Assert(m_graph, "Invalid iterator or moved passed end of list.");
SceneGraph::NodeHeader header = m_graph->GetHierarchyStorage().begin()[m_index];
if (!m_firstNode && header.HasSibling())
{
m_pending.push_back(static_cast<int32_t>(header.m_siblingIndex));
}
if (!m_ignoreDescendants && header.HasChild())
{
JumpTo(header.m_childIndex);
}
else if (!m_pending.empty())
{
JumpTo(m_pending.back());
m_pending.pop_back();
}
else
{
m_index = -1;
m_graph = nullptr;
}
m_ignoreDescendants = false;
m_firstNode = false;
}
template<typename Iterator, typename Traversal>
void SceneGraphDownwardsIterator<Iterator, Traversal>::MoveToNext(BreadthFirst)
{
AZ_Assert(m_graph, "Invalid iterator or moved passed end of list.");
SceneGraph::NodeHeader header = m_graph->GetHierarchyStorage().begin()[m_index];
if (!m_ignoreDescendants && header.HasChild())
{
m_pending.push_back(static_cast<int32_t>(header.m_childIndex));
}
if (!m_firstNode && header.HasSibling())
{
JumpTo(header.m_siblingIndex);
}
else if (!m_pending.empty())
{
JumpTo(m_pending.front());
m_pending.pop_front();
}
else
{
m_index = -1;
m_graph = nullptr;
}
m_ignoreDescendants = false;
m_firstNode = false;
}
template<typename Iterator, typename Traversal>
void SceneGraphDownwardsIterator<Iterator, Traversal>::JumpTo(int32_t index)
{
AZStd::advance(m_iterator, index - m_index);
m_index = index;
}
template<typename Traversal, typename Iterator>
SceneGraphDownwardsIterator<Iterator, Traversal> MakeSceneGraphDownwardsIterator(const SceneGraph& graph, Iterator iterator)
{
return SceneGraphDownwardsIterator<Iterator, Traversal>(graph, iterator);
}
template<typename Traversal, typename Iterator>
SceneGraphDownwardsIterator<Iterator, Traversal> MakeSceneGraphDownwardsIterator(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator)
{
return SceneGraphDownwardsIterator<Iterator, Traversal>(graph, graphIterator, iterator, rootIterator);
}
template<typename Traversal, typename Iterator>
SceneGraphDownwardsIterator<Iterator, Traversal> MakeSceneGraphDownwardsIterator(
const SceneGraph& graph, SceneGraph::NodeIndex node, Iterator iterator, bool rootIterator)
{
return SceneGraphDownwardsIterator<Iterator, Traversal>(graph, graph.ConvertToHierarchyIterator(node), iterator, rootIterator);
}
template<typename Traversal, typename Iterator>
View<SceneGraphDownwardsIterator<Iterator, Traversal> > MakeSceneGraphDownwardsView(const SceneGraph& graph, Iterator iterator)
{
return View<SceneGraphDownwardsIterator<Iterator, Traversal> >(
SceneGraphDownwardsIterator<Iterator, Traversal>(graph, iterator),
SceneGraphDownwardsIterator<Iterator, Traversal>());
}
template<typename Traversal, typename Iterator>
View<SceneGraphDownwardsIterator<Iterator, Traversal> > MakeSceneGraphDownwardsView(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator)
{
return View<SceneGraphDownwardsIterator<Iterator, Traversal> >(
SceneGraphDownwardsIterator<Iterator, Traversal>(graph, graphIterator, iterator, rootIterator),
SceneGraphDownwardsIterator<Iterator, Traversal>());
}
template<typename Traversal, typename Iterator>
View<SceneGraphDownwardsIterator<Iterator, Traversal> > MakeSceneGraphDownwardsView(
const SceneGraph& graph, SceneGraph::NodeIndex node, Iterator iterator, bool rootIterator)
{
return View<SceneGraphDownwardsIterator<Iterator, Traversal> >(
SceneGraphDownwardsIterator<Iterator, Traversal>(graph, graph.ConvertToHierarchyIterator(node), iterator, rootIterator),
SceneGraphDownwardsIterator<Iterator, Traversal>());
}
} // Views
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,109 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <stack>
#include <iterator>
#include <type_traits>
#include <AzCore/std/iterator.h>
#include <AzCore/std/typetraits/is_base_of.h>
#include <SceneAPI/SceneCore/Containers/Views/View.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
// Iterator to traverse a SceneGraph from a given node upwards to the root.
// The given node will be included as the first returned value.
// Example:
// auto view = MakeSceneGraphUpwardsView(graph, graph.ConvertToHierarchyIterator(nodeIndex), graph.GetNameStorage().begin(), true);
// for (auto it : view)
// {
// printf("Node: %s\n", it.c_str());
// }
template<typename Iterator>
class SceneGraphUpwardsIterator
{
static_assert(AZStd::is_base_of<AZStd::bidirectional_iterator_tag, typename AZStd::iterator_traits<Iterator>::iterator_category>::value,
"SceneGraphUpwardsIterator needs at least a bidrectional iterator for its data iterator.");
public:
using value_type = typename AZStd::iterator_traits<Iterator>::value_type;
using difference_type = AZStd::ptrdiff_t;
using pointer = typename AZStd::iterator_traits<Iterator>::pointer;
using reference = typename AZStd::iterator_traits<Iterator>::reference;
using iterator_category = AZStd::forward_iterator_tag;
// Creates an iterator at a specified node in the hierarchy.
// graph: SceneGraph that will traversed.
// graphIterator: The node to start traversing from.
// iterator: The data iterator to be dereferenced from.
// rootIterator: If true the data iterator will be the first iterator from the data and
// this iterator will be moved forward to match the graph iterator. If false
// the graph iterator and the data iterator should be pointing to the same relative
// element.
SceneGraphUpwardsIterator(const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator);
SceneGraphUpwardsIterator(const SceneGraphUpwardsIterator&) = default;
SceneGraphUpwardsIterator();
SceneGraphUpwardsIterator& operator=(const SceneGraphUpwardsIterator&) = default;
SceneGraphUpwardsIterator& operator++();
SceneGraphUpwardsIterator operator++(int);
bool operator==(const SceneGraphUpwardsIterator& rhs) const;
bool operator!=(const SceneGraphUpwardsIterator& rhs) const;
reference operator*() const;
pointer operator->() const;
SceneGraph::HierarchyStorageConstIterator GetHierarchyIterator() const;
private:
// For iterators that are raw pointers.
pointer GetPointer(AZStd::true_type) const;
// For all other types of iterator.
pointer GetPointer(AZStd::false_type) const;
void MoveToNext();
const SceneGraph* m_graph;
Iterator m_iterator;
int32_t m_index;
};
template<typename Iterator>
SceneGraphUpwardsIterator<Iterator> MakeSceneGraphUpwardsIterator(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator);
template<typename Iterator>
SceneGraphUpwardsIterator<Iterator> MakeSceneGraphUpwardsIterator(
const SceneGraph& graph, SceneGraph::NodeIndex node, Iterator iterator, bool rootIterator);
template<typename Iterator>
View<SceneGraphUpwardsIterator<Iterator> > MakeSceneGraphUpwardsView(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator);
template<typename Iterator>
View<SceneGraphUpwardsIterator<Iterator> > MakeSceneGraphUpwardsView(
const SceneGraph& graph, SceneGraph::NodeIndex node, Iterator iterator, bool rootIterator);
} // Views
} // Containers
} // SceneAPI
} // AZ
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphUpwardsIterator.inl>
@@ -0,0 +1,153 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
template<typename Iterator>
SceneGraphUpwardsIterator<Iterator>::SceneGraphUpwardsIterator(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator)
{
if (graph.GetHierarchyStorage().end() == graphIterator)
{
m_index = -1;
m_graph = nullptr;
}
else
{
m_graph = &graph;
m_index = static_cast<int32_t>(AZStd::distance(graph.GetHierarchyStorage().begin(), graphIterator));
m_iterator = rootIterator ? AZStd::next(iterator, m_index) : iterator;
}
}
template<typename Iterator>
SceneGraphUpwardsIterator<Iterator>::SceneGraphUpwardsIterator()
: m_graph(nullptr)
, m_index(-1)
{
}
template<typename Iterator>
auto SceneGraphUpwardsIterator<Iterator>::operator++()->SceneGraphUpwardsIterator &
{
MoveToNext();
return *this;
}
template<typename Iterator>
auto SceneGraphUpwardsIterator<Iterator>::operator++(int)->SceneGraphUpwardsIterator
{
SceneGraphUpwardsIterator result = *this;
MoveToNext();
return result;
}
template<typename Iterator>
bool SceneGraphUpwardsIterator<Iterator>::operator==(const SceneGraphUpwardsIterator& rhs) const
{
return m_graph == rhs.m_graph && m_index == rhs.m_index;
}
template<typename Iterator>
bool SceneGraphUpwardsIterator<Iterator>::operator!=(const SceneGraphUpwardsIterator& rhs) const
{
return m_graph != rhs.m_graph || m_index != rhs.m_index;
}
template<typename Iterator>
auto SceneGraphUpwardsIterator<Iterator>::operator*() const->reference
{
return *m_iterator;
}
template<typename Iterator>
auto SceneGraphUpwardsIterator<Iterator>::GetPointer(AZStd::true_type) const->pointer
{
return m_iterator;
}
template<typename Iterator>
auto SceneGraphUpwardsIterator<Iterator>::GetPointer(AZStd::false_type) const->pointer
{
return m_iterator.operator->();
}
template<typename Iterator>
auto SceneGraphUpwardsIterator<Iterator>::operator->() const->pointer
{
return GetPointer(typename AZStd::is_pointer<Iterator>::type());
}
template<typename Iterator>
SceneGraph::HierarchyStorageConstIterator SceneGraphUpwardsIterator<Iterator>::GetHierarchyIterator() const
{
return AZStd::next(m_graph->GetHierarchyStorage().begin(), m_index);
}
template<typename Iterator>
void SceneGraphUpwardsIterator<Iterator>::MoveToNext()
{
AZ_Assert(m_graph, "Invalid iterator or moved passed end of list.");
SceneGraph::NodeHeader header = m_graph->GetHierarchyStorage().begin()[m_index];
if (header.HasParent())
{
AZStd::advance(m_iterator, header.m_parentIndex - m_index);
m_index = header.m_parentIndex;
}
else
{
m_index = -1;
m_graph = nullptr;
}
}
template<typename Iterator>
SceneGraphUpwardsIterator<Iterator> MakeSceneGraphUpwardsIterator(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator)
{
return SceneGraphUpwardsIterator<Iterator>(graph, graphIterator, iterator, rootIterator);
}
template<typename Iterator>
SceneGraphUpwardsIterator<Iterator> MakeSceneGraphUpwardsIterator(
const SceneGraph& graph, SceneGraph::NodeIndex node, Iterator iterator, bool rootIterator)
{
return SceneGraphUpwardsIterator<Iterator>(graph, graph.ConvertToHierarchyIterator(node), iterator, rootIterator);
}
template<typename Iterator>
View<SceneGraphUpwardsIterator<Iterator> > MakeSceneGraphUpwardsView(
const SceneGraph& graph, SceneGraph::HierarchyStorageConstIterator graphIterator, Iterator iterator, bool rootIterator)
{
return View<SceneGraphUpwardsIterator<Iterator> >(
SceneGraphUpwardsIterator<Iterator>(graph, graphIterator, iterator, rootIterator),
SceneGraphUpwardsIterator<Iterator>());
}
template<typename Iterator>
View<SceneGraphUpwardsIterator<Iterator> > MakeSceneGraphUpwardsView(
const SceneGraph& graph, SceneGraph::NodeIndex node, Iterator iterator, bool rootIterator)
{
return View<SceneGraphUpwardsIterator<Iterator> >(
SceneGraphUpwardsIterator<Iterator>(graph, graph.ConvertToHierarchyIterator(node), iterator, rootIterator),
SceneGraphUpwardsIterator<Iterator>());
}
} // Views
} // Containers
} // SceneAPI
} // AZ
@@ -0,0 +1,62 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
// View combines begin and end iterators together in a single object.
// This reduces the number of functions that are needed to pass
// iterators from functions and avoids problems with mismatched
// iterators. It also makes it easier to use in ranged-based
// for-loops.
// Note that const correctness is enforced by the type of
// iterator passed, so all versions of begin and end return
// the same value.
template<typename Iterator>
class View
{
public:
using iterator = Iterator;
using const_iterator = Iterator;
View(Iterator begin, Iterator end);
Iterator begin();
Iterator end();
Iterator begin() const;
Iterator end() const;
Iterator cbegin() const;
Iterator cend() const;
private:
Iterator m_begin;
Iterator m_end;
};
template<typename Iterator>
View<Iterator> MakeView(Iterator begin, Iterator end)
{
return View<Iterator>(begin, end);
}
} // Views
} // Containers
} // SceneAPI
} // AZ
#include <SceneAPI/SceneCore/Containers/Views/View.inl>
@@ -0,0 +1,68 @@
#pragma once
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
namespace AZ
{
namespace SceneAPI
{
namespace Containers
{
namespace Views
{
template<typename Iterator>
View<Iterator>::View(Iterator begin, Iterator end)
: m_begin(begin)
, m_end(end)
{
}
template<typename Iterator>
Iterator View<Iterator>::begin()
{
return m_begin;
}
template<typename Iterator>
Iterator View<Iterator>::end()
{
return m_end;
}
template<typename Iterator>
Iterator View<Iterator>::begin() const
{
return m_begin;
}
template<typename Iterator>
Iterator View<Iterator>::end() const
{
return m_end;
}
template<typename Iterator>
Iterator View<Iterator>::cbegin() const
{
return m_begin;
}
template<typename Iterator>
Iterator View<Iterator>::cend() const
{
return m_end;
}
}; // Views
} // Containers
} // SceneAPI
} // AZ