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,36 @@
/*
* 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/Math/Crc.h>
namespace SurfaceData
{
namespace Constants
{
static const char* s_unassignedTagName = "(unassigned)";
static const char* s_terrainHoleTagName = "terrainHole";
static const char* s_terrainTagName = "terrain";
static const AZ::Crc32 s_unassignedTagCrc = AZ::Crc32(s_unassignedTagName);
static const AZ::Crc32 s_terrainHoleTagCrc = AZ::Crc32(s_terrainHoleTagName);
static const AZ::Crc32 s_terrainTagCrc = AZ::Crc32(s_terrainTagName);
static const char* s_allTagNames[] =
{
s_unassignedTagName,
s_terrainHoleTagName,
s_terrainTagName,
};
}
}
@@ -0,0 +1,42 @@
/*
* 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/EBus/EBus.h>
#include <AzCore/Math/Aabb.h>
#include <SurfaceData/SurfaceDataTypes.h>
namespace SurfaceData
{
/**
* the EBus is used to request information about a surface
*/
class SurfaceDataModifierRequests
: public AZ::EBusTraits
{
public:
////////////////////////////////////////////////////////////////////////
// EBusTraits
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
typedef AZ::u32 BusIdType;
////////////////////////////////////////////////////////////////////////
//! allows multiple threads to call
using MutexType = AZStd::recursive_mutex;
virtual void ModifySurfacePoints(SurfacePointList& surfacePointList) const = 0;
};
typedef AZ::EBus<SurfaceDataModifierRequests> SurfaceDataModifierRequestBus;
}
@@ -0,0 +1,41 @@
/*
* 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/EBus/EBus.h>
#include <SurfaceData/SurfaceDataTypes.h>
namespace SurfaceData
{
/**
* the EBus is used to request information about a surface
*/
class SurfaceDataProviderRequests
: public AZ::EBusTraits
{
public:
////////////////////////////////////////////////////////////////////////
// EBusTraits
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
typedef AZ::u32 BusIdType;
////////////////////////////////////////////////////////////////////////
//! allows multiple threads to call
using MutexType = AZStd::recursive_mutex;
virtual void GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const = 0;
};
typedef AZ::EBus<SurfaceDataProviderRequests> SurfaceDataProviderRequestBus;
}
@@ -0,0 +1,45 @@
/*
* 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/EBus/EBus.h>
#include <AzCore/Component/Entity.h>
namespace AZ
{
class Aabb;
}
namespace SurfaceData
{
/**
* the EBus is used to send notification information about surfaces
*/
class SurfaceDataSystemNotifications
: public AZ::EBusTraits
{
public:
////////////////////////////////////////////////////////////////////////
// EBusTraits
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
////////////////////////////////////////////////////////////////////////
//! allows multiple threads to call
using MutexType = AZStd::recursive_mutex;
virtual void OnSurfaceChanged(const AZ::EntityId& entityId, const AZ::Aabb& oldBounds, const AZ::Aabb& newBounds) = 0;
};
typedef AZ::EBus<SurfaceDataSystemNotifications> SurfaceDataSystemNotificationBus;
}
@@ -0,0 +1,61 @@
/*
* 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/Component/Entity.h>
#include <AzCore/EBus/EBus.h>
#include <AzCore/Math/Aabb.h>
#include <AzCore/Math/Vector2.h>
#include <SurfaceData/SurfaceDataTypes.h>
namespace SurfaceData
{
/**
* the EBus is used to request information about a surface
*/
class SurfaceDataSystemRequests
: public AZ::EBusTraits
{
public:
////////////////////////////////////////////////////////////////////////
// EBusTraits
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
////////////////////////////////////////////////////////////////////////
//! allows multiple threads to call
using MutexType = AZStd::recursive_mutex;
// Get all surface points located at the inPosition that matches one or more of the desiredTags. Only the XY components of inPosition are used.
virtual void GetSurfacePoints(const AZ::Vector3& inPosition, const SurfaceTagVector& desiredTags, SurfacePointList& surfacePointList) const = 0;
// Get all surface points for every input position within an AABB region. Only the XY dimensions of the AABB region are used.
// The input positions are chosen by starting at the min sides of inRegion and incrementing by stepSize. This method is inclusive
// on the min sides of the AABB, and exclusive on the max sides (i.e. for a box of (0,0) - (4,4), the point (0,0) is included but (4,4) isn't).
virtual void GetSurfacePointsFromRegion(const AZ::Aabb& inRegion, const AZ::Vector2 stepSize, const SurfaceTagVector& desiredTags,
SurfacePointListPerPosition& surfacePointListPerPosition) const = 0;
virtual SurfaceDataRegistryHandle RegisterSurfaceDataProvider(const SurfaceDataRegistryEntry& entry) = 0;
virtual void UnregisterSurfaceDataProvider(const SurfaceDataRegistryHandle& handle) = 0;
virtual void UpdateSurfaceDataProvider(const SurfaceDataRegistryHandle& handle, const SurfaceDataRegistryEntry& entry) = 0;
virtual SurfaceDataRegistryHandle RegisterSurfaceDataModifier(const SurfaceDataRegistryEntry& entry) = 0;
virtual void UnregisterSurfaceDataModifier(const SurfaceDataRegistryHandle& handle) = 0;
virtual void UpdateSurfaceDataModifier(const SurfaceDataRegistryHandle& handle, const SurfaceDataRegistryEntry& entry) = 0;
// Notify any dependent systems that they need to refresh their surface data for the provided area.
virtual void RefreshSurfaceData(const AZ::Aabb& dirtyArea) = 0;
};
typedef AZ::EBus<SurfaceDataSystemRequests> SurfaceDataSystemRequestBus;
}
@@ -0,0 +1,35 @@
/*
* 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/Component/ComponentBus.h>
#include <SurfaceData/SurfaceDataTypes.h>
namespace SurfaceData
{
/**
* the EBus is used to request tags
*/
class SurfaceDataTagEnumeratorRequests : public AZ::ComponentBus
{
public:
//! allows multiple threads to call
using MutexType = AZStd::recursive_mutex;
//tags are accumulated from all enumerators so implementers should not clear container
virtual void GetInclusionSurfaceTags([[maybe_unused]] SurfaceTagVector& tags, [[maybe_unused]] bool& includeAll) const {}
virtual void GetExclusionSurfaceTags([[maybe_unused]] SurfaceTagVector& tags) const {}
};
typedef AZ::EBus<SurfaceDataTagEnumeratorRequests> SurfaceDataTagEnumeratorRequestBus;
}
@@ -0,0 +1,41 @@
/*
* 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/EBus/EBus.h>
#include <AzCore/Math/Aabb.h>
#include <SurfaceData/SurfaceDataTypes.h>
namespace SurfaceData
{
/**
* the EBus is used to request registered tags
*/
class SurfaceDataTagProviderRequests
: public AZ::EBusTraits
{
public:
////////////////////////////////////////////////////////////////////////
// EBusTraits
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
////////////////////////////////////////////////////////////////////////
//! allows multiple threads to call
using MutexType = AZStd::recursive_mutex;
virtual void GetRegisteredSurfaceTagNames(SurfaceTagNameSet& names) const = 0;
};
typedef AZ::EBus<SurfaceDataTagProviderRequests> SurfaceDataTagProviderRequestBus;
}
@@ -0,0 +1,52 @@
/*
* 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/Math/Aabb.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/containers/unordered_set.h>
#include <SurfaceData/SurfaceTag.h>
namespace SurfaceData
{
//map of id or crc to contribution factor
using SurfaceTagWeightMap = AZStd::unordered_map<AZ::Crc32, float>;
using SurfaceTagNameSet = AZStd::unordered_set<AZStd::string>;
using SurfaceTagVector = AZStd::vector<SurfaceTag>;
struct SurfacePoint final
{
AZ_CLASS_ALLOCATOR(SurfacePoint, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(SurfacePoint, "{0DC7E720-68D6-47D4-BB6D-B89EF23C5A5C}");
AZ::EntityId m_entityId;
AZ::Vector3 m_position;
AZ::Vector3 m_normal;
SurfaceTagWeightMap m_masks;
};
using SurfacePointList = AZStd::vector<SurfacePoint>;
using SurfacePointListPerPosition = AZStd::vector<AZStd::pair<AZ::Vector3, SurfacePointList>>;
struct SurfaceDataRegistryEntry
{
AZ::EntityId m_entityId;
AZ::Aabb m_bounds = AZ::Aabb::CreateNull();
SurfaceTagVector m_tags;
};
using SurfaceDataRegistryHandle = AZ::u32;
const SurfaceDataRegistryHandle InvalidSurfaceDataRegistryHandle = 0;
}
@@ -0,0 +1,85 @@
/*
* 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/Component/Component.h>
#include <SurfaceData/SurfaceDataConstants.h>
namespace SurfaceData
{
/**
* Represents a tag value to match with surface materials and/or masks
*/
class SurfaceTag final
{
public:
AZ_CLASS_ALLOCATOR(SurfaceTag, AZ::SystemAllocator, 0);
AZ_RTTI(SurfaceTag, "{67C8C6ED-F32A-443E-A777-1CAE48B22CD7}");
static void Reflect(AZ::ReflectContext* context);
SurfaceTag()
: m_surfaceTagCrc(Constants::s_unassignedTagCrc)
{
}
SurfaceTag(const AZStd::string& value)
: m_surfaceTagCrc(AZ::Crc32(value.data()))
{
}
SurfaceTag(const AZ::Crc32& value)
: m_surfaceTagCrc(value)
{
}
AZ_INLINE bool operator==(const SurfaceTag& other) const;
AZ_INLINE bool operator<(const SurfaceTag& other) const;
AZ_INLINE operator AZ::Crc32() const;
AZ_INLINE operator AZ::u32() const;
void SetTag(const AZStd::string& value)
{
m_surfaceTagCrc = AZ::Crc32(value.data());
}
static AZStd::vector<AZStd::pair<AZ::u32, AZStd::string>> GetRegisteredTags();
private:
bool FindDisplayName(const AZStd::vector<AZStd::pair<AZ::u32, AZStd::string>>& selectableTags, AZStd::string& name) const;
AZStd::vector<AZStd::pair<AZ::u32, AZStd::string>> BuildSelectableTagList() const;
AZStd::string GetDisplayName() const;
AZ::u32 m_surfaceTagCrc;
};
AZ_INLINE bool SurfaceTag::operator==(const SurfaceTag& other) const
{
return other.m_surfaceTagCrc == m_surfaceTagCrc;
}
AZ_INLINE bool SurfaceTag::operator<(const SurfaceTag& other) const
{
return other.m_surfaceTagCrc < m_surfaceTagCrc;
}
AZ_INLINE SurfaceTag::operator AZ::Crc32() const
{
return m_surfaceTagCrc;
}
AZ_INLINE SurfaceTag::operator AZ::u32() const
{
return static_cast<AZ::u32>(m_surfaceTagCrc);
}
}
@@ -0,0 +1,317 @@
/*
* 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 <AzTest/AzTest.h>
#include <AzCore/std/hash.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/Component/TransformBus.h>
#include <LmbrCentral/Shape/ShapeComponentBus.h>
#include <SurfaceData/SurfaceDataSystemRequestBus.h>
#include <AzCore/Casting/lossy_cast.h>
namespace UnitTest
{
struct SurfaceDataTest
: public ::testing::Test
{
protected:
AZ::ComponentApplication m_app;
AZ::Entity* m_systemEntity = nullptr;
void SetUp() override
{
AZ::ComponentApplication::Descriptor appDesc;
appDesc.m_memoryBlocksByteSize = 128 * 1024 * 1024;
m_systemEntity = m_app.Create(appDesc);
m_app.AddEntity(m_systemEntity);
}
void TearDown() override
{
m_app.Destroy();
m_systemEntity = nullptr;
}
AZStd::unique_ptr<AZ::Entity> CreateEntity()
{
return AZStd::make_unique<AZ::Entity>();
}
void ActivateEntity(AZ::Entity* entity)
{
entity->Init();
EXPECT_EQ(AZ::Entity::State::Init, entity->GetState());
entity->Activate();
EXPECT_EQ(AZ::Entity::State::Active, entity->GetState());
}
template <typename Component, typename Configuration>
AZ::Component* CreateComponent(AZ::Entity* entity, const Configuration& config)
{
m_app.RegisterComponentDescriptor(Component::CreateDescriptor());
return entity->CreateComponent<Component>(config);
}
template <typename Component>
AZ::Component* CreateComponent(AZ::Entity* entity)
{
m_app.RegisterComponentDescriptor(Component::CreateDescriptor());
return entity->CreateComponent<Component>();
}
};
struct MockShapeComponentHandler
: public LmbrCentral::ShapeComponentRequestsBus::Handler
{
MockShapeComponentHandler(const AZ::EntityId& id)
{
BusConnect(id);
}
~MockShapeComponentHandler() override
{
BusDisconnect();
}
AZ::Aabb m_GetLocalBounds = AZ::Aabb::CreateCenterRadius(AZ::Vector3::CreateZero(), 0.5f);
AZ::Transform m_GetTransform = AZ::Transform::CreateIdentity();
void GetTransformAndLocalBounds(AZ::Transform& transform, AZ::Aabb& bounds) override
{
transform = m_GetTransform;
bounds = m_GetLocalBounds;
}
AZ::Crc32 m_GetShapeType = AZ_CRC("MockShapeComponentHandler", 0x5189d279);
AZ::Crc32 GetShapeType() override
{
return m_GetShapeType;
}
AZ::Aabb m_GetEncompassingAabb = AZ::Aabb::CreateCenterRadius(AZ::Vector3::CreateZero(), 0.5f);
AZ::Aabb GetEncompassingAabb() override
{
return m_GetEncompassingAabb;
}
bool IsPointInside(const AZ::Vector3& point) override
{
return m_GetEncompassingAabb.Contains(point);
}
float DistanceSquaredFromPoint(const AZ::Vector3& point) override
{
return m_GetEncompassingAabb.GetDistanceSq(point);
}
};
struct MockShapeComponent
: public AZ::Component
{
public:
AZ_COMPONENT(MockShapeComponent, "{DD9590BC-916B-4EFA-98B8-AC5023941672}", AZ::Component);
void Activate() override {}
void Deactivate() override {}
static void Reflect(AZ::ReflectContext* reflect) { AZ_UNUSED(reflect); }
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("ShapeService", 0xe86aa5fe));
}
};
struct MockTransformHandler
: public AZ::TransformBus::Handler
{
~MockTransformHandler()
{
AZ::TransformBus::Handler::BusDisconnect();
}
AZ::Transform m_GetLocalTMOutput = AZ::Transform::CreateIdentity();
const AZ::Transform & GetLocalTM() override
{
return m_GetLocalTMOutput;
}
AZ::Transform m_GetWorldTMOutput = AZ::Transform::CreateIdentity();
const AZ::Transform & GetWorldTM() override
{
return m_GetWorldTMOutput;
}
bool IsStaticTransform() override
{
return false;
}
bool IsPositionInterpolated() override
{
return false;
}
bool IsRotationInterpolated() override
{
return false;
}
};
struct MockSurfaceDataSystem
: public SurfaceData::SurfaceDataSystemRequestBus::Handler
{
MockSurfaceDataSystem()
{
BusConnect();
}
~MockSurfaceDataSystem()
{
BusDisconnect();
}
AZStd::unordered_map<AZStd::pair<float, float>, SurfaceData::SurfacePointList> m_GetSurfacePoints;
void GetSurfacePoints(const AZ::Vector3& inPosition, [[maybe_unused]] const SurfaceData::SurfaceTagVector& masks, SurfaceData::SurfacePointList& surfacePointList) const override
{
auto surfacePoints = m_GetSurfacePoints.find(AZStd::make_pair(inPosition.GetX(), inPosition.GetY()));
if (surfacePoints != m_GetSurfacePoints.end())
{
surfacePointList = surfacePoints->second;
}
}
void GetSurfacePointsFromRegion([[maybe_unused]] const AZ::Aabb& inRegion, [[maybe_unused]] const AZ::Vector2 stepSize, [[maybe_unused]] const SurfaceData::SurfaceTagVector& desiredTags,
[[maybe_unused]] SurfaceData::SurfacePointListPerPosition& surfacePointListPerPosition) const override
{
}
SurfaceData::SurfaceDataRegistryHandle RegisterSurfaceDataProvider(const SurfaceData::SurfaceDataRegistryEntry& entry) override
{
return RegisterEntry(entry, m_providers);
}
void UnregisterSurfaceDataProvider(const SurfaceData::SurfaceDataRegistryHandle& handle) override
{
UnregisterEntry(handle, m_providers);
}
SurfaceData::SurfaceDataRegistryHandle RegisterSurfaceDataModifier(const SurfaceData::SurfaceDataRegistryEntry& entry) override
{
return RegisterEntry(entry, m_modifiers);
}
void UnregisterSurfaceDataModifier(const SurfaceData::SurfaceDataRegistryHandle& handle) override
{
UnregisterEntry(handle, m_modifiers);
}
void UpdateSurfaceDataModifier(const SurfaceData::SurfaceDataRegistryHandle& handle, const SurfaceData::SurfaceDataRegistryEntry& entry) override
{
UpdateEntry(handle, entry, m_providers);
}
void UpdateSurfaceDataProvider(const SurfaceData::SurfaceDataRegistryHandle& handle, const SurfaceData::SurfaceDataRegistryEntry& entry) override
{
UpdateEntry(handle, entry, m_modifiers);
}
void RefreshSurfaceData([[maybe_unused]] const AZ::Aabb& dirtyBounds) override
{
}
SurfaceData::SurfaceDataRegistryHandle GetSurfaceProviderHandle(AZ::EntityId id)
{
return GetEntryHandle(id, m_providers);
}
SurfaceData::SurfaceDataRegistryHandle GetSurfaceModifierHandle(AZ::EntityId id)
{
return GetEntryHandle(id, m_modifiers);
}
SurfaceData::SurfaceDataRegistryEntry GetSurfaceProviderEntry(AZ::EntityId id)
{
return GetEntry(id, m_providers);
}
SurfaceData::SurfaceDataRegistryEntry GetSurfaceModifierEntry(AZ::EntityId id)
{
return GetEntry(id, m_modifiers);
}
protected:
AZStd::vector<SurfaceData::SurfaceDataRegistryEntry> m_providers;
AZStd::vector<SurfaceData::SurfaceDataRegistryEntry> m_modifiers;
SurfaceData::SurfaceDataRegistryHandle RegisterEntry(const SurfaceData::SurfaceDataRegistryEntry& entry, AZStd::vector<SurfaceData::SurfaceDataRegistryEntry>& entryList)
{
// Keep a list of registered entries. Use the "list index + 1" as the handle. (We add +1 because 0 is used to mean "invalid handle")
entryList.emplace_back(entry);
return entryList.size();
}
void UnregisterEntry(const SurfaceData::SurfaceDataRegistryHandle& handle, AZStd::vector<SurfaceData::SurfaceDataRegistryEntry>& entryList)
{
// We don't actually remove the entry from our list because we use handles as indices, so the indices can't change.
// Clearing out the entity Id should be good enough.
uint32 index = static_cast<uint32>(handle) - 1;
if (index < entryList.size())
{
entryList[index].m_entityId = AZ::EntityId();
}
}
void UpdateEntry(const SurfaceData::SurfaceDataRegistryHandle& handle, const SurfaceData::SurfaceDataRegistryEntry& entry,
AZStd::vector<SurfaceData::SurfaceDataRegistryEntry>& entryList)
{
uint32 index = static_cast<uint32>(handle) - 1;
if (index < entryList.size())
{
entryList[index] = entry;
}
}
SurfaceData::SurfaceDataRegistryHandle GetEntryHandle(AZ::EntityId id, const AZStd::vector<SurfaceData::SurfaceDataRegistryEntry>& entryList)
{
// Look up the requested entity Id and see if we have a registered surface entry with that handle. If so, return the handle.
auto result = AZStd::find_if(entryList.begin(), entryList.end(), [this, id](const SurfaceData::SurfaceDataRegistryEntry& entry) { return entry.m_entityId == id; });
if (result == entryList.end())
{
return SurfaceData::InvalidSurfaceDataRegistryHandle;
}
else
{
// We use "index + 1" as our handle
return static_cast<SurfaceData::SurfaceDataRegistryHandle>(result - entryList.begin() + 1);
}
}
SurfaceData::SurfaceDataRegistryEntry GetEntry(AZ::EntityId id, const AZStd::vector<SurfaceData::SurfaceDataRegistryEntry>& entryList)
{
SurfaceData::SurfaceDataRegistryHandle handle = GetEntryHandle(id, entryList);
if (handle != SurfaceData::InvalidSurfaceDataRegistryHandle)
{
return entryList[handle - 1];
}
else
{
SurfaceData::SurfaceDataRegistryEntry emptyEntry;
return emptyEntry;
}
}
};
}
@@ -0,0 +1,261 @@
/*
* 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 <SurfaceData/SurfaceDataTypes.h>
#include <AzCore/Math/MathUtils.h>
#include <AzCore/Math/IntersectSegment.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Math/Vector3.h>
#include <LmbrCentral/Rendering/MeshAsset.h>
#include <IStatObj.h>
#include <MathConversion.h>
namespace SurfaceData
{
AZ_INLINE bool GetQuadListRayIntersection(
const AZStd::vector<AZ::Vector3>& vertices,
const AZ::Vector3& rayOrigin,
const AZ::Vector3& rayDirection,
const float& rayMaxRange,
AZ::Vector3& outPosition,
AZ::Vector3& outNormal)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Entity);
const size_t vertexCount = vertices.size();
if (vertexCount > 0 && vertexCount % 4 == 0)
{
// Make sure our raycast segment is at least 1 mm long. If we have a 0-length ray, we'll never intersect.
const float adjustedMaxRange = AZStd::max(0.001f, rayMaxRange);
const AZ::Vector3 rayLength = rayDirection * adjustedMaxRange;
const AZ::Vector3 rayEnd = rayOrigin + rayLength;
for (size_t vertexIndex = 0; vertexIndex < vertexCount; vertexIndex += 4)
{
// This could potentially be optimized further with a single segment / quad intersection check.
// Unfortunately, AZ::Intersect::IntersectRayQuad() currently returns different
// (and worse) results than IntersectSegmentTriangle. It might be that our surface
// quads aren't actually planar, or it might just be a precision or winding order issue.
float resultDistance = 0.0f;
if (AZ::Intersect::IntersectSegmentTriangle(
rayOrigin,
rayEnd,
vertices[vertexIndex + 0],
vertices[vertexIndex + 2],
vertices[vertexIndex + 3],
outNormal,
resultDistance))
{
outPosition = rayOrigin + (rayLength * resultDistance);
return true;
}
resultDistance = 0.0f;
if (AZ::Intersect::IntersectSegmentTriangle(
rayOrigin,
rayEnd,
vertices[vertexIndex + 0],
vertices[vertexIndex + 3],
vertices[vertexIndex + 1],
outNormal,
resultDistance))
{
outPosition = rayOrigin + (rayLength * resultDistance);
return true;
}
}
}
return false;
}
AZ_INLINE bool GetMeshRayIntersection(
const LmbrCentral::MeshAsset& meshAsset,
const AZ::Transform& meshTransform,
const AZ::Transform& meshTransformInverse,
const AZ::Vector3& rayOrigin,
const AZ::Vector3& rayDirection,
AZ::Vector3& outPosition,
AZ::Vector3& outNormal)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Entity);
IStatObj* pStatObj = meshAsset.m_statObj.get();
if (pStatObj)
{
const Vec3 rayOriginLocal = AZVec3ToLYVec3(meshTransformInverse.TransformPoint(rayOrigin));
const Vec3 rayDirectionLocal = AZVec3ToLYVec3(meshTransformInverse.TransformVector(rayDirection).GetNormalized());
SRayHitInfo hitInfo = {};
hitInfo.inReferencePoint = rayOriginLocal;
hitInfo.inRay = Ray(rayOriginLocal, rayDirectionLocal);
if (pStatObj->RayIntersection(hitInfo))
{
outPosition = meshTransform.TransformPoint(LYVec3ToAZVec3(hitInfo.vHitPos));
outNormal = meshTransform.TransformVector(LYVec3ToAZVec3(hitInfo.vHitNormal)).GetNormalized();
return true;
}
}
return false;
}
AZ_INLINE void AddMaxValueForMasks(SurfaceTagWeightMap& masks, const AZ::Crc32 tag, const float value)
{
const auto maskItr = masks.find(tag);
const float valueOld = maskItr != masks.end() ? maskItr->second : 0.0f;
masks[tag] = AZ::GetMax(value, valueOld);
}
AZ_INLINE void AddMaxValueForMasks(SurfaceTagWeightMap& masks, const SurfaceTagVector& tags, const float value)
{
for (const auto& tag : tags)
{
AddMaxValueForMasks(masks, tag, value);
}
}
AZ_INLINE void AddMaxValueForMasks(SurfaceTagWeightMap& outMasks, const SurfaceTagWeightMap& inMasks)
{
for (const auto& inMask : inMasks)
{
AddMaxValueForMasks(outMasks, inMask.first, inMask.second);
}
}
template<typename Container, typename Element>
AZ_INLINE void AddItemIfNotFound(Container& container, const Element& element)
{
if (AZStd::find(container.begin(), container.end(), element) == container.end())
{
container.insert(container.end(), element);
}
}
template<typename SourceContainer>
AZ_INLINE bool HasMatchingTag(const SourceContainer& sourceTags, const AZ::Crc32& sampleTag)
{
return AZStd::find(sourceTags.begin(), sourceTags.end(), sampleTag) != sourceTags.end();
}
template<typename SourceContainer, typename SampleContainer>
AZ_INLINE bool HasMatchingTags(const SourceContainer& sourceTags, const SampleContainer& sampleTags)
{
for (const auto& sampleTag : sampleTags)
{
if (HasMatchingTag(sourceTags, sampleTag))
{
return true;
}
}
return false;
}
AZ_INLINE bool HasMatchingTag(const SurfaceTagWeightMap& sourceTags, const AZ::Crc32& sampleTag)
{
return sourceTags.find(sampleTag) != sourceTags.end();
}
template<typename SampleContainer>
AZ_INLINE bool HasMatchingTags(const SurfaceTagWeightMap& sourceTags, const SampleContainer& sampleTags)
{
for (const auto& sampleTag : sampleTags)
{
if (HasMatchingTag(sourceTags, sampleTag))
{
return true;
}
}
return false;
}
AZ_INLINE bool HasMatchingTag(const SurfaceTagWeightMap& sourceTags, const AZ::Crc32& sampleTag, float valueMin, float valueMax)
{
auto maskItr = sourceTags.find(sampleTag);
return maskItr != sourceTags.end() && valueMin <= maskItr->second && valueMax >= maskItr->second;
}
template<typename SampleContainer>
AZ_INLINE bool HasMatchingTags(const SurfaceTagWeightMap& sourceTags, const SampleContainer& sampleTags, float valueMin, float valueMax)
{
for (const auto& sampleTag : sampleTags)
{
if (HasMatchingTag(sourceTags, sampleTag, valueMin, valueMax))
{
return true;
}
}
return false;
}
template<typename SourceContainer>
AZ_INLINE void RemoveUnassignedTags(const SourceContainer& sourceTags)
{
sourceTags.erase(AZStd::remove(sourceTags.begin(), sourceTags.end(), Constants::s_unassignedTagCrc), sourceTags.end());
}
template<typename SourceContainer>
AZ_INLINE bool HasValidTags(const SourceContainer& sourceTags)
{
for (const auto& sourceTag : sourceTags)
{
if (sourceTag != Constants::s_unassignedTagCrc)
{
return true;
}
}
return false;
}
AZ_INLINE bool HasValidTags(const SurfaceTagWeightMap& sourceTags)
{
for (const auto& sourceTag : sourceTags)
{
if (sourceTag.first != Constants::s_unassignedTagCrc)
{
return true;
}
}
return false;
}
// Utility method to compare two AABBs for overlapping XY coordinates while ignoring the Z coordinates.
AZ_INLINE bool AabbOverlaps2D(const AZ::Aabb& box1, const AZ::Aabb& box2)
{
return box1.GetMin().GetX() <= box2.GetMax().GetX() &&
box1.GetMin().GetY() <= box2.GetMax().GetY() &&
box1.GetMax().GetX() >= box2.GetMin().GetX() &&
box1.GetMax().GetY() >= box2.GetMin().GetY();
}
// Utility method to compare an AABB and a point for overlapping XY coordinates while ignoring the Z coordinates.
AZ_INLINE bool AabbContains2D(const AZ::Aabb& box, const AZ::Vector2& point)
{
return box.GetMin().GetX() <= point.GetX() &&
box.GetMin().GetY() <= point.GetY() &&
box.GetMax().GetX() >= point.GetX() &&
box.GetMax().GetY() >= point.GetY();
}
// Utility method to compare an AABB and a point for overlapping XY coordinates while ignoring the Z coordinates.
AZ_INLINE bool AabbContains2D(const AZ::Aabb& box, const AZ::Vector3& point)
{
return box.GetMin().GetX() <= point.GetX() &&
box.GetMin().GetY() <= point.GetY() &&
box.GetMax().GetX() >= point.GetX() &&
box.GetMax().GetY() >= point.GetY();
}
}