Merge branch 'main' into Spawnable/ProductDependency
This commit is contained in:
@@ -189,7 +189,7 @@ namespace AZ
|
||||
if (!WasLoadSuccess(result.GetOutcome()))
|
||||
{
|
||||
// This if is a hack around fault in the JSON serialization system
|
||||
// Jira: https://jira.agscollab.com/browse/LY-106587
|
||||
// Jira: LY-106587
|
||||
if (message != "No part of the string could be interpreted as a uuid.")
|
||||
{
|
||||
deserializeError.append(message);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Math/Uuid.h>
|
||||
#include <AzCore/Preprocessor/Enum.h>
|
||||
#include <AzCore/std/containers/bitset.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/string/string_view.h>
|
||||
@@ -216,16 +217,14 @@ namespace AZ
|
||||
/**
|
||||
* Setting for each reference (Asset<T>) to control loading of referenced assets during serialization.
|
||||
*/
|
||||
enum class AssetLoadBehavior : u8
|
||||
{
|
||||
PreLoad = 0, ///< Serializer will "Pre load" dependencies, asset containers may load in parallel but will not signal AssetReady
|
||||
QueueLoad = 1, ///< Serializer will queue an asynchronous load of the referenced asset and return the object to the user. User code should use the \ref AZ::Data::AssetBus to monitor for when it's ready.
|
||||
NoLoad = 2, ///< Serializer will load reference information, but asset loading will be left to the user. User code should call Asset<T>::QueueLoad and use the \ref AZ::Data::AssetBus to monitor for when it's ready.
|
||||
///< AssetContainers will skip NoLoad dependencies
|
||||
|
||||
AZ_ENUM_WITH_UNDERLYING_TYPE(AssetLoadBehavior, u8,
|
||||
(PreLoad, 0), ///< Serializer will "Pre load" dependencies, asset containers may load in parallel but will not signal AssetReady
|
||||
(QueueLoad, 1), ///< Serializer will queue an asynchronous load of the referenced asset and return the object to the user. User code should use the \ref AZ::Data::AssetBus to monitor for when it's ready.
|
||||
(NoLoad, 2), ///< Serializer will load reference information, but asset loading will be left to the user. User code should call Asset<T>::QueueLoad and use the \ref AZ::Data::AssetBus to monitor for when it's ready.
|
||||
///< AssetContainers will skip NoLoad dependencies
|
||||
Count,
|
||||
Default = QueueLoad,
|
||||
};
|
||||
(Default, QueueLoad)
|
||||
);
|
||||
|
||||
struct AssetFilterInfo
|
||||
{
|
||||
@@ -1222,6 +1221,7 @@ namespace AZ
|
||||
} // namespace ProductDependencyInfo
|
||||
} // namespace Data
|
||||
|
||||
AZ_TYPE_INFO_SPECIALIZE(Data::AssetLoadBehavior, "{DAF9ECED-FEF3-4D7A-A220-8CFD6A5E6DA1}");
|
||||
AZ_TYPE_INFO_TEMPLATE_WITH_NAME(AZ::Data::Asset, "Asset", "{C891BF19-B60C-45E2-BFD0-027D15DDC939}", AZ_TYPE_INFO_CLASS);
|
||||
|
||||
} // namespace AZ
|
||||
|
||||
@@ -239,8 +239,13 @@ namespace AZ
|
||||
return;
|
||||
}
|
||||
|
||||
CheckReady();
|
||||
m_initComplete = true;
|
||||
|
||||
// *After* setting initComplete to true, check to see if the assets are already ready.
|
||||
// This check needs to wait until after setting initComplete because if they *are* ready, we want the final call to
|
||||
// RemoveWaitingAsset to trigger the OnAssetContainerReady/Canceled event. If we call CheckReady() *before* setting
|
||||
// initComplete, if all the assets are ready, the event will never get triggered.
|
||||
CheckReady();
|
||||
}
|
||||
|
||||
bool AssetContainer::IsReady() const
|
||||
|
||||
@@ -70,6 +70,17 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const AZ::Data::AssetLoadBehavior autoLoadBehavior = instance->GetAutoLoadBehavior();
|
||||
const AZ::Data::AssetLoadBehavior defaultAutoLoadBehavior = defaultInstance ?
|
||||
defaultInstance->GetAutoLoadBehavior() : AZ::Data::AssetLoadBehavior::Default;
|
||||
|
||||
result.Combine(
|
||||
ContinueStoringToJsonObjectField(outputValue, "loadBehavior",
|
||||
&autoLoadBehavior, &defaultAutoLoadBehavior,
|
||||
azrtti_typeid<Data::AssetLoadBehavior>(), context));
|
||||
}
|
||||
|
||||
{
|
||||
ScopedContextPath subPathHint(context, "m_assetHint");
|
||||
const AZStd::string* hint = &instance->GetHint();
|
||||
@@ -100,14 +111,28 @@ namespace AZ
|
||||
AssetId id;
|
||||
JSR::ResultCode result(JSR::Tasks::ReadField);
|
||||
|
||||
SerializedAssetTracker* assetTracker =
|
||||
context.GetMetadata().Find<SerializedAssetTracker>();
|
||||
|
||||
{
|
||||
Data::AssetLoadBehavior loadBehavior = instance->GetAutoLoadBehavior();
|
||||
|
||||
result =
|
||||
ContinueLoadingFromJsonObjectField(&loadBehavior,
|
||||
azrtti_typeid<Data::AssetLoadBehavior>(),
|
||||
inputValue, "loadBehavior", context);
|
||||
|
||||
instance->SetAutoLoadBehavior(loadBehavior);
|
||||
}
|
||||
|
||||
auto it = inputValue.FindMember("assetId");
|
||||
if (it != inputValue.MemberEnd())
|
||||
{
|
||||
ScopedContextPath subPath(context, "assetId");
|
||||
result = ContinueLoading(&id, azrtti_typeid<AssetId>(), it->value, context);
|
||||
result.Combine(ContinueLoading(&id, azrtti_typeid<AssetId>(), it->value, context));
|
||||
if (!id.m_guid.IsNull())
|
||||
{
|
||||
*instance = AssetManager::Instance().FindOrCreateAsset(id, instance->GetType(), AssetLoadBehavior::NoLoad);
|
||||
*instance = AssetManager::Instance().FindOrCreateAsset(id, instance->GetType(), instance->GetAutoLoadBehavior());
|
||||
|
||||
|
||||
result.Combine(context.Report(result, "Successfully created Asset<T> with id."));
|
||||
@@ -142,6 +167,11 @@ namespace AZ
|
||||
"The asset hint is missing for Asset<T>, so it will be left empty."));
|
||||
}
|
||||
|
||||
if (assetTracker)
|
||||
{
|
||||
assetTracker->AddAsset(*instance);
|
||||
}
|
||||
|
||||
bool success = result.GetOutcome() <= JSR::Outcomes::PartialSkip;
|
||||
bool defaulted = result.GetOutcome() == JSR::Outcomes::DefaultsUsed || result.GetOutcome() == JSR::Outcomes::PartialDefaults;
|
||||
AZStd::string_view message =
|
||||
@@ -150,5 +180,20 @@ namespace AZ
|
||||
"Not enough information was available to create an instance of Asset<T> or data was corrupted.";
|
||||
return context.Report(result, message);
|
||||
}
|
||||
|
||||
void SerializedAssetTracker::AddAsset(Asset<AssetData>& asset)
|
||||
{
|
||||
m_serializedAssets.emplace_back(asset);
|
||||
}
|
||||
|
||||
const AZStd::vector<Asset<AssetData>>& SerializedAssetTracker::GetTrackedAssets() const
|
||||
{
|
||||
return m_serializedAssets;
|
||||
}
|
||||
|
||||
AZStd::vector<Asset<AssetData>>& SerializedAssetTracker::GetTrackedAssets()
|
||||
{
|
||||
return m_serializedAssets;
|
||||
}
|
||||
} // namespace Data
|
||||
} // namespace AZ
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Memory/Memory.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
|
||||
|
||||
namespace AZ
|
||||
@@ -37,5 +38,18 @@ namespace AZ
|
||||
private:
|
||||
JsonSerializationResult::Result LoadAsset(void* outputValue, const rapidjson::Value& inputValue, JsonDeserializerContext& context);
|
||||
};
|
||||
|
||||
class SerializedAssetTracker final
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(SerializedAssetTracker, "{1E067091-8C0A-44B1-A455-6E97663F6963}");
|
||||
|
||||
void AddAsset(Asset<AssetData>& asset);
|
||||
AZStd::vector<Asset<AssetData>>& GetTrackedAssets();
|
||||
const AZStd::vector<Asset<AssetData>>& GetTrackedAssets() const;
|
||||
|
||||
private:
|
||||
AZStd::vector<Asset<AssetData>> m_serializedAssets;
|
||||
};
|
||||
} // namespace Data
|
||||
} // namespace AZ
|
||||
|
||||
@@ -1454,32 +1454,48 @@ namespace AZ
|
||||
//=========================================================================
|
||||
void AssetManager::ReloadAssetFromData(const Asset<AssetData>& asset)
|
||||
{
|
||||
AZ_Assert(asset.Get(), "Asset data for reload is missing.");
|
||||
AZStd::scoped_lock<AZStd::recursive_mutex> assetLock(m_assetMutex);
|
||||
AZ_Assert(m_assets.find(asset.GetId()) != m_assets.end(), "Unable to reload asset %s because its not in the AssetManager's asset list.", asset.ToString<AZStd::string>().c_str());
|
||||
AZ_Assert(m_assets.find(asset.GetId()) == m_assets.end() || asset->RTTI_GetType() == m_assets.find(asset.GetId())->second->RTTI_GetType(),
|
||||
"New and old data types are mismatched!");
|
||||
bool shouldAssignAssetData = false;
|
||||
|
||||
auto found = m_assets.find(asset.GetId());
|
||||
if ((found == m_assets.end()) || (asset->RTTI_GetType() != found->second->RTTI_GetType()))
|
||||
{
|
||||
return; // this will just lead to crashes down the line and the above asserts cover this.
|
||||
}
|
||||
AZ_Assert(asset.Get(), "Asset data for reload is missing.");
|
||||
AZStd::scoped_lock<AZStd::recursive_mutex> assetLock(m_assetMutex);
|
||||
AZ_Assert(
|
||||
m_assets.find(asset.GetId()) != m_assets.end(),
|
||||
"Unable to reload asset %s because it's not in the AssetManager's asset list.", asset.ToString<AZStd::string>().c_str());
|
||||
AZ_Assert(
|
||||
m_assets.find(asset.GetId()) == m_assets.end() ||
|
||||
asset->RTTI_GetType() == m_assets.find(asset.GetId())->second->RTTI_GetType(),
|
||||
"New and old data types are mismatched!");
|
||||
|
||||
AssetData* newData = asset.Get();
|
||||
|
||||
if (found->second != newData)
|
||||
{
|
||||
// Notify users that we are about to change asset
|
||||
AssetBus::Event(asset.GetId(), &AssetBus::Events::OnAssetPreReload, asset);
|
||||
|
||||
// Resolve the asset handler and account for the new asset instance.
|
||||
auto found = m_assets.find(asset.GetId());
|
||||
if ((found == m_assets.end()) || (asset->RTTI_GetType() != found->second->RTTI_GetType()))
|
||||
{
|
||||
AssetHandlerMap::iterator handlerIt = m_handlers.find(newData->GetType());
|
||||
AZ_Assert(handlerIt != m_handlers.end(), "No handler was registered for this asset [type:%s id:%s]!",
|
||||
newData->GetType().ToString<AZ::OSString>().c_str(), newData->GetId().ToString<AZ::OSString>().c_str());
|
||||
return; // this will just lead to crashes down the line and the above asserts cover this.
|
||||
}
|
||||
|
||||
AssetData* newData = asset.Get();
|
||||
|
||||
if (found->second != newData)
|
||||
{
|
||||
// Notify users that we are about to change asset
|
||||
AssetBus::Event(asset.GetId(), &AssetBus::Events::OnAssetPreReload, asset);
|
||||
|
||||
// Resolve the asset handler and account for the new asset instance.
|
||||
{
|
||||
AssetHandlerMap::iterator handlerIt = m_handlers.find(newData->GetType());
|
||||
AZ_Assert(
|
||||
handlerIt != m_handlers.end(), "No handler was registered for this asset [type:%s id:%s]!",
|
||||
newData->GetType().ToString<AZ::OSString>().c_str(), newData->GetId().ToString<AZ::OSString>().c_str());
|
||||
}
|
||||
|
||||
shouldAssignAssetData = true;
|
||||
}
|
||||
}
|
||||
|
||||
// We specifically perform this outside of the m_assetMutex lock so that the lock isn't held at the point that
|
||||
// OnAssetReload is triggered inside of AssignAssetData. Otherwise, we open up a high potential for deadlocks.
|
||||
if (shouldAssignAssetData)
|
||||
{
|
||||
AssignAssetData(asset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <AzCore/Asset/AssetJsonSerializer.h>
|
||||
#include <AzCore/Asset/AssetManagerComponent.h>
|
||||
#include <AzCore/Asset/AssetManagerBus.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Preprocessor/EnumReflectUtils.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
@@ -24,6 +24,11 @@
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Data
|
||||
{
|
||||
AZ_ENUM_DEFINE_REFLECT_UTILITIES(AssetLoadBehavior);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// AssetDatabaseComponent
|
||||
// [6/25/2012]
|
||||
@@ -99,6 +104,8 @@ namespace AZ
|
||||
|
||||
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
|
||||
{
|
||||
AZ::Data::AssetLoadBehaviorReflect(*serializeContext);
|
||||
|
||||
serializeContext->RegisterGenericType<Data::Asset<Data::AssetData>>();
|
||||
|
||||
serializeContext->Class<AssetManagerComponent, AZ::Component>()
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Math/Sfmt.h>
|
||||
#include <AzCore/Math/Crc.h>
|
||||
|
||||
@@ -173,7 +174,11 @@ namespace AZ
|
||||
//=========================================================================
|
||||
void ComponentDescriptor::ReleaseDescriptor()
|
||||
{
|
||||
EBUS_EVENT(ComponentApplicationBus, UnregisterComponentDescriptor, this);
|
||||
AZ::ComponentApplicationRequests* componentApplication = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
|
||||
if (componentApplication != nullptr)
|
||||
{
|
||||
componentApplication->UnregisterComponentDescriptor(this);
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
@@ -526,6 +526,11 @@ namespace AZ
|
||||
// are destroyed
|
||||
m_commandLine = {};
|
||||
|
||||
m_entityAddedEvent.DisconnectAllHandlers();
|
||||
m_entityRemovedEvent.DisconnectAllHandlers();
|
||||
m_entityActivatedEvent.DisconnectAllHandlers();
|
||||
m_entityDeactivatedEvent.DisconnectAllHandlers();
|
||||
|
||||
DestroyAllocator();
|
||||
}
|
||||
|
||||
@@ -980,6 +985,26 @@ namespace AZ
|
||||
handler.Connect(m_entityRemovedEvent);
|
||||
}
|
||||
|
||||
void ComponentApplication::RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler& handler)
|
||||
{
|
||||
handler.Connect(m_entityActivatedEvent);
|
||||
}
|
||||
|
||||
void ComponentApplication::RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler& handler)
|
||||
{
|
||||
handler.Connect(m_entityDeactivatedEvent);
|
||||
}
|
||||
|
||||
void ComponentApplication::SignalEntityActivated(AZ::Entity* entity)
|
||||
{
|
||||
m_entityActivatedEvent.Signal(entity);
|
||||
}
|
||||
|
||||
void ComponentApplication::SignalEntityDeactivated(AZ::Entity* entity)
|
||||
{
|
||||
m_entityDeactivatedEvent.Signal(entity);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// AddEntity
|
||||
// [5/30/2012]
|
||||
|
||||
@@ -204,6 +204,10 @@ namespace AZ
|
||||
void UnregisterComponentDescriptor(const ComponentDescriptor* descriptor) override final;
|
||||
void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler& handler) override final;
|
||||
void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler& handler) override final;
|
||||
void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler& handler) override final;
|
||||
void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler& handler) override final;
|
||||
void SignalEntityActivated(Entity* entity) override final;
|
||||
void SignalEntityDeactivated(Entity* entity) override final;
|
||||
bool AddEntity(Entity* entity) override;
|
||||
bool RemoveEntity(Entity* entity) override;
|
||||
bool DeleteEntity(const EntityId& id) override;
|
||||
@@ -382,6 +386,8 @@ namespace AZ
|
||||
AZStd::unique_ptr<SettingsRegistryInterface> m_settingsRegistry;
|
||||
EntityAddedEvent m_entityAddedEvent;
|
||||
EntityRemovedEvent m_entityRemovedEvent;
|
||||
EntityAddedEvent m_entityActivatedEvent;
|
||||
EntityRemovedEvent m_entityDeactivatedEvent;
|
||||
AZ::IConsole* m_console{};
|
||||
Descriptor m_descriptor;
|
||||
bool m_isStarted{ false };
|
||||
|
||||
@@ -72,6 +72,8 @@ namespace AZ
|
||||
|
||||
using EntityAddedEvent = AZ::Event<AZ::Entity*>;
|
||||
using EntityRemovedEvent = AZ::Event<AZ::Entity*>;
|
||||
using EntityActivatedEvent = AZ::Event<AZ::Entity*>;
|
||||
using EntityDeactivatedEvent = AZ::Event<AZ::Entity*>;
|
||||
|
||||
//! Interface that components can use to make requests of the main application.
|
||||
class ComponentApplicationRequests
|
||||
@@ -102,6 +104,22 @@ namespace AZ
|
||||
//! @param handler the event handler to signal.
|
||||
virtual void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler& handler) = 0;
|
||||
|
||||
//! Registers an event handler that will be signalled whenever an entity is added.
|
||||
//! @param handler the event handler to signal.
|
||||
virtual void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler& handler) = 0;
|
||||
|
||||
//! Registers an event handler that will be signalled whenever an entity is removed.
|
||||
//! @param handler the event handler to signal.
|
||||
virtual void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler& handler) = 0;
|
||||
|
||||
//! Signals that the provided entity has been activated.
|
||||
//! @param entity the entity being activated.
|
||||
virtual void SignalEntityActivated(AZ::Entity* entity) = 0;
|
||||
|
||||
//! Signals that the provided entity has been deactivated.
|
||||
//! @param entity the entity being deactivated.
|
||||
virtual void SignalEntityDeactivated(AZ::Entity* entity) = 0;
|
||||
|
||||
//! Adds an entity to the application's registry.
|
||||
//! Calling Init() on an entity automatically performs this operation.
|
||||
//! @param entity A pointer to the entity to add to the application's registry.
|
||||
|
||||
@@ -112,7 +112,11 @@ namespace AZ
|
||||
{
|
||||
EBUS_EVENT(EntitySystemBus, OnEntityDestruction, m_id);
|
||||
EBUS_EVENT_ID(m_id, EntityBus, OnEntityDestruction, m_id);
|
||||
EBUS_EVENT(ComponentApplicationBus, RemoveEntity, this);
|
||||
AZ::ComponentApplicationRequests* componentApplication = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
|
||||
if (componentApplication != nullptr)
|
||||
{
|
||||
componentApplication->RemoveEntity(this);
|
||||
}
|
||||
m_stateEvent.Signal(State::Init, State::Destroying);
|
||||
}
|
||||
|
||||
@@ -216,12 +220,22 @@ namespace AZ
|
||||
|
||||
EBUS_EVENT_ID(m_id, EntityBus, OnEntityActivated, m_id);
|
||||
EBUS_EVENT(EntitySystemBus, OnEntityActivated, m_id);
|
||||
AZ::ComponentApplicationRequests* componentApplication = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
|
||||
if (componentApplication != nullptr)
|
||||
{
|
||||
componentApplication->SignalEntityActivated(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Entity::Deactivate()
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzCore);
|
||||
|
||||
AZ::ComponentApplicationRequests* componentApplication = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
|
||||
if (componentApplication != nullptr)
|
||||
{
|
||||
componentApplication->SignalEntityDeactivated(this);
|
||||
}
|
||||
EBUS_EVENT_ID(m_id, EntityBus, OnEntityDeactivated, m_id);
|
||||
EBUS_EVENT(EntitySystemBus, OnEntityDeactivated, m_id);
|
||||
|
||||
|
||||
@@ -126,9 +126,11 @@ namespace AZ
|
||||
char buffer[MaxLogBufferSize];
|
||||
|
||||
const AZStd::size_t length = azvsnprintf(buffer, MaxLogBufferSize, format, args);
|
||||
buffer[AZStd::min<AZStd::size_t>(length, MaxLogBufferSize - 2)] = '\n';
|
||||
buffer[AZStd::min<AZStd::size_t>(length + 1, MaxLogBufferSize - 1)] = '\0';
|
||||
m_logEvent.Signal(level, buffer, file, function, line);
|
||||
|
||||
// Force a new-line before calling the AZ::Debug::Trace functions, as they assume a newline is present
|
||||
buffer[AZStd::min<AZStd::size_t>(length + 1, MaxLogBufferSize - 2)] = '\n';
|
||||
switch (level)
|
||||
{
|
||||
case LogLevel::Warn:
|
||||
@@ -142,8 +144,6 @@ namespace AZ
|
||||
AZ::Debug::Trace::Output("Logger", buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
m_logEvent.Signal(level, buffer, file, function, line);
|
||||
}
|
||||
|
||||
void LoggerSystemComponent::SetLevel(const AZ::ConsoleCommandContainer& arguments)
|
||||
|
||||
@@ -233,6 +233,14 @@ namespace AZ
|
||||
AZ_Assert(handler->m_event == this, "Entry event does not match");
|
||||
handler->Disconnect();
|
||||
}
|
||||
|
||||
// Free up any owned memory
|
||||
AZStd::vector<Handler*> freeHandlers;
|
||||
m_handlers.swap(freeHandlers);
|
||||
AZStd::vector<Handler*> freeAdds;
|
||||
m_addList.swap(freeAdds);
|
||||
AZStd::stack<size_t> freeFree;
|
||||
m_freeList.swap(freeFree);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,485 @@
|
||||
/*
|
||||
* 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/MathMatrixSerializer.h>
|
||||
#include <AzCore/Math/Matrix3x3.h>
|
||||
#include <AzCore/Math/Matrix3x4.h>
|
||||
#include <AzCore/Math/Matrix4x4.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
#include <AzCore/Serialization/Json/StackedString.h>
|
||||
#include <AzCore/std/algorithm.h>
|
||||
#include <AzCore/std/string/osstring.h>
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
|
||||
namespace AZ::JsonMathMatrixSerializerInternal
|
||||
{
|
||||
template<typename MatrixType, size_t RowCount, size_t ColumnCount>
|
||||
JsonSerializationResult::Result LoadArray(MatrixType& output, const rapidjson::Value& inputValue, JsonDeserializerContext& context)
|
||||
{
|
||||
namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
|
||||
|
||||
constexpr size_t ElementCount = RowCount * ColumnCount;
|
||||
static_assert(ElementCount == 9 || ElementCount == 12 || ElementCount == 16,
|
||||
"MathMatrixSerializer only support Matrix3x3, Matrix3x4 and Matrix4x4.");
|
||||
|
||||
rapidjson::SizeType arraySize = inputValue.Size();
|
||||
if (arraySize < ElementCount)
|
||||
{
|
||||
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported,
|
||||
"Not enough numbers in JSON array to load math matrix from.");
|
||||
}
|
||||
|
||||
AZ::BaseJsonSerializer* floatSerializer = context.GetRegistrationContext()->GetSerializerForType(azrtti_typeid<float>());
|
||||
if (!floatSerializer)
|
||||
{
|
||||
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic, "Failed to find the JSON float serializer.");
|
||||
}
|
||||
|
||||
constexpr const char* names[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15"};
|
||||
float values[ElementCount];
|
||||
for (int i = 0; i < ElementCount; ++i)
|
||||
{
|
||||
ScopedContextPath subPath(context, names[i]);
|
||||
JSR::Result intermediate = floatSerializer->Load(values + i, azrtti_typeid<float>(), inputValue[i], context);
|
||||
if (intermediate.GetResultCode().GetProcessing() != JSR::Processing::Completed)
|
||||
{
|
||||
return intermediate;
|
||||
}
|
||||
}
|
||||
|
||||
size_t valueIndex = 0;
|
||||
for (size_t r = 0; r < RowCount; ++r)
|
||||
{
|
||||
for (size_t c = 0; c < ColumnCount; ++c)
|
||||
{
|
||||
output.SetElement(aznumeric_caster(r), aznumeric_caster(c), values[valueIndex++]);
|
||||
}
|
||||
}
|
||||
|
||||
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Success, "Successfully read math matrix.");
|
||||
}
|
||||
|
||||
JsonSerializationResult::Result LoadFloatFromObject(
|
||||
float& output,
|
||||
const rapidjson::Value& inputValue,
|
||||
JsonDeserializerContext& context,
|
||||
const char* name,
|
||||
const char* altName)
|
||||
{
|
||||
namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
|
||||
|
||||
AZ::BaseJsonSerializer* floatSerializer = context.GetRegistrationContext()->GetSerializerForType(azrtti_typeid<float>());
|
||||
if (!floatSerializer)
|
||||
{
|
||||
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic, "Failed to find the json float serializer.");
|
||||
}
|
||||
|
||||
const char* nameUsed = name;
|
||||
JSR::ResultCode result(JSR::Tasks::ReadField);
|
||||
auto iterator = inputValue.FindMember(rapidjson::StringRef(name));
|
||||
if (iterator == inputValue.MemberEnd())
|
||||
{
|
||||
nameUsed = altName;
|
||||
iterator = inputValue.FindMember(rapidjson::StringRef(altName));
|
||||
if (iterator == inputValue.MemberEnd())
|
||||
{
|
||||
// field not found so leave default value
|
||||
result.Combine(JSR::ResultCode(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed));
|
||||
nameUsed = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (nameUsed)
|
||||
{
|
||||
ScopedContextPath subPath(context, nameUsed);
|
||||
JSR::Result intermediate = floatSerializer->Load(&output, azrtti_typeid<float>(), iterator->value, context);
|
||||
if (intermediate.GetResultCode().GetProcessing() != JSR::Processing::Completed)
|
||||
{
|
||||
return intermediate;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Combine(JSR::ResultCode(JSR::Tasks::ReadField, JSR::Outcomes::Success));
|
||||
}
|
||||
}
|
||||
|
||||
return context.Report(result, "Successfully read float.");
|
||||
}
|
||||
|
||||
JsonSerializationResult::Result LoadVector3FromObject(
|
||||
Vector3& output,
|
||||
const rapidjson::Value& inputValue,
|
||||
JsonDeserializerContext& context,
|
||||
AZStd::fixed_vector<AZStd::string_view, 6> names)
|
||||
{
|
||||
namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
|
||||
constexpr size_t ElementCount = 3; // Vector3
|
||||
|
||||
JSR::ResultCode result(JSR::Tasks::ReadField);
|
||||
float values[ElementCount];
|
||||
for (int i = 0; i < ElementCount; ++i)
|
||||
{
|
||||
values[i] = output.GetElement(i);
|
||||
auto name = names[i * 2];
|
||||
auto altName = names[(i * 2) + 1];
|
||||
|
||||
JSR::Result intermediate = LoadFloatFromObject(values[i], inputValue, context, name.data(), altName.data());
|
||||
if (intermediate.GetResultCode().GetProcessing() != JSR::Processing::Completed)
|
||||
{
|
||||
return intermediate;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Combine(JSR::ResultCode(JSR::Tasks::ReadField, JSR::Outcomes::Success));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < ElementCount; ++i)
|
||||
{
|
||||
output.SetElement(i, values[i]);
|
||||
}
|
||||
|
||||
return context.Report(result, "Successfully read math matrix.");
|
||||
}
|
||||
|
||||
JsonSerializationResult::Result LoadQuaternionAndScale(
|
||||
AZ::Quaternion& quaternion,
|
||||
float& scale,
|
||||
const rapidjson::Value& inputValue,
|
||||
JsonDeserializerContext& context)
|
||||
{
|
||||
namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
|
||||
|
||||
JSR::ResultCode result(JSR::Tasks::ReadField);
|
||||
scale = 1.0f;
|
||||
JSR::Result intermediateScale = LoadFloatFromObject(scale, inputValue, context, "scale", "Scale");
|
||||
if (intermediateScale.GetResultCode().GetProcessing() != JSR::Processing::Completed)
|
||||
{
|
||||
return intermediateScale;
|
||||
}
|
||||
result.Combine(intermediateScale);
|
||||
|
||||
if (AZ::IsClose(scale, 0.0f))
|
||||
{
|
||||
result.Combine({ JSR::Tasks::ReadField, JSR::Outcomes::Unsupported });
|
||||
return context.Report(result, "Scale can not be zero.");
|
||||
}
|
||||
|
||||
AZ::Vector3 degreesRollPitchYaw = AZ::Vector3::CreateZero();
|
||||
JSR::Result intermediateDegrees = LoadVector3FromObject(degreesRollPitchYaw, inputValue, context, { "roll", "Roll", "pitch", "Pitch", "yaw", "Yaw" });
|
||||
if (intermediateDegrees.GetResultCode().GetProcessing() != JSR::Processing::Completed)
|
||||
{
|
||||
return intermediateDegrees;
|
||||
}
|
||||
result.Combine(intermediateDegrees);
|
||||
|
||||
// the quaternion should be equivalent to a series of rotations in the order z, then y, then x
|
||||
const AZ::Vector3 eulerRadians = AZ::Vector3DegToRad(degreesRollPitchYaw);
|
||||
quaternion = AZ::Quaternion::CreateRotationX(eulerRadians.GetX()) *
|
||||
AZ::Quaternion::CreateRotationY(eulerRadians.GetY()) *
|
||||
AZ::Quaternion::CreateRotationZ(eulerRadians.GetZ());
|
||||
|
||||
return context.Report(result, "Successfully read math yaw, pitch, roll, and scale.");
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
JsonSerializationResult::Result LoadObject(MatrixType& output, const rapidjson::Value& inputValue, JsonDeserializerContext& context)
|
||||
{
|
||||
namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
|
||||
output = MatrixType::CreateIdentity();
|
||||
|
||||
JSR::ResultCode result(JSR::Tasks::ReadField);
|
||||
float scale;
|
||||
AZ::Quaternion rotation;
|
||||
|
||||
JSR::Result intermediate = LoadQuaternionAndScale(rotation, scale, inputValue, context);
|
||||
if (intermediate.GetResultCode().GetProcessing() != JSR::Processing::Completed)
|
||||
{
|
||||
return intermediate;
|
||||
}
|
||||
result.Combine(intermediate);
|
||||
|
||||
AZ::Vector3 translation = AZ::Vector3::CreateZero();
|
||||
JSR::Result intermediateTranslation = LoadVector3FromObject(translation, inputValue, context, { "x", "X", "y", "Y", "z", "Z" });
|
||||
if (intermediateTranslation.GetResultCode().GetProcessing() != JSR::Processing::Completed)
|
||||
{
|
||||
return intermediateTranslation;
|
||||
}
|
||||
result.Combine(intermediateTranslation);
|
||||
|
||||
// composed a matrix by rotation, then scale, then translation
|
||||
auto matrix = MatrixType::CreateFromQuaternion(rotation);
|
||||
matrix.MultiplyByScale(Vector3{ scale });
|
||||
matrix.SetTranslation(translation);
|
||||
|
||||
if (matrix == MatrixType::CreateIdentity())
|
||||
{
|
||||
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed, "Using identity matrix for empty object.");
|
||||
}
|
||||
|
||||
output = matrix;
|
||||
return context.Report(result, "Successfully read math matrix.");
|
||||
}
|
||||
|
||||
template<>
|
||||
JsonSerializationResult::Result LoadObject<Matrix3x3>(Matrix3x3& output, const rapidjson::Value& inputValue, JsonDeserializerContext& context)
|
||||
{
|
||||
namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
|
||||
output = Matrix3x3::CreateIdentity();
|
||||
|
||||
JSR::ResultCode result(JSR::Tasks::ReadField);
|
||||
float scale;
|
||||
AZ::Quaternion rotation;
|
||||
|
||||
JSR::Result intermediate = LoadQuaternionAndScale(rotation, scale, inputValue, context);
|
||||
if (intermediate.GetResultCode().GetProcessing() != JSR::Processing::Completed)
|
||||
{
|
||||
return intermediate;
|
||||
}
|
||||
result.Combine(intermediate);
|
||||
|
||||
// composed a matrix by rotation then scale
|
||||
auto matrix = Matrix3x3::CreateFromQuaternion(rotation);
|
||||
matrix.MultiplyByScale(Vector3{ scale });
|
||||
|
||||
if (matrix == Matrix3x3::CreateIdentity())
|
||||
{
|
||||
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed, "Using identity matrix for empty object.");
|
||||
}
|
||||
|
||||
output = matrix;
|
||||
return context.Report(result, "Successfully read math matrix.");
|
||||
}
|
||||
|
||||
template<typename MatrixType, size_t RowCount, size_t ColumnCount>
|
||||
JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId,
|
||||
const rapidjson::Value& inputValue, JsonDeserializerContext& context)
|
||||
{
|
||||
namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
|
||||
|
||||
constexpr size_t ElementCount = RowCount * ColumnCount;
|
||||
static_assert(ElementCount == 9 || ElementCount == 12 || ElementCount == 16,
|
||||
"MathMatrixSerializer only support Matrix3x3, Matrix3x4 and Matrix4x4.");
|
||||
|
||||
AZ_Assert(azrtti_typeid<MatrixType>() == outputValueTypeId,
|
||||
"Unable to deserialize Matrix%zux%zu to json because the provided type is %s",
|
||||
RowCount, ColumnCount, outputValueTypeId.ToString<OSString>().c_str());
|
||||
AZ_UNUSED(outputValueTypeId);
|
||||
|
||||
MatrixType* matrix = reinterpret_cast<MatrixType*>(outputValue);
|
||||
AZ_Assert(matrix, "Output value for JsonMatrix%zux%zuSerializer can't be null.", RowCount, ColumnCount);
|
||||
|
||||
switch (inputValue.GetType())
|
||||
{
|
||||
case rapidjson::kArrayType:
|
||||
return LoadArray<MatrixType, RowCount, ColumnCount>(*matrix, inputValue, context);
|
||||
case rapidjson::kObjectType:
|
||||
return LoadObject<MatrixType>(*matrix, inputValue, context);
|
||||
|
||||
case rapidjson::kStringType:
|
||||
[[fallthrough]];
|
||||
case rapidjson::kNumberType:
|
||||
[[fallthrough]];
|
||||
case rapidjson::kNullType:
|
||||
[[fallthrough]];
|
||||
case rapidjson::kFalseType:
|
||||
[[fallthrough]];
|
||||
case rapidjson::kTrueType:
|
||||
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported,
|
||||
"Unsupported type. Math matrix can only be read from arrays or objects.");
|
||||
|
||||
default:
|
||||
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unknown,
|
||||
"Unknown json type encountered in math matrix.");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
AZ::Quaternion CreateQuaternion(const MatrixType& matrix);
|
||||
|
||||
template<>
|
||||
AZ::Quaternion CreateQuaternion<AZ::Matrix3x3>(const AZ::Matrix3x3& matrix)
|
||||
{
|
||||
return Quaternion::CreateFromMatrix3x3(matrix);
|
||||
}
|
||||
|
||||
template<>
|
||||
AZ::Quaternion CreateQuaternion<AZ::Matrix3x4>(const AZ::Matrix3x4& matrix)
|
||||
{
|
||||
return Quaternion::CreateFromMatrix3x4(matrix);
|
||||
}
|
||||
|
||||
template<>
|
||||
AZ::Quaternion CreateQuaternion<AZ::Matrix4x4>(const AZ::Matrix4x4& matrix)
|
||||
{
|
||||
return Quaternion::CreateFromMatrix4x4(matrix);
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
JsonSerializationResult::Result StoreRotationAndScale(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
|
||||
const Uuid& valueTypeId, JsonSerializerContext& context)
|
||||
{
|
||||
namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
|
||||
AZ_UNUSED(valueTypeId);
|
||||
|
||||
const MatrixType* matrix = reinterpret_cast<const MatrixType*>(inputValue);
|
||||
AZ_Assert(matrix, "Input value for JsonMatrixSerializer can't be null.");
|
||||
const MatrixType* defaultMatrix = reinterpret_cast<const MatrixType*>(defaultValue);
|
||||
|
||||
if (!context.ShouldKeepDefaults() && defaultMatrix && *matrix == *defaultMatrix)
|
||||
{
|
||||
return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "Default math Matrix used.");
|
||||
}
|
||||
|
||||
MatrixType matrixToExport = *matrix;
|
||||
AZ::Vector3 scale = matrixToExport.ExtractScale();
|
||||
|
||||
AZ::Quaternion rotation = CreateQuaternion(matrixToExport);
|
||||
auto degrees = rotation.GetEulerDegrees();
|
||||
outputValue.AddMember(rapidjson::StringRef("roll"), degrees.GetX(), context.GetJsonAllocator());
|
||||
outputValue.AddMember(rapidjson::StringRef("pitch"), degrees.GetY(), context.GetJsonAllocator());
|
||||
outputValue.AddMember(rapidjson::StringRef("yaw"), degrees.GetZ(), context.GetJsonAllocator());
|
||||
outputValue.AddMember(rapidjson::StringRef("scale"), scale.GetX(), context.GetJsonAllocator());
|
||||
|
||||
return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::Success, "Math Matrix successfully stored.");
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
JsonSerializationResult::Result StoreTranslation(rapidjson::Value& outputValue, const void* inputValue,
|
||||
const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context)
|
||||
{
|
||||
namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
|
||||
AZ_UNUSED(valueTypeId);
|
||||
|
||||
const MatrixType* matrix = reinterpret_cast<const MatrixType*>(inputValue);
|
||||
AZ_Assert(matrix, "Input value for JsonMatrixSerializer can't be null.");
|
||||
const MatrixType* defaultMatrix = reinterpret_cast<const MatrixType*>(defaultValue);
|
||||
|
||||
if (!context.ShouldKeepDefaults() && defaultMatrix && *matrix == *defaultMatrix)
|
||||
{
|
||||
return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "Default math Matrix used.");
|
||||
}
|
||||
|
||||
auto translation = matrix->GetTranslation();
|
||||
outputValue.AddMember(rapidjson::StringRef("x"), translation.GetX(), context.GetJsonAllocator());
|
||||
outputValue.AddMember(rapidjson::StringRef("y"), translation.GetY(), context.GetJsonAllocator());
|
||||
outputValue.AddMember(rapidjson::StringRef("z"), translation.GetZ(), context.GetJsonAllocator());
|
||||
|
||||
return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::Success, "Math Matrix successfully stored.");
|
||||
}
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
// Matrix3x3
|
||||
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JsonMatrix3x3Serializer, SystemAllocator, 0);
|
||||
|
||||
JsonSerializationResult::Result JsonMatrix3x3Serializer::Load(void* outputValue, const Uuid& outputValueTypeId,
|
||||
const rapidjson::Value& inputValue, JsonDeserializerContext& context)
|
||||
{
|
||||
return JsonMathMatrixSerializerInternal::Load<Matrix3x3, 3, 3>(
|
||||
outputValue,
|
||||
outputValueTypeId,
|
||||
inputValue,
|
||||
context);
|
||||
}
|
||||
|
||||
JsonSerializationResult::Result JsonMatrix3x3Serializer::Store(rapidjson::Value& outputValue, const void* inputValue,
|
||||
const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context)
|
||||
{
|
||||
outputValue.SetObject();
|
||||
|
||||
return JsonMathMatrixSerializerInternal::StoreRotationAndScale<Matrix3x3>(
|
||||
outputValue,
|
||||
inputValue,
|
||||
defaultValue,
|
||||
valueTypeId,
|
||||
context);
|
||||
}
|
||||
|
||||
|
||||
// Matrix3x4
|
||||
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JsonMatrix3x4Serializer, SystemAllocator, 0);
|
||||
|
||||
JsonSerializationResult::Result JsonMatrix3x4Serializer::Load(void* outputValue, const Uuid& outputValueTypeId,
|
||||
const rapidjson::Value& inputValue, JsonDeserializerContext& context)
|
||||
{
|
||||
return JsonMathMatrixSerializerInternal::Load<Matrix3x4, 3, 4>(
|
||||
outputValue,
|
||||
outputValueTypeId,
|
||||
inputValue,
|
||||
context);
|
||||
}
|
||||
|
||||
JsonSerializationResult::Result JsonMatrix3x4Serializer::Store(rapidjson::Value& outputValue, const void* inputValue,
|
||||
const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context)
|
||||
{
|
||||
outputValue.SetObject();
|
||||
|
||||
auto result = JsonMathMatrixSerializerInternal::StoreRotationAndScale<Matrix3x4>(
|
||||
outputValue,
|
||||
inputValue,
|
||||
defaultValue,
|
||||
valueTypeId,
|
||||
context);
|
||||
|
||||
auto resultTranslation = JsonMathMatrixSerializerInternal::StoreTranslation<Matrix3x4>(
|
||||
outputValue,
|
||||
inputValue,
|
||||
defaultValue,
|
||||
valueTypeId,
|
||||
context);
|
||||
|
||||
result.GetResultCode().Combine(resultTranslation);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Matrix4x4
|
||||
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JsonMatrix4x4Serializer, SystemAllocator, 0);
|
||||
|
||||
JsonSerializationResult::Result JsonMatrix4x4Serializer::Load(void* outputValue, const Uuid& outputValueTypeId,
|
||||
const rapidjson::Value& inputValue, JsonDeserializerContext& context)
|
||||
{
|
||||
return JsonMathMatrixSerializerInternal::Load<Matrix4x4, 4, 4>(
|
||||
outputValue,
|
||||
outputValueTypeId,
|
||||
inputValue,
|
||||
context);
|
||||
}
|
||||
|
||||
JsonSerializationResult::Result JsonMatrix4x4Serializer::Store(rapidjson::Value& outputValue, const void* inputValue,
|
||||
const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context)
|
||||
{
|
||||
outputValue.SetObject();
|
||||
|
||||
auto result = JsonMathMatrixSerializerInternal::StoreRotationAndScale<Matrix4x4>(
|
||||
outputValue,
|
||||
inputValue,
|
||||
defaultValue,
|
||||
valueTypeId,
|
||||
context);
|
||||
|
||||
auto resultTranslation = JsonMathMatrixSerializerInternal::StoreTranslation<Matrix4x4>(
|
||||
outputValue,
|
||||
inputValue,
|
||||
defaultValue,
|
||||
valueTypeId,
|
||||
context);
|
||||
|
||||
result.GetResultCode().Combine(resultTranslation);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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/Json/BaseJsonSerializer.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class JsonMatrix3x3Serializer
|
||||
: public BaseJsonSerializer
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(JsonMatrix3x3Serializer, "{8C76CD6A-8576-4604-A746-CF7A7F20F366}", BaseJsonSerializer);
|
||||
AZ_CLASS_ALLOCATOR_DECL;
|
||||
JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
|
||||
JsonDeserializerContext& context) override;
|
||||
JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
|
||||
const Uuid& valueTypeId, JsonSerializerContext& context) override;
|
||||
};
|
||||
|
||||
class JsonMatrix3x4Serializer
|
||||
: public BaseJsonSerializer
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(JsonMatrix3x4Serializer, "{E801333B-4AF1-4F43-976C-579670B02DC5}", BaseJsonSerializer);
|
||||
AZ_CLASS_ALLOCATOR_DECL;
|
||||
JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
|
||||
JsonDeserializerContext& context) override;
|
||||
JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
|
||||
const Uuid& valueTypeId, JsonSerializerContext& context) override;
|
||||
};
|
||||
|
||||
class JsonMatrix4x4Serializer
|
||||
: public BaseJsonSerializer
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(JsonMatrix4x4Serializer, "{46E888FC-248A-4910-9221-4E101A10AEA1}", BaseJsonSerializer);
|
||||
AZ_CLASS_ALLOCATOR_DECL;
|
||||
JsonSerializationResult::Result Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue,
|
||||
JsonDeserializerContext& context) override;
|
||||
JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
|
||||
const Uuid& valueTypeId, JsonSerializerContext& context) override;
|
||||
};
|
||||
}
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <AzCore/Math/Vector2.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/Math/Vector4.h>
|
||||
#include <AzCore/Math/MathMatrixSerializer.h>
|
||||
#include <AzCore/Math/MathVectorSerializer.h>
|
||||
#include <AzCore/Math/Color.h>
|
||||
#include <AzCore/Math/ColorSerializer.h>
|
||||
@@ -366,6 +367,9 @@ namespace AZ
|
||||
{
|
||||
context.Serializer<JsonColorSerializer>()->HandlesType<Color>();
|
||||
context.Serializer<JsonUuidSerializer>()->HandlesType<Uuid>();
|
||||
context.Serializer<JsonMatrix3x3Serializer>()->HandlesType<Matrix3x3>();
|
||||
context.Serializer<JsonMatrix3x4Serializer>()->HandlesType<Matrix3x4>();
|
||||
context.Serializer<JsonMatrix4x4Serializer>()->HandlesType<Matrix4x4>();
|
||||
context.Serializer<JsonVector2Serializer>()->HandlesType<Vector2>();
|
||||
context.Serializer<JsonVector3Serializer>()->HandlesType<Vector3>();
|
||||
context.Serializer<JsonVector4Serializer>()->HandlesType<Vector4>();
|
||||
|
||||
@@ -13,16 +13,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/std/math.h>
|
||||
#include <AzCore/std/typetraits/conditional.h>
|
||||
#include <AzCore/std/typetraits/is_integral.h>
|
||||
#include <AzCore/std/typetraits/is_signed.h>
|
||||
#include <AzCore/std/typetraits/is_unsigned.h>
|
||||
#include <AzCore/std/utils.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <float.h>
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
#include <math.h>
|
||||
#include <utility>
|
||||
#include <AzCore/std/typetraits/conditional.h>
|
||||
#include <AzCore/std/typetraits/is_integral.h>
|
||||
|
||||
// We have a separate inline define for math functions.
|
||||
// The performance of these functions is very sensitive to inlining, and some compilers don't deal well with this.
|
||||
@@ -308,12 +309,12 @@ namespace AZ
|
||||
|
||||
AZ_MATH_INLINE bool IsClose(float a, float b, float tolerance = Constants::Tolerance)
|
||||
{
|
||||
return (fabsf(a - b) <= tolerance);
|
||||
return (AZStd::abs(a - b) <= tolerance);
|
||||
}
|
||||
|
||||
AZ_MATH_INLINE bool IsClose(double a, double b, double tolerance = Constants::Tolerance)
|
||||
{
|
||||
return (fabs(a - b) <= tolerance);
|
||||
return (AZStd::abs(a - b) <= tolerance);
|
||||
}
|
||||
|
||||
//! Returns x >= 0.0f ? 1.0f : -1.0f.
|
||||
@@ -402,12 +403,12 @@ namespace AZ
|
||||
|
||||
AZ_MATH_INLINE float GetAbs(float a)
|
||||
{
|
||||
return fabsf(a);
|
||||
return AZStd::abs(a);
|
||||
}
|
||||
|
||||
AZ_MATH_INLINE double GetAbs(double a)
|
||||
{
|
||||
return std::abs(a);
|
||||
return AZStd::abs(a);
|
||||
}
|
||||
|
||||
AZ_MATH_INLINE float GetMod(float a, float b)
|
||||
@@ -441,7 +442,7 @@ namespace AZ
|
||||
template<typename T>
|
||||
AZ_MATH_INLINE bool IsCloseMag(T x, T y, T epsilonValue = std::numeric_limits<T>::epsilon())
|
||||
{
|
||||
return (std::fabs(x - y) <= epsilonValue * GetMax<T>(GetMax<T>(T(1.0), std::fabs(x)), std::fabs(y)));
|
||||
return (AZStd::abs(x - y) <= epsilonValue * GetMax<T>(GetMax<T>(T(1.0), AZStd::abs(x)), AZStd::abs(y)));
|
||||
}
|
||||
|
||||
//! ClampIfCloseMag(x, y, epsilon) returns y when x and y are within epsilon of each other (taking magnitude into account). Otherwise returns x.
|
||||
|
||||
@@ -142,27 +142,44 @@ namespace AZ
|
||||
void SetBasis(const Vector3& basisX, const Vector3& basisY, const Vector3& basisZ);
|
||||
//! @}
|
||||
|
||||
Matrix3x3 operator*(const Matrix3x3& rhs) const;
|
||||
|
||||
//! Calculates (this->GetTranspose() * rhs).
|
||||
Matrix3x3 TransposedMultiply(const Matrix3x3& rhs) const;
|
||||
|
||||
//! Post-multiplies the matrix by a vector.
|
||||
Vector3 operator*(const Vector3& rhs) const;
|
||||
|
||||
Matrix3x3 operator+(const Matrix3x3& rhs) const;
|
||||
Matrix3x3 operator-(const Matrix3x3& rhs) const;
|
||||
|
||||
Matrix3x3 operator*(float multiplier) const;
|
||||
Matrix3x3 operator/(float divisor) const;
|
||||
|
||||
Matrix3x3 operator-() const;
|
||||
|
||||
Matrix3x3& operator*=(const Matrix3x3& rhs);
|
||||
//! Operator for matrix-matrix addition.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x3 operator+(const Matrix3x3& rhs) const;
|
||||
Matrix3x3& operator+=(const Matrix3x3& rhs);
|
||||
//! @}
|
||||
|
||||
//! Operator for matrix-matrix substraction.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x3 operator-(const Matrix3x3& rhs) const;
|
||||
Matrix3x3& operator-=(const Matrix3x3& rhs);
|
||||
//! @}
|
||||
|
||||
//! Operator for matrix-matrix multiplication.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x3 operator*(const Matrix3x3& rhs) const;
|
||||
Matrix3x3& operator*=(const Matrix3x3& rhs);
|
||||
//! @}
|
||||
|
||||
//! Operator for multiplying all matrix's elements with a scalar
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x3 operator*(float multiplier) const;
|
||||
Matrix3x3& operator*=(float multiplier);
|
||||
//! @}
|
||||
|
||||
//! Operator for dividing all matrix's elements with a scalar
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x3 operator/(float divisor) const;
|
||||
Matrix3x3& operator/=(float divisor);
|
||||
//! @}
|
||||
|
||||
//! Operator for negating all matrix's elements
|
||||
[[nodiscard]] Matrix3x3 operator-() const;
|
||||
|
||||
bool operator==(const Matrix3x3& rhs) const;
|
||||
bool operator!=(const Matrix3x3& rhs) const;
|
||||
@@ -187,7 +204,10 @@ namespace AZ
|
||||
//! @}
|
||||
|
||||
//! Gets the scale part of the transformation, i.e. the length of the scale components.
|
||||
Vector3 RetrieveScale() const;
|
||||
[[nodiscard]] Vector3 RetrieveScale() const;
|
||||
|
||||
//! Gets the squared scale part of the transformation (the squared length of the basis vectors).
|
||||
[[nodiscard]] Vector3 RetrieveScaleSq() const;
|
||||
|
||||
//! Gets the scale part of the transformation as in RetrieveScale, and also removes this scaling from the matrix.
|
||||
Vector3 ExtractScale();
|
||||
@@ -195,6 +215,9 @@ namespace AZ
|
||||
//! Quick multiplication by a scale matrix, equivalent to m*=Matrix3x3::CreateScale(scale).
|
||||
void MultiplyByScale(const Vector3& scale);
|
||||
|
||||
//! Returns a matrix with the reciprocal scale, keeping the same rotation and translation.
|
||||
[[nodiscard]] Matrix3x3 GetReciprocalScaled() const;
|
||||
|
||||
//! Polar decomposition, M=U*H, U is orthogonal (unitary) and H is symmetric (hermitian).
|
||||
//! This function returns the orthogonal part only
|
||||
Matrix3x3 GetPolarDecomposition() const;
|
||||
@@ -241,7 +264,9 @@ namespace AZ
|
||||
//! Note that this is not the usual multiplication order for transformations.
|
||||
Vector3& operator*=(Vector3& lhs, const Matrix3x3& rhs);
|
||||
|
||||
//! Pre-multiplies the matrix by a scalar.
|
||||
Matrix3x3 operator*(float lhs, const Matrix3x3& rhs);
|
||||
}
|
||||
|
||||
} // namespace AZ
|
||||
|
||||
#include <AzCore/Math/Matrix3x3.inl>
|
||||
|
||||
@@ -392,14 +392,6 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator*(const Matrix3x3& rhs) const
|
||||
{
|
||||
Matrix3x3 result;
|
||||
Simd::Vec3::Mat3x3Multiply(GetSimdValues(), rhs.GetSimdValues(), result.GetSimdValues());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::TransposedMultiply(const Matrix3x3& rhs) const
|
||||
{
|
||||
Matrix3x3 result;
|
||||
@@ -416,51 +408,12 @@ namespace AZ
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator+(const Matrix3x3& rhs) const
|
||||
{
|
||||
return Matrix3x3(Simd::Vec3::Add(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue())
|
||||
, Simd::Vec3::Add(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue())
|
||||
, Simd::Vec3::Add(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue()));
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator-(const Matrix3x3& rhs) const
|
||||
{
|
||||
return Matrix3x3(Simd::Vec3::Sub(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue())
|
||||
, Simd::Vec3::Sub(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue())
|
||||
, Simd::Vec3::Sub(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue()));
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator*(float multiplier) const
|
||||
{
|
||||
const Simd::Vec3::FloatType mulVec = Simd::Vec3::Splat(multiplier);
|
||||
return Matrix3x3(Simd::Vec3::Mul(m_rows[0].GetSimdValue(), mulVec)
|
||||
, Simd::Vec3::Mul(m_rows[1].GetSimdValue(), mulVec)
|
||||
, Simd::Vec3::Mul(m_rows[2].GetSimdValue(), mulVec));
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator/(float divisor) const
|
||||
{
|
||||
const Simd::Vec3::FloatType divVec = Simd::Vec3::Splat(divisor);
|
||||
return Matrix3x3(Simd::Vec3::Div(m_rows[0].GetSimdValue(), divVec)
|
||||
, Simd::Vec3::Div(m_rows[1].GetSimdValue(), divVec)
|
||||
, Simd::Vec3::Div(m_rows[2].GetSimdValue(), divVec));
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator-() const
|
||||
{
|
||||
const Simd::Vec3::FloatType zeroVec = Simd::Vec3::ZeroFloat();
|
||||
return Matrix3x3(Simd::Vec3::Sub(zeroVec, m_rows[0].GetSimdValue())
|
||||
, Simd::Vec3::Sub(zeroVec, m_rows[1].GetSimdValue())
|
||||
, Simd::Vec3::Sub(zeroVec, m_rows[2].GetSimdValue()));
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3& Matrix3x3::operator*=(const Matrix3x3& rhs)
|
||||
{
|
||||
*this = *this * rhs;
|
||||
return *this;
|
||||
return Matrix3x3
|
||||
(
|
||||
Simd::Vec3::Add(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue()),
|
||||
Simd::Vec3::Add(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue()),
|
||||
Simd::Vec3::Add(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -471,6 +424,17 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator-(const Matrix3x3& rhs) const
|
||||
{
|
||||
return Matrix3x3
|
||||
(
|
||||
Simd::Vec3::Sub(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue()),
|
||||
Simd::Vec3::Sub(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue()),
|
||||
Simd::Vec3::Sub(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3& Matrix3x3::operator-=(const Matrix3x3& rhs)
|
||||
{
|
||||
*this = *this - rhs;
|
||||
@@ -478,6 +442,33 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator*(const Matrix3x3& rhs) const
|
||||
{
|
||||
Matrix3x3 result;
|
||||
Simd::Vec3::Mat3x3Multiply(GetSimdValues(), rhs.GetSimdValues(), result.GetSimdValues());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3& Matrix3x3::operator*=(const Matrix3x3& rhs)
|
||||
{
|
||||
*this = *this * rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator*(float multiplier) const
|
||||
{
|
||||
const Simd::Vec3::FloatType mulVec = Simd::Vec3::Splat(multiplier);
|
||||
return Matrix3x3
|
||||
(
|
||||
Simd::Vec3::Mul(m_rows[0].GetSimdValue(), mulVec),
|
||||
Simd::Vec3::Mul(m_rows[1].GetSimdValue(), mulVec),
|
||||
Simd::Vec3::Mul(m_rows[2].GetSimdValue(), mulVec)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3& Matrix3x3::operator*=(float multiplier)
|
||||
{
|
||||
*this = *this * multiplier;
|
||||
@@ -485,6 +476,18 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator/(float divisor) const
|
||||
{
|
||||
const Simd::Vec3::FloatType divVec = Simd::Vec3::Splat(divisor);
|
||||
return Matrix3x3
|
||||
(
|
||||
Simd::Vec3::Div(m_rows[0].GetSimdValue(), divVec),
|
||||
Simd::Vec3::Div(m_rows[1].GetSimdValue(), divVec),
|
||||
Simd::Vec3::Div(m_rows[2].GetSimdValue(), divVec)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3& Matrix3x3::operator/=(float divisor)
|
||||
{
|
||||
*this = *this / divisor;
|
||||
@@ -492,6 +495,18 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::operator-() const
|
||||
{
|
||||
const Simd::Vec3::FloatType zeroVec = Simd::Vec3::ZeroFloat();
|
||||
return Matrix3x3
|
||||
(
|
||||
Simd::Vec3::Sub(zeroVec, m_rows[0].GetSimdValue()),
|
||||
Simd::Vec3::Sub(zeroVec, m_rows[1].GetSimdValue()),
|
||||
Simd::Vec3::Sub(zeroVec, m_rows[2].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE bool Matrix3x3::operator==(const Matrix3x3& rhs) const
|
||||
{
|
||||
return (Simd::Vec3::CmpAllEq(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue())
|
||||
@@ -552,6 +567,12 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Vector3 Matrix3x3::RetrieveScaleSq() const
|
||||
{
|
||||
return Vector3(GetBasisX().GetLengthSq(), GetBasisY().GetLengthSq(), GetBasisZ().GetLengthSq());
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Vector3 Matrix3x3::ExtractScale()
|
||||
{
|
||||
const Vector3 x = GetBasisX();
|
||||
@@ -584,6 +605,14 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 Matrix3x3::GetReciprocalScaled() const
|
||||
{
|
||||
Matrix3x3 result = *this;
|
||||
result.MultiplyByScale(RetrieveScaleSq().GetReciprocal());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE void Matrix3x3::GetPolarDecomposition(Matrix3x3* orthogonalOut, Matrix3x3* symmetricOut) const
|
||||
{
|
||||
*orthogonalOut = GetPolarDecomposition();
|
||||
@@ -679,8 +708,6 @@ namespace AZ
|
||||
|
||||
AZ_MATH_INLINE Matrix3x3 operator*(float lhs, const Matrix3x3& rhs)
|
||||
{
|
||||
const Simd::Vec3::FloatType lhsVec = Simd::Vec3::Splat(lhs);
|
||||
const Simd::Vec3::FloatType* rows = rhs.GetSimdValues();
|
||||
return Matrix3x3(Simd::Vec3::Mul(lhsVec, rows[0]), Simd::Vec3::Mul(lhsVec, rows[1]), Simd::Vec3::Mul(lhsVec, rows[2]));
|
||||
return rhs * lhs;
|
||||
}
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
@@ -225,11 +225,38 @@ namespace AZ
|
||||
//! Sets the three basis vectors and the translation.
|
||||
void SetBasisAndTranslation(const Vector3& basisX, const Vector3& basisY, const Vector3& basisZ, const Vector3& translation);
|
||||
|
||||
//! Operator for matrix-matrix multiplication.
|
||||
[[nodiscard]] Matrix3x4 operator*(const Matrix3x4& rhs) const;
|
||||
//! Operator for matrix-matrix addition.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x4 operator+(const Matrix3x4& rhs) const;
|
||||
Matrix3x4& operator+=(const Matrix3x4& rhs);
|
||||
//! @}
|
||||
|
||||
//! Compound assignment operator for matrix-matrix multiplication.
|
||||
//! Operator for matrix-matrix substraction.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x4 operator-(const Matrix3x4& rhs) const;
|
||||
Matrix3x4& operator-=(const Matrix3x4& rhs);
|
||||
//! @}
|
||||
|
||||
//! Operator for matrix-matrix multiplication.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x4 operator*(const Matrix3x4& rhs) const;
|
||||
Matrix3x4& operator*=(const Matrix3x4& rhs);
|
||||
//! @}
|
||||
|
||||
//! Operator for multiplying all matrix's elements with a scalar
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x4 operator*(float multiplier) const;
|
||||
Matrix3x4& operator*=(float multiplier);
|
||||
//! @}
|
||||
|
||||
//! Operator for dividing all matrix's elements with a scalar
|
||||
//! @{
|
||||
[[nodiscard]] Matrix3x4 operator/(float divisor) const;
|
||||
Matrix3x4& operator/=(float divisor);
|
||||
//! @}
|
||||
|
||||
//! Operator for negating all matrix's elements
|
||||
[[nodiscard]] Matrix3x4 operator-() const;
|
||||
|
||||
//! Operator for transforming a Vector3.
|
||||
[[nodiscard]] Vector3 operator*(const Vector3& rhs) const;
|
||||
@@ -274,12 +301,18 @@ namespace AZ
|
||||
//! Gets the scale part of the transformation (the length of the basis vectors).
|
||||
[[nodiscard]] Vector3 RetrieveScale() const;
|
||||
|
||||
//! Gets the squared scale part of the transformation (the squared length of the basis vectors).
|
||||
[[nodiscard]] Vector3 RetrieveScaleSq() const;
|
||||
|
||||
//! Gets the scale part of the transformation as in RetrieveScale, and also removes this scaling from the matrix.
|
||||
Vector3 ExtractScale();
|
||||
|
||||
//! Multiplies the basis vectors of the matrix by the elements of the scale specified.
|
||||
void MultiplyByScale(const Vector3& scale);
|
||||
|
||||
//! Returns a matrix with the reciprocal scale, keeping the same rotation and translation.
|
||||
[[nodiscard]] Matrix3x4 GetReciprocalScaled() const;
|
||||
|
||||
//! Tests if the 3x3 part of the matrix is orthogonal.
|
||||
bool IsOrthogonal(float tolerance = Constants::Tolerance) const;
|
||||
|
||||
@@ -335,6 +368,10 @@ namespace AZ
|
||||
|
||||
Vector4 m_rows[RowCount];
|
||||
};
|
||||
|
||||
//! Pre-multiplies the matrix by a scalar.
|
||||
Matrix3x4 operator*(float lhs, const Matrix3x4& rhs);
|
||||
|
||||
} // namespace AZ
|
||||
|
||||
#include <AzCore/Math/Matrix3x4.inl>
|
||||
|
||||
@@ -472,6 +472,42 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4 Matrix3x4::operator+(const Matrix3x4& rhs) const
|
||||
{
|
||||
return Matrix3x4
|
||||
(
|
||||
Simd::Vec4::Add(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue()),
|
||||
Simd::Vec4::Add(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue()),
|
||||
Simd::Vec4::Add(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4& Matrix3x4::operator+=(const Matrix3x4& rhs)
|
||||
{
|
||||
*this = *this + rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4 Matrix3x4::operator-(const Matrix3x4& rhs) const
|
||||
{
|
||||
return Matrix3x4
|
||||
(
|
||||
Simd::Vec4::Sub(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue()),
|
||||
Simd::Vec4::Sub(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue()),
|
||||
Simd::Vec4::Sub(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4& Matrix3x4::operator-=(const Matrix3x4& rhs)
|
||||
{
|
||||
*this = *this - rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4 Matrix3x4::operator*(const Matrix3x4& rhs) const
|
||||
{
|
||||
Matrix3x4 result;
|
||||
@@ -487,6 +523,56 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4 Matrix3x4::operator*(float multiplier) const
|
||||
{
|
||||
const Simd::Vec4::FloatType mulVec = Simd::Vec4::Splat(multiplier);
|
||||
return Matrix3x4
|
||||
(
|
||||
Simd::Vec4::Mul(m_rows[0].GetSimdValue(), mulVec),
|
||||
Simd::Vec4::Mul(m_rows[1].GetSimdValue(), mulVec),
|
||||
Simd::Vec4::Mul(m_rows[2].GetSimdValue(), mulVec)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4& Matrix3x4::operator*=(float multiplier)
|
||||
{
|
||||
*this = *this * multiplier;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4 Matrix3x4::operator/(float divisor) const
|
||||
{
|
||||
const Simd::Vec4::FloatType divVec = Simd::Vec4::Splat(divisor);
|
||||
return Matrix3x4
|
||||
(
|
||||
Simd::Vec4::Div(m_rows[0].GetSimdValue(), divVec),
|
||||
Simd::Vec4::Div(m_rows[1].GetSimdValue(), divVec),
|
||||
Simd::Vec4::Div(m_rows[2].GetSimdValue(), divVec)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4& Matrix3x4::operator/=(float divisor)
|
||||
{
|
||||
*this = *this / divisor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4 Matrix3x4::operator-() const
|
||||
{
|
||||
const Simd::Vec4::FloatType zeroVec = Simd::Vec4::ZeroFloat();
|
||||
return Matrix3x4
|
||||
(
|
||||
Simd::Vec4::Sub(zeroVec, m_rows[0].GetSimdValue()),
|
||||
Simd::Vec4::Sub(zeroVec, m_rows[1].GetSimdValue()),
|
||||
Simd::Vec4::Sub(zeroVec, m_rows[2].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Vector3 Matrix3x4::operator*(const Vector3& rhs) const
|
||||
{
|
||||
return Vector3
|
||||
@@ -583,6 +669,12 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Vector3 Matrix3x4::RetrieveScaleSq() const
|
||||
{
|
||||
return Vector3(GetColumn(0).GetLengthSq(), GetColumn(1).GetLengthSq(), GetColumn(2).GetLengthSq());
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Vector3 Matrix3x4::ExtractScale()
|
||||
{
|
||||
const Vector3 scale = RetrieveScale();
|
||||
@@ -600,6 +692,14 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4 Matrix3x4::GetReciprocalScaled() const
|
||||
{
|
||||
Matrix3x4 result = *this;
|
||||
result.MultiplyByScale(RetrieveScaleSq().GetReciprocal());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE void Matrix3x4::Orthogonalize()
|
||||
{
|
||||
*this = GetOrthogonalized();
|
||||
@@ -660,4 +760,10 @@ namespace AZ
|
||||
{
|
||||
return reinterpret_cast<Simd::Vec4::FloatType*>(m_rows);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix3x4 operator*(float lhs, const Matrix3x4& rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
@@ -171,14 +171,38 @@ namespace AZ
|
||||
void SetTranslation(const Vector3& v);
|
||||
//! @}
|
||||
|
||||
Matrix4x4 operator+(const Matrix4x4& rhs) const;
|
||||
//! Operator for matrix-matrix addition.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix4x4 operator+(const Matrix4x4& rhs) const;
|
||||
Matrix4x4& operator+=(const Matrix4x4& rhs);
|
||||
//! @}
|
||||
|
||||
Matrix4x4 operator-(const Matrix4x4& rhs) const;
|
||||
//! Operator for matrix-matrix substraction.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix4x4 operator-(const Matrix4x4& rhs) const;
|
||||
Matrix4x4& operator-=(const Matrix4x4& rhs);
|
||||
//! @}
|
||||
|
||||
Matrix4x4 operator*(const Matrix4x4& rhs) const;
|
||||
//! Operator for matrix-matrix multiplication.
|
||||
//! @{
|
||||
[[nodiscard]] Matrix4x4 operator*(const Matrix4x4& rhs) const;
|
||||
Matrix4x4& operator*=(const Matrix4x4& rhs);
|
||||
//! @}
|
||||
|
||||
//! Operator for multiplying all matrix's elements with a scalar
|
||||
//! @{
|
||||
[[nodiscard]] Matrix4x4 operator*(float multiplier) const;
|
||||
Matrix4x4& operator*=(float multiplier);
|
||||
//! @}
|
||||
|
||||
//! Operator for dividing all matrix's elements with a scalar
|
||||
//! @{
|
||||
[[nodiscard]] Matrix4x4 operator/(float divisor) const;
|
||||
Matrix4x4& operator/=(float divisor);
|
||||
//! @}
|
||||
|
||||
//! Operator for negating all matrix's elements
|
||||
[[nodiscard]] Matrix4x4 operator-() const;
|
||||
|
||||
//! Post-multiplies the matrix by a vector.
|
||||
//! Assumes that the w-component of the Vector3 is 1.0.
|
||||
@@ -222,7 +246,10 @@ namespace AZ
|
||||
//! @}
|
||||
|
||||
//! Gets the scale part of the transformation, i.e. the length of the scale components.
|
||||
Vector3 RetrieveScale() const;
|
||||
[[nodiscard]] Vector3 RetrieveScale() const;
|
||||
|
||||
//! Gets the squared scale part of the transformation (the squared length of the basis vectors).
|
||||
[[nodiscard]] Vector3 RetrieveScaleSq() const;
|
||||
|
||||
//! Gets the scale part of the transformation as in RetrieveScale, and also removes this scaling from the matrix.
|
||||
Vector3 ExtractScale();
|
||||
@@ -230,6 +257,9 @@ namespace AZ
|
||||
//! Quick multiplication by a scale matrix, equivalent to m*=Matrix4x4::CreateScale(scale).
|
||||
void MultiplyByScale(const Vector3& scale);
|
||||
|
||||
//! Returns a matrix with the reciprocal scale, keeping the same rotation and translation.
|
||||
[[nodiscard]] Matrix4x4 GetReciprocalScaled() const;
|
||||
|
||||
bool IsClose(const Matrix4x4& rhs, float tolerance = Constants::Tolerance) const;
|
||||
|
||||
bool operator==(const Matrix4x4& rhs) const;
|
||||
@@ -270,6 +300,10 @@ namespace AZ
|
||||
//! Pre-multiplies the matrix by a vector in-place.
|
||||
//! Note that this is not the usual multiplication order for transformations.
|
||||
Vector4& operator*=(Vector4& lhs, const Matrix4x4& rhs);
|
||||
}
|
||||
|
||||
//! Pre-multiplies the matrix by a scalar.
|
||||
Matrix4x4 operator*(float lhs, const Matrix4x4& rhs);
|
||||
|
||||
} // namespace AZ
|
||||
|
||||
#include <AzCore/Math/Matrix4x4.inl>
|
||||
|
||||
@@ -480,20 +480,12 @@ namespace AZ
|
||||
AZ_MATH_INLINE Matrix4x4 Matrix4x4::operator+(const Matrix4x4& rhs) const
|
||||
{
|
||||
return Matrix4x4
|
||||
( Simd::Vec4::Add(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue())
|
||||
, Simd::Vec4::Add(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue())
|
||||
, Simd::Vec4::Add(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue())
|
||||
, Simd::Vec4::Add(m_rows[3].GetSimdValue(), rhs.m_rows[3].GetSimdValue()));
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4 Matrix4x4::operator-(const Matrix4x4& rhs) const
|
||||
{
|
||||
return Matrix4x4
|
||||
( Simd::Vec4::Sub(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue())
|
||||
, Simd::Vec4::Sub(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue())
|
||||
, Simd::Vec4::Sub(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue())
|
||||
, Simd::Vec4::Sub(m_rows[3].GetSimdValue(), rhs.m_rows[3].GetSimdValue()));
|
||||
(
|
||||
Simd::Vec4::Add(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue()),
|
||||
Simd::Vec4::Add(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue()),
|
||||
Simd::Vec4::Add(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue()),
|
||||
Simd::Vec4::Add(m_rows[3].GetSimdValue(), rhs.m_rows[3].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4& Matrix4x4::operator+=(const Matrix4x4& rhs)
|
||||
@@ -502,6 +494,18 @@ namespace AZ
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4 Matrix4x4::operator-(const Matrix4x4& rhs) const
|
||||
{
|
||||
return Matrix4x4
|
||||
(
|
||||
Simd::Vec4::Sub(m_rows[0].GetSimdValue(), rhs.m_rows[0].GetSimdValue()),
|
||||
Simd::Vec4::Sub(m_rows[1].GetSimdValue(), rhs.m_rows[1].GetSimdValue()),
|
||||
Simd::Vec4::Sub(m_rows[2].GetSimdValue(), rhs.m_rows[2].GetSimdValue()),
|
||||
Simd::Vec4::Sub(m_rows[3].GetSimdValue(), rhs.m_rows[3].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4& Matrix4x4::operator-=(const Matrix4x4& rhs)
|
||||
{
|
||||
*this = *this - rhs;
|
||||
@@ -523,6 +527,59 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4 Matrix4x4::operator*(float multiplier) const
|
||||
{
|
||||
const Simd::Vec4::FloatType mulVec = Simd::Vec4::Splat(multiplier);
|
||||
return Matrix4x4
|
||||
(
|
||||
Simd::Vec4::Mul(m_rows[0].GetSimdValue(), mulVec),
|
||||
Simd::Vec4::Mul(m_rows[1].GetSimdValue(), mulVec),
|
||||
Simd::Vec4::Mul(m_rows[2].GetSimdValue(), mulVec),
|
||||
Simd::Vec4::Mul(m_rows[3].GetSimdValue(), mulVec)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4& Matrix4x4::operator*=(float multiplier)
|
||||
{
|
||||
*this = *this * multiplier;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4 Matrix4x4::operator/(float divisor) const
|
||||
{
|
||||
const Simd::Vec4::FloatType divVec = Simd::Vec4::Splat(divisor);
|
||||
return Matrix4x4
|
||||
(
|
||||
Simd::Vec4::Div(m_rows[0].GetSimdValue(), divVec),
|
||||
Simd::Vec4::Div(m_rows[1].GetSimdValue(), divVec),
|
||||
Simd::Vec4::Div(m_rows[2].GetSimdValue(), divVec),
|
||||
Simd::Vec4::Div(m_rows[3].GetSimdValue(), divVec)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4& Matrix4x4::operator/=(float divisor)
|
||||
{
|
||||
*this = *this / divisor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4 Matrix4x4::operator-() const
|
||||
{
|
||||
const Simd::Vec4::FloatType zeroVec = Simd::Vec4::ZeroFloat();
|
||||
return Matrix4x4
|
||||
(
|
||||
Simd::Vec4::Sub(zeroVec, m_rows[0].GetSimdValue()),
|
||||
Simd::Vec4::Sub(zeroVec, m_rows[1].GetSimdValue()),
|
||||
Simd::Vec4::Sub(zeroVec, m_rows[2].GetSimdValue()),
|
||||
Simd::Vec4::Sub(zeroVec, m_rows[3].GetSimdValue())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Vector3 Matrix4x4::operator*(const Vector3& rhs) const
|
||||
{
|
||||
return Vector3(Simd::Vec4::Mat4x4TransformPoint3(GetSimdValues(), rhs.GetSimdValue()));
|
||||
@@ -595,6 +652,12 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Vector3 Matrix4x4::RetrieveScaleSq() const
|
||||
{
|
||||
return Vector3(GetBasisX().GetLengthSq(), GetBasisY().GetLengthSq(), GetBasisZ().GetLengthSq());
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Vector3 Matrix4x4::ExtractScale()
|
||||
{
|
||||
Vector4 x = GetBasisX();
|
||||
@@ -619,6 +682,14 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4 Matrix4x4::GetReciprocalScaled() const
|
||||
{
|
||||
Matrix4x4 result = *this;
|
||||
result.MultiplyByScale(RetrieveScaleSq().GetReciprocal());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE bool Matrix4x4::IsClose(const Matrix4x4& rhs, float tolerance) const
|
||||
{
|
||||
const Simd::Vec4::FloatType vecTolerance = Simd::Vec4::Splat(tolerance);
|
||||
@@ -702,4 +773,10 @@ namespace AZ
|
||||
lhs = lhs * rhs;
|
||||
return lhs;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Matrix4x4 operator*(float lhs, const Matrix4x4& rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
@@ -816,7 +816,7 @@ namespace AZ
|
||||
template<size_t Index>
|
||||
static void ReflectUnpackMethodFold(BehaviorContext::ClassBuilder<ContainerType>& builder)
|
||||
{
|
||||
AZStd::string methodName = AZStd::string::format("Get%ld", Index);
|
||||
const AZStd::string methodName = AZStd::string::format("Get%zu", Index);
|
||||
builder->Method(methodName.data(), [](ContainerType& value) { return AZStd::get<Index>(value); })
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(AZ::ScriptCanvasAttributes::TupleGetFunctionIndex, Index)
|
||||
|
||||
@@ -53,6 +53,10 @@ namespace AZ
|
||||
//! RemoveableByUser : A bool which determines if the component can be removed by the user.
|
||||
//! Setting this to false prevents the user from removing this component. Default behavior is removeable by user.
|
||||
const static AZ::Crc32 RemoveableByUser = AZ_CRC("RemoveableByUser", 0x32c7fd50);
|
||||
//! An int which, if specified, causes a component to be forced to a particular position in the sorted list of
|
||||
//! components on an entity, and prevents dragging or moving operations which would affect that position.
|
||||
const static AZ::Crc32 FixedComponentListIndex = AZ_CRC_CE("FixedComponentListIndex");
|
||||
|
||||
const static AZ::Crc32 AppearsInAddComponentMenu = AZ_CRC("AppearsInAddComponentMenu", 0x53790e31);
|
||||
const static AZ::Crc32 ForceAutoExpand = AZ_CRC("ForceAutoExpand", 0x1a5c79d2); // Ignores expansion state set by user, enforces expansion.
|
||||
const static AZ::Crc32 AutoExpand = AZ_CRC("AutoExpand", 0x306ff5c0); // Expands automatically unless user changes expansion state.
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace AZ
|
||||
"Unable to retrieve the correct container information for AZStd::array instance.");
|
||||
}
|
||||
|
||||
Flags flags = Flags::None;
|
||||
ContinuationFlags flags = ContinuationFlags::None;
|
||||
Uuid elementTypeId = Uuid::CreateNull();
|
||||
auto typeEnumCallback = [&elementTypeId, &flags](const Uuid&, const SerializeContext::ClassElement* genericClassElement)
|
||||
{
|
||||
@@ -82,7 +82,7 @@ namespace AZ
|
||||
elementTypeId = genericClassElement->m_typeId;
|
||||
if (genericClassElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER)
|
||||
{
|
||||
flags = Flags::ResolvePointer;
|
||||
flags = ContinuationFlags::ResolvePointer;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
@@ -161,7 +161,7 @@ namespace AZ
|
||||
"Not enough entries in JSON array to load an AZStd::array from.");
|
||||
}
|
||||
|
||||
Flags flags = Flags::None;
|
||||
ContinuationFlags flags = ContinuationFlags::None;
|
||||
Uuid elementTypeId = Uuid::CreateNull();
|
||||
auto typeEnumCallback = [&elementTypeId, &flags](const Uuid&, const SerializeContext::ClassElement* genericClassElement)
|
||||
{
|
||||
@@ -169,7 +169,7 @@ namespace AZ
|
||||
elementTypeId = genericClassElement->m_typeId;
|
||||
if (genericClassElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER)
|
||||
{
|
||||
flags = Flags::ResolvePointer;
|
||||
flags = ContinuationFlags::ResolvePointer;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -208,22 +208,28 @@ namespace AZ
|
||||
// BaseJsonSerializer
|
||||
//
|
||||
|
||||
JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueLoading(void* object, const Uuid& typeId, const rapidjson::Value& value,
|
||||
JsonDeserializerContext& context, Flags flags)
|
||||
BaseJsonSerializer::OperationFlags BaseJsonSerializer::GetOperationsFlags() const
|
||||
{
|
||||
return flags & Flags::ResolvePointer ?
|
||||
JsonDeserializer::LoadToPointer(object, typeId, value, context) :
|
||||
JsonDeserializer::Load(object, typeId, value, context);
|
||||
return OperationFlags::None;
|
||||
}
|
||||
|
||||
JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueStoring(rapidjson::Value& output, const void* object,
|
||||
const void* defaultObject, const Uuid& typeId, JsonSerializerContext& context, Flags flags)
|
||||
JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueLoading(
|
||||
void* object, const Uuid& typeId, const rapidjson::Value& value, JsonDeserializerContext& context, ContinuationFlags flags)
|
||||
{
|
||||
return (flags & ContinuationFlags::ResolvePointer) == ContinuationFlags::ResolvePointer
|
||||
? JsonDeserializer::LoadToPointer(object, typeId, value, context)
|
||||
: JsonDeserializer::Load(object, typeId, value, context);
|
||||
}
|
||||
|
||||
JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueStoring(
|
||||
rapidjson::Value& output, const void* object, const void* defaultObject, const Uuid& typeId, JsonSerializerContext& context,
|
||||
ContinuationFlags flags)
|
||||
{
|
||||
using namespace JsonSerializationResult;
|
||||
|
||||
if (flags & Flags::ReplaceDefault && !context.ShouldKeepDefaults())
|
||||
if ((flags & ContinuationFlags::ReplaceDefault) == ContinuationFlags::ReplaceDefault && !context.ShouldKeepDefaults())
|
||||
{
|
||||
if (flags & Flags::ResolvePointer)
|
||||
if ((flags & ContinuationFlags::ResolvePointer) == ContinuationFlags::ResolvePointer)
|
||||
{
|
||||
return JsonSerializer::StoreFromPointer(output, object, nullptr, typeId, context);
|
||||
}
|
||||
@@ -248,7 +254,7 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
return flags & Flags::ResolvePointer ?
|
||||
return (flags & ContinuationFlags::ResolvePointer) == ContinuationFlags::ResolvePointer ?
|
||||
JsonSerializer::StoreFromPointer(output, object, defaultObject, typeId, context) :
|
||||
JsonSerializer::Store(output, object, defaultObject, typeId, context);
|
||||
}
|
||||
@@ -265,8 +271,9 @@ namespace AZ
|
||||
return JsonSerializer::StoreTypeName(output, typeId, context);
|
||||
}
|
||||
|
||||
JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueLoadingFromJsonObjectField(void* object, const Uuid& typeId, const rapidjson::Value& value,
|
||||
rapidjson::Value::StringRefType memberName, JsonDeserializerContext& context, Flags flags)
|
||||
JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueLoadingFromJsonObjectField(
|
||||
void* object, const Uuid& typeId, const rapidjson::Value& value, rapidjson::Value::StringRefType memberName,
|
||||
JsonDeserializerContext& context, ContinuationFlags flags)
|
||||
{
|
||||
using namespace JsonSerializationResult;
|
||||
|
||||
@@ -291,7 +298,7 @@ namespace AZ
|
||||
|
||||
JsonSerializationResult::ResultCode BaseJsonSerializer::ContinueStoringToJsonObjectField(rapidjson::Value& output,
|
||||
rapidjson::Value::StringRefType newMemberName, const void* object, const void* defaultObject,
|
||||
const Uuid& typeId, JsonSerializerContext& context, Flags flags)
|
||||
const Uuid& typeId, JsonSerializerContext& context, ContinuationFlags flags)
|
||||
{
|
||||
using namespace JsonSerializationResult;
|
||||
|
||||
|
||||
@@ -161,13 +161,19 @@ namespace AZ
|
||||
public:
|
||||
AZ_RTTI(BaseJsonSerializer, "{7291FFDC-D339-40B5-BB26-EA067A327B21}");
|
||||
|
||||
enum Flags
|
||||
enum class ContinuationFlags
|
||||
{
|
||||
None = 0, //! No extra flags.
|
||||
None = 0, //! No extra flags.
|
||||
ResolvePointer = 1 << 0, //! The pointer passed in contains a pointer. The (de)serializer will attempt to resolve to an instance.
|
||||
ReplaceDefault = 1 << 1 //! The default value provided for storing will be replaced with a newly created one.
|
||||
};
|
||||
|
||||
enum class OperationFlags
|
||||
{
|
||||
None = 0, //! No flags that control how the custom json serializer is used.
|
||||
ManualDefault = 1 << 0 //! Even if an (explicit) default is found the custom json serializer will still be called.
|
||||
};
|
||||
|
||||
virtual ~BaseJsonSerializer() = default;
|
||||
|
||||
//! Transforms the data from the rapidjson Value to outputValue, if the conversion is possible and supported.
|
||||
@@ -180,6 +186,9 @@ namespace AZ
|
||||
virtual JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
|
||||
const Uuid& valueTypeId, JsonSerializerContext& context) = 0;
|
||||
|
||||
//! Returns the operation flags which tells the Json Serialization how this custom json serializer can be used.
|
||||
virtual OperationFlags GetOperationsFlags() const;
|
||||
|
||||
protected:
|
||||
//! Continues loading of a (sub)value. Use this function to load member variables for instance. This is more optimal than
|
||||
//! directly calling the json serialization.
|
||||
@@ -187,8 +196,9 @@ namespace AZ
|
||||
//! @param typeId Type id of the object passed in.
|
||||
//! @param value The value in the JSON document where the deserializer will start reading data from.
|
||||
//! @param context The context used during deserialization. Use the value passed in from Load.
|
||||
JsonSerializationResult::ResultCode ContinueLoading(void* object, const Uuid& typeId, const rapidjson::Value& value,
|
||||
JsonDeserializerContext& context, Flags flags = Flags::None);
|
||||
JsonSerializationResult::ResultCode ContinueLoading(
|
||||
void* object, const Uuid& typeId, const rapidjson::Value& value, JsonDeserializerContext& context,
|
||||
ContinuationFlags flags = ContinuationFlags::None);
|
||||
|
||||
//! Continues storing of a (sub)value. Use this function to store member variables for instance. This is more optimal than
|
||||
//! directly calling the json serialization.
|
||||
@@ -200,8 +210,9 @@ namespace AZ
|
||||
//! the settings.
|
||||
//! @param typeId The type id of the object and default object.
|
||||
//! @param context The context used during serialization. Use the value passed in from Store.
|
||||
JsonSerializationResult::ResultCode ContinueStoring(rapidjson::Value& output, const void* object, const void* defaultObject,
|
||||
const Uuid& typeId, JsonSerializerContext& context, Flags flags = Flags::None);
|
||||
JsonSerializationResult::ResultCode ContinueStoring(
|
||||
rapidjson::Value& output, const void* object, const void* defaultObject, const Uuid& typeId, JsonSerializerContext& context,
|
||||
ContinuationFlags flags = ContinuationFlags::None);
|
||||
|
||||
//! Retrieves the type id from a json object or json string.
|
||||
//! @param typeId The retrieved type id.
|
||||
@@ -222,12 +233,14 @@ namespace AZ
|
||||
const Uuid& typeId, JsonSerializerContext& context);
|
||||
|
||||
//! Helper function similar to ContinueLoading, but loads the data as a member of 'value' rather than 'value' itself, if it exists.
|
||||
JsonSerializationResult::ResultCode ContinueLoadingFromJsonObjectField(void* object, const Uuid& typeId, const rapidjson::Value& value,
|
||||
rapidjson::Value::StringRefType memberName, JsonDeserializerContext& context, Flags flags = Flags::None);
|
||||
JsonSerializationResult::ResultCode ContinueLoadingFromJsonObjectField(
|
||||
void* object, const Uuid& typeId, const rapidjson::Value& value, rapidjson::Value::StringRefType memberName,
|
||||
JsonDeserializerContext& context, ContinuationFlags flags = ContinuationFlags::None);
|
||||
|
||||
//! Helper function similar to ContinueStoring, but stores the data as a member of 'output' rather than overwriting 'output'.
|
||||
JsonSerializationResult::ResultCode ContinueStoringToJsonObjectField(rapidjson::Value& output, rapidjson::Value::StringRefType newMemberName,
|
||||
const void* object, const void* defaultObject, const Uuid& typeId, JsonSerializerContext& context, Flags flags = Flags::None);
|
||||
JsonSerializationResult::ResultCode ContinueStoringToJsonObjectField(
|
||||
rapidjson::Value& output, rapidjson::Value::StringRefType newMemberName, const void* object, const void* defaultObject,
|
||||
const Uuid& typeId, JsonSerializerContext& context, ContinuationFlags flags = ContinuationFlags::None);
|
||||
|
||||
//! Checks if a value is an explicit default. This useful for containers where not storing anything as a default would mean
|
||||
//! a slot wouldn't be used so something has to be added to represent the fully default target.
|
||||
@@ -238,6 +251,7 @@ namespace AZ
|
||||
rapidjson::Value GetExplicitDefault();
|
||||
};
|
||||
|
||||
AZ_DEFINE_ENUM_BITWISE_OPERATORS(AZ::BaseJsonSerializer::Flags)
|
||||
AZ_DEFINE_ENUM_BITWISE_OPERATORS(AZ::BaseJsonSerializer::ContinuationFlags)
|
||||
AZ_DEFINE_ENUM_BITWISE_OPERATORS(AZ::BaseJsonSerializer::OperationFlags)
|
||||
|
||||
} // namespace AZ
|
||||
|
||||
@@ -75,9 +75,10 @@ namespace AZ
|
||||
auto elementCallback = [this, &array, &retVal, &index, &context]
|
||||
(void* elementPtr, const Uuid& elementId, const SerializeContext::ClassData*, const SerializeContext::ClassElement* classElement)
|
||||
{
|
||||
Flags flags = classElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER ?
|
||||
Flags::ResolvePointer : Flags::None;
|
||||
flags |= Flags::ReplaceDefault;
|
||||
ContinuationFlags flags = classElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER
|
||||
? ContinuationFlags::ResolvePointer
|
||||
: ContinuationFlags::None;
|
||||
flags |= ContinuationFlags::ReplaceDefault;
|
||||
|
||||
ScopedContextPath subPath(context, index);
|
||||
index++;
|
||||
@@ -161,8 +162,9 @@ namespace AZ
|
||||
container->EnumTypes(typeEnumCallback);
|
||||
AZ_Assert(classElement, "No class element found for the type in the basic container.");
|
||||
|
||||
Flags flags = classElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER ?
|
||||
Flags::ResolvePointer : Flags::None;
|
||||
ContinuationFlags flags = classElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER
|
||||
? ContinuationFlags::ResolvePointer
|
||||
: ContinuationFlags::None;
|
||||
|
||||
const size_t capacity = container->IsFixedCapacity() ? container->Capacity(outputValue) : std::numeric_limits<size_t>::max();
|
||||
|
||||
|
||||
@@ -22,6 +22,19 @@
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
JsonSerializationResult::ResultCode JsonDeserializer::DeserializerDefaultCheck(BaseJsonSerializer* serializer, void* object,
|
||||
const Uuid& typeId, const rapidjson::Value& value, JsonDeserializerContext& context)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
bool isExplicitDefault = IsExplicitDefault(value);
|
||||
bool manuallyDefaults = (serializer->GetOperationsFlags() & BaseJsonSerializer::OperationFlags::ManualDefault) ==
|
||||
BaseJsonSerializer::OperationFlags::ManualDefault;
|
||||
return !isExplicitDefault || (isExplicitDefault && manuallyDefaults)
|
||||
? serializer->Load(object, typeId, value, context)
|
||||
: context.Report(Tasks::ReadField, Outcomes::DefaultsUsed, "Value has an explicit default.");
|
||||
}
|
||||
|
||||
JsonSerializationResult::ResultCode JsonDeserializer::Load(void* object, const Uuid& typeId, const rapidjson::Value& value,
|
||||
JsonDeserializerContext& context)
|
||||
{
|
||||
@@ -33,17 +46,12 @@ namespace AZ
|
||||
"Target object for Json Serialization is pointing to nothing during loading.");
|
||||
}
|
||||
|
||||
if (IsExplicitDefault(value))
|
||||
{
|
||||
return context.Report(Tasks::ReadField, Outcomes::DefaultsUsed, "Value has an explicit default.");
|
||||
}
|
||||
|
||||
BaseJsonSerializer* serializer = context.GetRegistrationContext()->GetSerializerForType(typeId);
|
||||
if (serializer)
|
||||
{
|
||||
return serializer->Load(object, typeId, value, context);
|
||||
return DeserializerDefaultCheck(serializer, object, typeId, value, context);
|
||||
}
|
||||
|
||||
|
||||
const SerializeContext::ClassData* classData = context.GetSerializeContext()->FindClassData(typeId);
|
||||
if (!classData)
|
||||
{
|
||||
@@ -56,9 +64,14 @@ namespace AZ
|
||||
serializer = context.GetRegistrationContext()->GetSerializerForType(classData->m_azRtti->GetGenericTypeId());
|
||||
if (serializer)
|
||||
{
|
||||
return serializer->Load(object, typeId, value, context);
|
||||
return DeserializerDefaultCheck(serializer, object, typeId, value, context);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsExplicitDefault(value))
|
||||
{
|
||||
return context.Report(Tasks::ReadField, Outcomes::DefaultsUsed, "Value has an explicit default.");
|
||||
}
|
||||
|
||||
if (classData->m_azRtti && (classData->m_azRtti->GetTypeTraits() & AZ::TypeTraits::is_enum) == AZ::TypeTraits::is_enum)
|
||||
{
|
||||
@@ -97,7 +110,8 @@ namespace AZ
|
||||
return context.Report(Tasks::RetrieveInfo, Outcomes::Unknown,
|
||||
AZStd::string::format("Failed to retrieve rtti information for %s.", classData->m_name));
|
||||
}
|
||||
AZ_Assert(classData->m_azRtti->GetTypeId() == typeId, "Type id mismatch during deserialization of a json file. (%s vs %s)");
|
||||
AZ_Assert(classData->m_azRtti->GetTypeId() == typeId, "Type id mismatch during deserialization of a json file. (%s vs %s)",
|
||||
classData->m_azRtti->GetTypeId().ToString<AZStd::string>().c_str(), typeId.ToString<AZStd::string>().c_str());
|
||||
|
||||
void** objectPtr = reinterpret_cast<void**>(object);
|
||||
bool isNull = *objectPtr == nullptr;
|
||||
@@ -512,27 +526,24 @@ namespace AZ
|
||||
if (*object)
|
||||
{
|
||||
const AZ::Uuid& actualClassId = rtti.GetActualUuid(*object);
|
||||
if (actualClassId != objectType)
|
||||
const SerializeContext::ClassData* actualClassData = context.GetSerializeContext()->FindClassData(actualClassId);
|
||||
if (!actualClassData)
|
||||
{
|
||||
const SerializeContext::ClassData* actualClassData = context.GetSerializeContext()->FindClassData(actualClassId);
|
||||
if (!actualClassData)
|
||||
{
|
||||
status = context.Report(Tasks::RetrieveInfo, Outcomes::Unknown,
|
||||
AZStd::string::format("Unable to find serialization information for type %s.", actualClassId.ToString<AZStd::string>().c_str()));
|
||||
return ResolvePointerResult::FullyProcessed;
|
||||
}
|
||||
status = context.Report(Tasks::RetrieveInfo, Outcomes::Unknown,
|
||||
AZStd::string::format("Unable to find serialization information for type %s.", actualClassId.ToString<AZStd::string>().c_str()));
|
||||
return ResolvePointerResult::FullyProcessed;
|
||||
}
|
||||
|
||||
if (actualClassData->m_factory)
|
||||
{
|
||||
actualClassData->m_factory->Destroy(*object);
|
||||
*object = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = context.Report(Tasks::RetrieveInfo, Outcomes::Catastrophic,
|
||||
"Unable to find the factory needed to clear out the default value.");
|
||||
return ResolvePointerResult::FullyProcessed;
|
||||
}
|
||||
if (actualClassData->m_factory)
|
||||
{
|
||||
actualClassData->m_factory->Destroy(*object);
|
||||
*object = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = context.Report(Tasks::RetrieveInfo, Outcomes::Catastrophic,
|
||||
"Unable to find the factory needed to clear out the default value.");
|
||||
return ResolvePointerResult::FullyProcessed;
|
||||
}
|
||||
}
|
||||
status = ResultCode(Tasks::ReadField, Outcomes::Success);
|
||||
|
||||
@@ -113,5 +113,13 @@ namespace AZ
|
||||
|
||||
//! Checks if a value is an explicit default. This means the value is an object with no members.
|
||||
static bool IsExplicitDefault(const rapidjson::Value& value);
|
||||
|
||||
private:
|
||||
static JsonSerializationResult::ResultCode DeserializerDefaultCheck(
|
||||
BaseJsonSerializer* serializer,
|
||||
void* object,
|
||||
const Uuid& typeId,
|
||||
const rapidjson::Value& value,
|
||||
JsonDeserializerContext& context);
|
||||
};
|
||||
} // namespace AZ
|
||||
|
||||
@@ -38,6 +38,20 @@ namespace AZ
|
||||
};
|
||||
|
||||
//! Core class to handle serialization to and from json documents.
|
||||
//! The Json Serialization works by taking a default constructed object and then apply the information found in the JSON document
|
||||
//! on top of that object. This allows the Json Serialization to avoid storing default values and helps guarantee that the final
|
||||
//! object is in a valid state even if non-fatal issues are encountered.
|
||||
//! Note on containers: Containers such as vector or map are always considered to be empty even if there's entries in the provided
|
||||
//! default object. During deserialization entries will be appended to any existing values. A flag is provided to automatically
|
||||
//! clear containers during deserialization.
|
||||
//! Note on maps: If the key for map containers such as unordered_map can be interpret as a string the Json Serialization will use
|
||||
//! a JSON Object to store the data in instead of an array with key/value objects.
|
||||
//! Note on pointers: The Json Serialization assumes that are always constructed, so a default JSON value of "{}" is interpret as
|
||||
//! creating a new default instance even if the default value is a null pointer. A JSON Null needs to be explicitly stored in
|
||||
//! the JSON Document in order to default or explicitly set a pointer to null.
|
||||
//! Note on pointer memory: Objects created/destroyed by the Json Serialization for pointers require that the AZ_CLASS_ALLOCATOR is
|
||||
//! declared and the object is created using aznew or memory is allocated using azmalloc. Without these the application may
|
||||
//! crash if the Json Serialization tries to create or destroy an object pointed to by a pointer.
|
||||
class JsonSerialization final
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -215,10 +215,10 @@ namespace AZ
|
||||
// Load key
|
||||
void* keyAddress = pairContainer->GetElementByIndex(address, pairElement, 0);
|
||||
AZ_Assert(keyAddress, "Element reserved for associative container, but unable to retrieve address of the key.");
|
||||
Flags keyLoadFlags = Flags::None;
|
||||
ContinuationFlags keyLoadFlags = ContinuationFlags::None;
|
||||
if (keyElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER)
|
||||
{
|
||||
keyLoadFlags = Flags::ResolvePointer;
|
||||
keyLoadFlags = ContinuationFlags::ResolvePointer;
|
||||
*reinterpret_cast<void**>(keyAddress) = nullptr;
|
||||
}
|
||||
JSR::ResultCode keyResult = ContinueLoading(keyAddress, keyElement->m_typeId, key, context, keyLoadFlags);
|
||||
@@ -231,10 +231,10 @@ namespace AZ
|
||||
// Load value
|
||||
void* valueAddress = pairContainer->GetElementByIndex(address, pairElement, 1);
|
||||
AZ_Assert(valueAddress, "Element reserved for associative container, but unable to retrieve address of the value.");
|
||||
Flags valueLoadFlags = Flags::None;
|
||||
ContinuationFlags valueLoadFlags = ContinuationFlags::None;
|
||||
if (valueElement->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER)
|
||||
{
|
||||
valueLoadFlags = Flags::ResolvePointer;
|
||||
valueLoadFlags = ContinuationFlags::ResolvePointer;
|
||||
*reinterpret_cast<void**>(valueAddress) = nullptr;
|
||||
}
|
||||
JSR::ResultCode valueResult = ContinueLoading(valueAddress, valueElement->m_typeId, value, context, valueLoadFlags);
|
||||
|
||||
@@ -23,13 +23,6 @@ namespace AZ
|
||||
{
|
||||
namespace JSR = JsonSerializationResult;
|
||||
|
||||
if (IsExplicitDefault(inputValue))
|
||||
{
|
||||
// Do nothing if the input is an explicit default.
|
||||
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::DefaultsUsed,
|
||||
"Default value for smart pointer requested so no change was made.");
|
||||
}
|
||||
|
||||
const SerializeContext::ClassData* containerClass = context.GetSerializeContext()->FindClassData(outputValueTypeId);
|
||||
if (!containerClass)
|
||||
{
|
||||
@@ -89,7 +82,7 @@ namespace AZ
|
||||
{
|
||||
// If the target type is the same as the type already stored in the smart pointer than no new
|
||||
// instance is created and the existing instance will be updated with the data in the json document.
|
||||
result = ContinueLoading(instance, elementClassId, inputValue, context, Flags::ResolvePointer);
|
||||
result = ContinueLoading(instance, elementClassId, inputValue, context, ContinuationFlags::ResolvePointer);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -100,7 +93,7 @@ namespace AZ
|
||||
// the wrong address. In these cases explicitly reset the smart pointer. This will erase the existing
|
||||
// data but that's fine as it's not being used.
|
||||
void* element = nullptr;
|
||||
result = ContinueLoading(&element, elementClassId, inputValue, context, Flags::ResolvePointer);
|
||||
result = ContinueLoading(&element, elementClassId, inputValue, context, ContinuationFlags::ResolvePointer);
|
||||
if (result.GetProcessing() != JSR::Processing::Halted && result.GetProcessing() != JSR::Processing::Altered)
|
||||
{
|
||||
void* elementPtr = container->ReserveElement(instance, nullptr);
|
||||
@@ -153,8 +146,7 @@ namespace AZ
|
||||
|
||||
if (defaultValue)
|
||||
{
|
||||
bool typesMatch = false;
|
||||
auto defaultInputCallback = [&defaultValue, &inputPtrType, &typesMatch]
|
||||
auto defaultInputCallback = [&defaultValue]
|
||||
(void* elementPtr, const Uuid&, const SerializeContext::ClassData*, const SerializeContext::ClassElement*)
|
||||
{
|
||||
defaultValue = elementPtr;
|
||||
@@ -163,13 +155,14 @@ namespace AZ
|
||||
container->EnumElements(const_cast<void*>(defaultValue), defaultInputCallback);
|
||||
}
|
||||
|
||||
JSR::ResultCode result = ContinueStoring(outputValue, inputValue, defaultValue, inputPtrType, context, Flags::ResolvePointer);
|
||||
if (result.GetOutcome() == JSR::Outcomes::DefaultsUsed)
|
||||
{
|
||||
outputValue = GetExplicitDefault();
|
||||
return context.Report(result, "Smart pointer used all defaults.");
|
||||
}
|
||||
JSR::ResultCode result =
|
||||
ContinueStoring(outputValue, inputValue, defaultValue, inputPtrType, context, ContinuationFlags::ResolvePointer);
|
||||
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted ?
|
||||
"Successfully processed smart pointer." : "A problem occurred while processing a smart pointer.");
|
||||
}
|
||||
|
||||
BaseJsonSerializer::OperationFlags JsonSmartPointerSerializer::GetOperationsFlags() const
|
||||
{
|
||||
return OperationFlags::ManualDefault;
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
@@ -28,5 +28,7 @@ namespace AZ
|
||||
JsonDeserializerContext& context) override;
|
||||
JsonSerializationResult::Result Store(rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue,
|
||||
const Uuid& valueTypeId, JsonSerializerContext& context) override;
|
||||
|
||||
OperationFlags GetOperationsFlags() const override;
|
||||
};
|
||||
} // namespace AZ
|
||||
|
||||
@@ -99,8 +99,9 @@ namespace AZ
|
||||
|
||||
ScopedContextPath subPath(context, i);
|
||||
|
||||
Flags flags = classElements[i]->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER ?
|
||||
Flags::ResolvePointer : Flags::None;
|
||||
ContinuationFlags flags = classElements[i]->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER
|
||||
? ContinuationFlags::ResolvePointer
|
||||
: ContinuationFlags::None;
|
||||
|
||||
JSR::ResultCode result = ContinueStoring(elementValues[i], elementAddress, defaultElementAddress,
|
||||
classElements[i]->m_typeId, context, flags);
|
||||
@@ -179,8 +180,9 @@ namespace AZ
|
||||
void* elementAddress = container->GetElementByIndex(outputValue, nullptr, i);
|
||||
AZ_Assert(elementAddress, "Address of AZStd::pair or AZStd::tuple element %zu could not be retrieved.", i);
|
||||
|
||||
Flags flags = classElements[i]->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER ?
|
||||
Flags::ResolvePointer : Flags::None;
|
||||
ContinuationFlags flags = classElements[i]->m_flags & SerializeContext::ClassElement::Flags::FLG_POINTER
|
||||
? ContinuationFlags::ResolvePointer
|
||||
: ContinuationFlags::None;
|
||||
|
||||
while (arrayIndex < inputValue.Size())
|
||||
{
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
|
||||
#include <AzCore/Memory/OSAllocator.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
|
||||
|
||||
@@ -33,6 +33,10 @@ namespace UnitTest
|
||||
MOCK_METHOD1(UnregisterComponentDescriptor, void (const AZ::ComponentDescriptor*));
|
||||
MOCK_METHOD1(RegisterEntityAddedEventHandler, void(AZ::EntityAddedEvent::Handler&));
|
||||
MOCK_METHOD1(RegisterEntityRemovedEventHandler, void(AZ::EntityRemovedEvent::Handler&));
|
||||
MOCK_METHOD1(RegisterEntityActivatedEventHandler, void(AZ::EntityActivatedEvent::Handler&));
|
||||
MOCK_METHOD1(RegisterEntityDeactivatedEventHandler, void(AZ::EntityDeactivatedEvent::Handler&));
|
||||
MOCK_METHOD1(SignalEntityActivated, void(AZ::Entity*));
|
||||
MOCK_METHOD1(SignalEntityDeactivated, void(AZ::Entity*));
|
||||
MOCK_METHOD1(RemoveEntity, bool (AZ::Entity*));
|
||||
MOCK_METHOD1(DeleteEntity, bool (const AZ::EntityId&));
|
||||
MOCK_METHOD1(GetEntityName, AZStd::string (const AZ::EntityId&));
|
||||
|
||||
@@ -169,5 +169,10 @@ namespace AZ::Utils
|
||||
template AZ::Outcome<AZStd::vector<int8_t>, AZStd::string> ReadFile(AZStd::string_view filePath, size_t maxFileSize);
|
||||
template AZ::Outcome<AZStd::vector<uint8_t>, AZStd::string> ReadFile(AZStd::string_view filePath, size_t maxFileSize);
|
||||
|
||||
|
||||
AZ::IO::FixedMaxPathString GetO3deManifestDirectory()
|
||||
{
|
||||
AZ::IO::FixedMaxPath path = GetHomeDirectory();
|
||||
path /= ".o3de";
|
||||
return path.Native();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,9 @@ namespace AZ
|
||||
//! Retrieves the project name from the settings registry
|
||||
AZ::SettingsRegistryInterface::FixedValueString GetProjectName();
|
||||
|
||||
//! Retrieves the full directory to the Home directory, i.e. "<userhome> or overrideHomeDirectory"
|
||||
AZ::IO::FixedMaxPathString GetHomeDirectory();
|
||||
|
||||
//! Retrieves the full directory to the O3DE manifest directory, i.e. "<userhome>/.o3de"
|
||||
AZ::IO::FixedMaxPathString GetO3deManifestDirectory();
|
||||
|
||||
|
||||
@@ -290,6 +290,8 @@ set(FILES
|
||||
Math/MathScriptHelpers.h
|
||||
Math/MathUtils.cpp
|
||||
Math/MathUtils.h
|
||||
Math/MathMatrixSerializer.h
|
||||
Math/MathMatrixSerializer.cpp
|
||||
Math/MathVectorSerializer.h
|
||||
Math/MathVectorSerializer.cpp
|
||||
Math/Matrix3x3.cpp
|
||||
|
||||
@@ -31,6 +31,7 @@ set(FILES
|
||||
iterator.h
|
||||
limits.h
|
||||
numeric.h
|
||||
math.h
|
||||
optional.h
|
||||
ratio.h
|
||||
reference_wrapper.h
|
||||
|
||||
+31
-26
@@ -1,26 +1,31 @@
|
||||
/*
|
||||
* 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/RTTI/RTTI.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
class AtomActiveInterface
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(AtomActiveInterface, "{4BB59C86-0848-485D-AB28-700540470B2B}");
|
||||
|
||||
AtomActiveInterface() = default;
|
||||
virtual ~AtomActiveInterface() = default;
|
||||
};
|
||||
} // namespace AzFramework
|
||||
/*
|
||||
* 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 <cmath>
|
||||
|
||||
namespace AZStd
|
||||
{
|
||||
using std::abs;
|
||||
using std::acos;
|
||||
using std::asin;
|
||||
using std::atan;
|
||||
using std::atan2;
|
||||
using std::cos;
|
||||
using std::exp2;
|
||||
using std::fmod;
|
||||
using std::round;
|
||||
using std::sin;
|
||||
using std::sqrt;
|
||||
using std::tan;
|
||||
} // namespace AZStd
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
|
||||
namespace AZ::Utils
|
||||
{
|
||||
AZ::IO::FixedMaxPathString GetO3deManifestDirectory()
|
||||
AZ::IO::FixedMaxPathString GetHomeDirectory()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -25,8 +25,19 @@ namespace AZ
|
||||
|
||||
void NativeErrorMessageBox(const char*, const char*) {}
|
||||
|
||||
AZ::IO::FixedMaxPathString GetO3deManifestDirectory()
|
||||
AZ::IO::FixedMaxPathString GetHomeDirectory()
|
||||
{
|
||||
constexpr AZStd::string_view overrideHomeDirKey = "/Amazon/Settings/override_home_dir";
|
||||
AZ::IO::FixedMaxPathString overrideHomeDir;
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
if (settingsRegistry->Get(overrideHomeDir, overrideHomeDirKey))
|
||||
{
|
||||
AZ::IO::FixedMaxPath path{overrideHomeDir};
|
||||
return path.Native();
|
||||
}
|
||||
}
|
||||
|
||||
if (const char* homePath = std::getenv("HOME"); homePath != nullptr)
|
||||
{
|
||||
AZ::IO::FixedMaxPath path{homePath};
|
||||
|
||||
@@ -22,15 +22,25 @@ namespace AZ::Utils
|
||||
::MessageBox(0, message, title, MB_OK | MB_ICONERROR);
|
||||
}
|
||||
|
||||
AZ::IO::FixedMaxPathString GetO3deManifestDirectory()
|
||||
AZ::IO::FixedMaxPathString GetHomeDirectory()
|
||||
{
|
||||
constexpr AZStd::string_view overrideHomeDirKey = "/Amazon/Settings/override_home_dir";
|
||||
AZ::IO::FixedMaxPathString overrideHomeDir;
|
||||
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
|
||||
{
|
||||
if (settingsRegistry->Get(overrideHomeDir, overrideHomeDirKey))
|
||||
{
|
||||
AZ::IO::FixedMaxPath path{overrideHomeDir};
|
||||
return path.Native();
|
||||
}
|
||||
}
|
||||
|
||||
char userProfileBuffer[AZ::IO::MaxPathLength]{};
|
||||
size_t variableSize = 0;
|
||||
auto err = getenv_s(&variableSize, userProfileBuffer, AZ::IO::MaxPathLength, "USERPROFILE");
|
||||
if (!err)
|
||||
{
|
||||
AZ::IO::FixedMaxPath path{ userProfileBuffer };
|
||||
path /= ".o3de";
|
||||
return path.Native();
|
||||
}
|
||||
|
||||
|
||||
@@ -330,4 +330,163 @@ namespace UnitTest
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// The AssetManagerStreamerImmediateCompletionTests class adjusts the asset loading to force it to complete immediately,
|
||||
// while still within the callstack for GetAsset(). This can be used to test various conditions in which the load thread
|
||||
// completes more rapidly than expected, and can expose subtle race conditions.
|
||||
// There are a few key things that this class does to make this work:
|
||||
// - The file I/O streamer is mocked
|
||||
// - The asset stream data is mocked to a 0-byte length for the asset so that the stream load will bypass the I/O streamer and
|
||||
// just immediately return completion.
|
||||
// - The number of JobManager threads is set to 0, forcing jobs to execute synchronously inline when they are started.
|
||||
// With these changes, GetAssetInternal() will queue the stream, which will immediately call the callback that creates LoadAssetJob,
|
||||
// which immediately executes in-place to process the asset due to the synchronous JobManager.
|
||||
// Note that if we just created the asset in a Ready state, most of the asset loading code is completely bypassed, and so we
|
||||
// wouldn't be able to test for race conditions in the AssetContainer.
|
||||
//
|
||||
// This class also unregisters the catalog and asset handler before shutting down the asset manager. This is done to catch
|
||||
// any outstanding asset references that exist due to loads not completing and cleaning up successfully.
|
||||
struct AssetManagerStreamerImmediateCompletionTests : public BaseAssetManagerTest,
|
||||
public AZ::Data::AssetCatalogRequestBus::Handler,
|
||||
public AZ::Data::AssetHandler,
|
||||
public AZ::Data::AssetCatalog
|
||||
{
|
||||
static inline const AZ::Uuid TestAssetId{"{E970B177-5F45-44EB-A2C4-9F29D9A0B2A2}"};
|
||||
static inline constexpr AZStd::string_view TestAssetPath = "test";
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
BaseAssetManagerTest::SetUp();
|
||||
AssetManager::Descriptor desc;
|
||||
AssetManager::Create(desc);
|
||||
|
||||
// Register the handler and catalog after creation, because we intend to destroy them before AssetManager destruction.
|
||||
// The specific asset we load is irrelevant, so register EmptyAsset.
|
||||
AZ::Data::AssetManager::Instance().RegisterHandler(this, AZ::AzTypeInfo<EmptyAsset>::Uuid());
|
||||
AZ::Data::AssetManager::Instance().RegisterCatalog(this, AZ::AzTypeInfo<EmptyAsset>::Uuid());
|
||||
|
||||
// Intercept messages for finding assets by name so that we can mock out the asset we're loading.
|
||||
AZ::Data::AssetCatalogRequestBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
// Unregister before destroying AssetManager.
|
||||
// This will catch any assets that got stuck in a loading state without getting cleaned up.
|
||||
AZ::Data::AssetManager::Instance().UnregisterCatalog(this);
|
||||
AZ::Data::AssetManager::Instance().UnregisterHandler(this);
|
||||
|
||||
AZ::Data::AssetCatalogRequestBus::Handler::BusDisconnect();
|
||||
|
||||
AssetManager::Destroy();
|
||||
BaseAssetManagerTest::TearDown();
|
||||
}
|
||||
|
||||
size_t GetNumJobManagerThreads() const override
|
||||
{
|
||||
// Return 0 threads so that the Job Manager executes jobs synchronously inline. This lets us finish a load while still
|
||||
// in the callstack that initiates the load.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create a mock streamer instead of a real one, since we don't really want to load an asset.
|
||||
IO::IStreamer* CreateStreamer() override
|
||||
{
|
||||
m_mockStreamer = AZStd::make_unique<StreamerWrapper>();
|
||||
return &(m_mockStreamer->m_mockStreamer);
|
||||
}
|
||||
|
||||
void DestroyStreamer([[maybe_unused]] IO::IStreamer* streamer) override
|
||||
{
|
||||
m_mockStreamer = nullptr;
|
||||
}
|
||||
|
||||
// AssetHandler implementation
|
||||
|
||||
// Minimalist mock to create a new EmptyAsset with the desired asset ID.
|
||||
AZ::Data::AssetPtr CreateAsset(const AZ::Data::AssetId& id, [[maybe_unused]] const AZ::Data::AssetType& type) override
|
||||
{
|
||||
return new EmptyAsset(id);
|
||||
}
|
||||
|
||||
void DestroyAsset(AZ::Data::AssetPtr ptr) override
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
// The mocked-out Asset Catalog handles EmptyAsset types.
|
||||
void GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes) override
|
||||
{
|
||||
assetTypes.push_back(AZ::AzTypeInfo<EmptyAsset>::Uuid());
|
||||
}
|
||||
|
||||
// This is a mocked-out load, so just immediately return completion without doing anything.
|
||||
AZ::Data::AssetHandler::LoadResult LoadAssetData(
|
||||
[[maybe_unused]] const AZ::Data::Asset<AZ::Data::AssetData>& asset,
|
||||
[[maybe_unused]] AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
|
||||
[[maybe_unused]] const AZ::Data::AssetFilterCB& assetLoadFilterCB)
|
||||
{
|
||||
return AZ::Data::AssetHandler::LoadResult::LoadComplete;
|
||||
}
|
||||
|
||||
// AssetCatalogRequestBus implementation
|
||||
|
||||
// Minimalist mocks to provide our desired asset path or asset id
|
||||
AZStd::string GetAssetPathById([[maybe_unused]] const AZ::Data::AssetId& id) override
|
||||
{
|
||||
return TestAssetPath;
|
||||
}
|
||||
AZ::Data::AssetId GetAssetIdByPath(
|
||||
[[maybe_unused]] const char* path, [[maybe_unused]] const AZ::Data::AssetType& typeToRegister,
|
||||
[[maybe_unused]] bool autoRegisterIfNotFound) override
|
||||
{
|
||||
return TestAssetId;
|
||||
}
|
||||
|
||||
// Return the mocked-out information for our test asset
|
||||
AZ::Data::AssetInfo GetAssetInfoById([[maybe_unused]] const AZ::Data::AssetId& id) override
|
||||
{
|
||||
AZ::Data::AssetInfo assetInfo;
|
||||
assetInfo.m_assetId = TestAssetId;
|
||||
assetInfo.m_assetType = AZ::AzTypeInfo<EmptyAsset>::Uuid();
|
||||
assetInfo.m_relativePath = TestAssetPath;
|
||||
return assetInfo;
|
||||
}
|
||||
|
||||
// AssetCatalog implementation
|
||||
|
||||
// Set the mocked-out asset load to have a 0-byte length so that the load skips I/O and immediately returns success
|
||||
AZ::Data::AssetStreamInfo GetStreamInfoForLoad(
|
||||
[[maybe_unused]] const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override
|
||||
{
|
||||
EXPECT_TRUE(type == AZ::AzTypeInfo<EmptyAsset>::Uuid());
|
||||
AZ::Data::AssetStreamInfo info;
|
||||
info.m_dataOffset = 0;
|
||||
info.m_streamName = TestAssetPath;
|
||||
info.m_dataLen = 0;
|
||||
info.m_streamFlags = AZ::IO::OpenMode::ModeRead;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<StreamerWrapper> m_mockStreamer;
|
||||
};
|
||||
|
||||
// This test will verify that even if the asset loading stream/job returns immediately, all of the loading
|
||||
// code works successfully. The test here is fairly simple - it just loads the asset and verifies that it
|
||||
// loaded successfully. The bulk of the test is really in the setup class above, where the load is forced
|
||||
// to complete immediately. Also, the true failure condition is caught in the setup class too, which is
|
||||
// the presence of any assets at the point that the asset handler is unregistered. If they're present, then
|
||||
// the immediate load wasn't truly successful, as it left around extra references to the asset that haven't
|
||||
// been cleaned up.
|
||||
TEST_F(AssetManagerStreamerImmediateCompletionTests, LoadAssetWithImmediateJobCompletion_WorksSuccessfully)
|
||||
{
|
||||
AZ::Data::AssetLoadParameters loadParams;
|
||||
|
||||
auto testAsset =
|
||||
AssetManager::Instance().GetAsset<EmptyAsset>(TestAssetId, AZ::Data::AssetLoadBehavior::Default, loadParams);
|
||||
|
||||
AZ::Data::AssetManager::Instance().DispatchEvents();
|
||||
EXPECT_TRUE(testAsset.IsReady());
|
||||
}
|
||||
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -24,6 +24,13 @@ namespace UnitTest
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(EmptyAsset, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(EmptyAsset, "{098E3F7F-13AC-414B-9B4E-49B5AD1BD7FE}", AZ::Data::AssetData);
|
||||
|
||||
EmptyAsset(
|
||||
const AZ::Data::AssetId& assetId = AZ::Data::AssetId(),
|
||||
AZ::Data::AssetData::AssetStatus status = AZ::Data::AssetData::AssetStatus::NotLoaded)
|
||||
: AZ::Data::AssetData(assetId, status)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// EmptyAssetWithNoHandler: no data contained within, and no AssetHandler registered for this type
|
||||
|
||||
@@ -104,6 +104,11 @@ namespace JsonSerializationTests
|
||||
AZ::AllocatorInstance<AZ::PoolAllocator>::Destroy();
|
||||
}
|
||||
|
||||
void Reflect(AZStd::unique_ptr<AZ::SerializeContext>& context) override
|
||||
{
|
||||
context->RegisterGenericType<Asset>();
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<AZ::BaseJsonSerializer> CreateSerializer() override
|
||||
{
|
||||
return AZStd::make_shared<AZ::Data::AssetJsonSerializer>();
|
||||
@@ -130,6 +135,7 @@ namespace JsonSerializationTests
|
||||
auto instance = AZStd::make_shared<Asset>();
|
||||
instance->Create(id, false);
|
||||
instance->SetHint("TestFile");
|
||||
instance->SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::PreLoad);
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -153,6 +159,7 @@ namespace JsonSerializationTests
|
||||
"guid": "{BBEAC89F-8BAD-4A9D-BF6E-D0DF84A8DFD6}",
|
||||
"subId": 1
|
||||
},
|
||||
"loadBehavior": "PreLoad",
|
||||
"assetHint": "TestFile"
|
||||
})";
|
||||
}
|
||||
|
||||
@@ -49,9 +49,13 @@ namespace UnitTest
|
||||
// ComponentApplicationBus
|
||||
AZ::ComponentApplication* GetApplication() override { return nullptr; }
|
||||
void RegisterComponentDescriptor(const AZ::ComponentDescriptor*) override {}
|
||||
void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override {}
|
||||
void RegisterEntityAddedEventHandler(AZ::EntityAddedEvent::Handler&) override {}
|
||||
void RegisterEntityRemovedEventHandler(AZ::EntityRemovedEvent::Handler&) override {}
|
||||
void UnregisterComponentDescriptor(const AZ::ComponentDescriptor*) override {}
|
||||
void RegisterEntityActivatedEventHandler(AZ::EntityActivatedEvent::Handler&) override {}
|
||||
void RegisterEntityDeactivatedEventHandler(AZ::EntityDeactivatedEvent::Handler&) override {}
|
||||
void SignalEntityActivated(AZ::Entity*) override {}
|
||||
void SignalEntityDeactivated(AZ::Entity*) override {}
|
||||
bool AddEntity(AZ::Entity*) override { return true; }
|
||||
bool RemoveEntity(AZ::Entity*) override { return true; }
|
||||
bool DeleteEntity(const AZ::EntityId&) override { return true; }
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/Math/Quaternion.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AZTestShared/Math/MathTestHelpers.h>
|
||||
|
||||
using namespace AZ;
|
||||
|
||||
@@ -251,19 +252,19 @@ namespace UnitTest
|
||||
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
|
||||
|
||||
Matrix3x3 m3 = m1 * m2;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(66.0f, 72.0f, 78.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(156.0f, 171.0f, 186.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(246.0f, 270.0f, 294.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(66.0f, 72.0f, 78.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(156.0f, 171.0f, 186.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(246.0f, 270.0f, 294.0f)));
|
||||
|
||||
Matrix3x3 m4 = m1;
|
||||
m4 *= m2;
|
||||
AZ_TEST_ASSERT(m4.GetRow(0).IsClose(Vector3(66.0f, 72.0f, 78.0f)));
|
||||
AZ_TEST_ASSERT(m4.GetRow(1).IsClose(Vector3(156.0f, 171.0f, 186.0f)));
|
||||
AZ_TEST_ASSERT(m4.GetRow(2).IsClose(Vector3(246.0f, 270.0f, 294.0f)));
|
||||
EXPECT_THAT(m4.GetRow(0), IsClose(Vector3(66.0f, 72.0f, 78.0f)));
|
||||
EXPECT_THAT(m4.GetRow(1), IsClose(Vector3(156.0f, 171.0f, 186.0f)));
|
||||
EXPECT_THAT(m4.GetRow(2), IsClose(Vector3(246.0f, 270.0f, 294.0f)));
|
||||
m3 = m1.TransposedMultiply(m2);
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(138.0f, 150.0f, 162.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(168.0f, 183.0f, 198.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(198.0f, 216.0f, 234.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(138.0f, 150.0f, 162.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(168.0f, 183.0f, 198.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(198.0f, 216.0f, 234.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestVectorMultiplication)
|
||||
@@ -277,11 +278,11 @@ namespace UnitTest
|
||||
m2.SetRow(1, 10.0f, 11.0f, 12.0f);
|
||||
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
|
||||
|
||||
AZ_TEST_ASSERT((m1 * Vector3(1.0f, 2.0f, 3.0f)).IsClose(Vector3(14.0f, 32.0f, 50.0f)));
|
||||
EXPECT_THAT((m1 * Vector3(1.0f, 2.0f, 3.0f)), IsClose(Vector3(14.0f, 32.0f, 50.0f)));
|
||||
Vector3 v1(1.0f, 2.0f, 3.0f);
|
||||
AZ_TEST_ASSERT((v1 * m1).IsClose(Vector3(30.0f, 36.0f, 42.0f)));
|
||||
EXPECT_THAT((v1 * m1), IsClose(Vector3(30.0f, 36.0f, 42.0f)));
|
||||
v1 *= m1;
|
||||
AZ_TEST_ASSERT(v1.IsClose(Vector3(30.0f, 36.0f, 42.0f)));
|
||||
EXPECT_THAT(v1, IsClose(Vector3(30.0f, 36.0f, 42.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestSum)
|
||||
@@ -296,15 +297,15 @@ namespace UnitTest
|
||||
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
|
||||
|
||||
Matrix3x3 m3 = m1 + m2;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(20.0f, 22.0f, 24.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(20.0f, 22.0f, 24.0f)));
|
||||
|
||||
m3 = m1;
|
||||
m3 += m2;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(20.0f, 22.0f, 24.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(20.0f, 22.0f, 24.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestDifference)
|
||||
@@ -319,14 +320,14 @@ namespace UnitTest
|
||||
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
|
||||
|
||||
Matrix3x3 m3 = m1 - m2;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
m3 = m1;
|
||||
m3 -= m2;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(-6.0f, -6.0f, -6.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestScalarMultiplication)
|
||||
@@ -341,18 +342,18 @@ namespace UnitTest
|
||||
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
|
||||
|
||||
Matrix3x3 m3 = m1 * 2.0f;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
m3 = m1;
|
||||
m3 *= 2.0f;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
m3 = 2.0f * m1;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestScalarDivision)
|
||||
@@ -367,18 +368,32 @@ namespace UnitTest
|
||||
m2.SetRow(2, 13.0f, 14.0f, 15.0f);
|
||||
|
||||
Matrix3x3 m3 = m1 / 0.5f;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
m3 = m1;
|
||||
m3 /= 0.5f;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
m3 = -m1;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector3(-1.0f, -2.0f, -3.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector3(-4.0f, -5.0f, -6.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector3(-7.0f, -8.0f, -9.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector3(2.0f, 4.0f, 6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector3(8.0f, 10.0f, 12.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector3(14.0f, 16.0f, 18.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestNegation)
|
||||
{
|
||||
Matrix3x3 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f);
|
||||
m1.SetRow(1, 4.0f, 5.0f, 6.0f);
|
||||
m1.SetRow(2, 7.0f, 8.0f, 9.0f);
|
||||
EXPECT_THAT(-(-m1), IsClose(m1));
|
||||
EXPECT_THAT(-Matrix3x3::CreateZero(), IsClose(Matrix3x3::CreateZero()));
|
||||
|
||||
Matrix3x3 m2 = -m1;
|
||||
EXPECT_THAT(m2.GetRow(0), IsClose(Vector3(-1.0f, -2.0f, -3.0f)));
|
||||
EXPECT_THAT(m2.GetRow(1), IsClose(Vector3(-4.0f, -5.0f, -6.0f)));
|
||||
EXPECT_THAT(m2.GetRow(2), IsClose(Vector3(-7.0f, -8.0f, -9.0f)));
|
||||
|
||||
Matrix3x3 m3 = m1 + (-m1);
|
||||
EXPECT_THAT(m3, IsClose(Matrix3x3::CreateZero()));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestTranspose)
|
||||
@@ -425,11 +440,33 @@ namespace UnitTest
|
||||
TEST(MATH_Matrix3x3, TestScaleAccess)
|
||||
{
|
||||
Matrix3x3 m1 = Matrix3x3::CreateRotationX(DegToRad(40.0f)) * Matrix3x3::CreateScale(Vector3(2.0f, 3.0f, 4.0f));
|
||||
AZ_TEST_ASSERT(m1.RetrieveScale().IsClose(Vector3(2.0f, 3.0f, 4.0f)));
|
||||
AZ_TEST_ASSERT(m1.ExtractScale().IsClose(Vector3(2.0f, 3.0f, 4.0f)));
|
||||
AZ_TEST_ASSERT(m1.RetrieveScale().IsClose(Vector3::CreateOne()));
|
||||
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3(2.0f, 3.0f, 4.0f)));
|
||||
EXPECT_THAT(m1.ExtractScale(), IsClose(Vector3(2.0f, 3.0f, 4.0f)));
|
||||
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3::CreateOne()));
|
||||
m1.MultiplyByScale(Vector3(3.0f, 4.0f, 5.0f));
|
||||
AZ_TEST_ASSERT(m1.RetrieveScale().IsClose(Vector3(3.0f, 4.0f, 5.0f)));
|
||||
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3(3.0f, 4.0f, 5.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestScaleSqAccess)
|
||||
{
|
||||
Matrix3x3 m1 = Matrix3x3::CreateRotationX(DegToRad(40.0f)) * Matrix3x3::CreateScale(Vector3(2.0f, 3.0f, 4.0f));
|
||||
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3(4.0f, 9.0f, 16.0f)));
|
||||
m1.ExtractScale();
|
||||
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3::CreateOne()));
|
||||
m1.MultiplyByScale(Vector3(3.0f, 4.0f, 5.0f));
|
||||
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3(9.0f, 16.0f, 25.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestReciprocalScaled)
|
||||
{
|
||||
Matrix3x3 orthogonalMatrix = Matrix3x3::CreateRotationX(DegToRad(40.0f));
|
||||
EXPECT_THAT(orthogonalMatrix.GetReciprocalScaled(), IsClose(orthogonalMatrix));
|
||||
const AZ::Vector3 scale(2.8f, 0.7f, 1.3f);
|
||||
AZ::Matrix3x3 scaledMatrix = orthogonalMatrix;
|
||||
scaledMatrix.MultiplyByScale(scale);
|
||||
AZ::Matrix3x3 reciprocalScaledMatrix = orthogonalMatrix;
|
||||
reciprocalScaledMatrix.MultiplyByScale(scale.GetReciprocal());
|
||||
EXPECT_THAT(scaledMatrix.GetReciprocalScaled(), IsClose(reciprocalScaledMatrix));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x3, TestPolarDecomposition)
|
||||
|
||||
@@ -467,21 +467,136 @@ namespace UnitTest
|
||||
EXPECT_THAT(matrix.Multiply3x3(axisDirection), IsClose(forwardDirection));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x4, MultiplyByMatrix3x4)
|
||||
TEST(MATH_Matrix3x4, TestMatrixMultiplication)
|
||||
{
|
||||
const AZ::Matrix3x4 matrix1 = AZ::Matrix3x4::CreateFromValue(1.2f);
|
||||
const AZ::Matrix3x4 matrix2 = AZ::Matrix3x4::CreateDiagonal(AZ::Vector3(1.3f, 1.5f, 0.4f));
|
||||
const AZ::Matrix3x4 matrix3 = AZ::Matrix3x4::CreateFromQuaternionAndTranslation(
|
||||
AZ::Quaternion(0.42f, 0.46f, -0.66f, 0.42f), AZ::Vector3(2.8f, -3.7f, 1.6f));
|
||||
const AZ::Matrix3x4 matrix4 = AZ::Matrix3x4::CreateRotationX(-0.7f) * AZ::Matrix3x4::CreateScale(AZ::Vector3(0.6f, 1.3f, 0.7f));
|
||||
AZ::Matrix3x4 matrix5 = matrix1;
|
||||
matrix5 *= matrix4;
|
||||
const AZ::Vector3 vector(1.9f, 2.3f, 0.2f);
|
||||
EXPECT_TRUE((matrix1 * (matrix2 * matrix3)).IsClose((matrix1 * matrix2) * matrix3));
|
||||
EXPECT_THAT((matrix3 * matrix4) * vector, IsClose(matrix3 * (matrix4 * vector)));
|
||||
EXPECT_TRUE((matrix2 * AZ::Matrix3x4::Identity()).IsClose(matrix2));
|
||||
EXPECT_TRUE((matrix3 * AZ::Matrix3x4::Identity()).IsClose(AZ::Matrix3x4::Identity() * matrix3));
|
||||
EXPECT_TRUE(matrix5.IsClose(matrix1 * matrix4));
|
||||
AZ::Matrix3x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
AZ::Matrix3x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
AZ::Matrix3x4 m3 = m1 * m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(74.0f, 80.0f, 86.0f, 96.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(206.0f, 224.0f, 242.0f, 268.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(338.0f, 368.0f, 398.0f, 440.0f)));
|
||||
AZ::Matrix3x4 m4 = m1;
|
||||
m4 *= m2;
|
||||
EXPECT_THAT(m4.GetRow(0), IsClose(AZ::Vector4(74.0f, 80.0f, 86.0f, 96.0f)));
|
||||
EXPECT_THAT(m4.GetRow(1), IsClose(AZ::Vector4(206.0f, 224.0f, 242.0f, 268.0f)));
|
||||
EXPECT_THAT(m4.GetRow(2), IsClose(AZ::Vector4(338.0f, 368.0f, 398.0f, 440.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x4, TestSum)
|
||||
{
|
||||
AZ::Matrix3x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
AZ::Matrix3x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
|
||||
AZ::Matrix3x4 m3 = m1 + m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(8.0f, 10.0f, 12.0f, 14.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(16.0f, 18.0f, 20.0f, 22.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(24.0f, 26.0f, 28.0f, 30.0f)));
|
||||
|
||||
m3 = m1;
|
||||
m3 += m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(8.0f, 10.0f, 12.0f, 14.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(16.0f, 18.0f, 20.0f, 22.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(24.0f, 26.0f, 28.0f, 30.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x4, TestDifference)
|
||||
{
|
||||
AZ::Matrix3x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
AZ::Matrix3x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
|
||||
AZ::Matrix3x4 m3 = m1 - m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
m3 = m1;
|
||||
m3 -= m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x4, TestScalarMultiplication)
|
||||
{
|
||||
AZ::Matrix3x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
AZ::Matrix3x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
|
||||
AZ::Matrix3x4 m3 = m1 * 2.0f;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
m3 = m1;
|
||||
m3 *= 2.0f;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
m3 = 2.0f * m1;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x4, TestScalarDivision)
|
||||
{
|
||||
AZ::Matrix3x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
AZ::Matrix3x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
|
||||
AZ::Matrix3x4 m3 = m1 / 0.5f;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
m3 = m1;
|
||||
m3 /= 0.5f;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(AZ::Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(AZ::Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(AZ::Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x4, TestNegation)
|
||||
{
|
||||
AZ::Matrix3x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
EXPECT_THAT(-(-m1), IsClose(m1));
|
||||
EXPECT_THAT(-AZ::Matrix3x4::CreateZero(), IsClose(AZ::Matrix3x4::CreateZero()));
|
||||
|
||||
AZ::Matrix3x4 m2 = -m1;
|
||||
EXPECT_THAT(m2.GetRow(0), IsClose(AZ::Vector4(-1.0f, -2.0f, -3.0f, -4.0f)));
|
||||
EXPECT_THAT(m2.GetRow(1), IsClose(AZ::Vector4(-5.0f, -6.0f, -7.0f, -8.0f)));
|
||||
EXPECT_THAT(m2.GetRow(2), IsClose(AZ::Vector4(-9.0f, -10.0f, -11.0f, -12.0f)));
|
||||
|
||||
AZ::Matrix3x4 m3 = m1 + (-m1);
|
||||
EXPECT_THAT(m3, IsClose(AZ::Matrix3x4::CreateZero()));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix3x4, MultiplyByVector3)
|
||||
@@ -652,6 +767,34 @@ namespace UnitTest
|
||||
EXPECT_THAT(scaledMatrix.RetrieveScale(), IsClose(AZ::Vector3::CreateOne()));
|
||||
}
|
||||
|
||||
TEST_P(Matrix3x4ScaleFixture, ScaleSq)
|
||||
{
|
||||
const AZ::Matrix3x4 orthogonalMatrix = GetParam();
|
||||
EXPECT_THAT(orthogonalMatrix.RetrieveScaleSq(), IsClose(AZ::Vector3::CreateOne()));
|
||||
AZ::Matrix3x4 unscaledMatrix = orthogonalMatrix;
|
||||
unscaledMatrix.ExtractScale();
|
||||
EXPECT_THAT(unscaledMatrix.RetrieveScaleSq(), IsClose(AZ::Vector3::CreateOne()));
|
||||
const AZ::Vector3 scale(2.8f, 0.7f, 1.3f);
|
||||
AZ::Matrix3x4 scaledMatrix = orthogonalMatrix;
|
||||
scaledMatrix.MultiplyByScale(scale);
|
||||
EXPECT_THAT(scaledMatrix.RetrieveScaleSq(), IsClose(scale * scale));
|
||||
EXPECT_THAT(scaledMatrix.RetrieveScaleSq(), IsClose(scaledMatrix.RetrieveScale() * scaledMatrix.RetrieveScale()));
|
||||
scaledMatrix.ExtractScale();
|
||||
EXPECT_THAT(scaledMatrix.RetrieveScaleSq(), IsClose(AZ::Vector3::CreateOne()));
|
||||
}
|
||||
|
||||
TEST_P(Matrix3x4ScaleFixture, GetReciprocalScaled)
|
||||
{
|
||||
const AZ::Matrix3x4 orthogonalMatrix = GetParam();
|
||||
EXPECT_THAT(orthogonalMatrix.GetReciprocalScaled(), IsClose(orthogonalMatrix));
|
||||
const AZ::Vector3 scale(2.8f, 0.7f, 1.3f);
|
||||
AZ::Matrix3x4 scaledMatrix = orthogonalMatrix;
|
||||
scaledMatrix.MultiplyByScale(scale);
|
||||
AZ::Matrix3x4 reciprocalScaledMatrix = orthogonalMatrix;
|
||||
reciprocalScaledMatrix.MultiplyByScale(scale.GetReciprocal());
|
||||
EXPECT_THAT(scaledMatrix.GetReciprocalScaled(), IsClose(reciprocalScaledMatrix));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(MATH_Matrix3x4, Matrix3x4ScaleFixture, ::testing::ValuesIn(MathTestData::OrthogonalMatrix3x4s));
|
||||
|
||||
TEST(MATH_Matrix3x4, IsOrthogonal)
|
||||
|
||||
@@ -246,16 +246,16 @@ namespace UnitTest
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
m2.SetRow(3, 19.0f, 20.0f, 21.0f, 22.0f);
|
||||
Matrix4x4 m3 = m1 * m2;
|
||||
AZ_TEST_ASSERT(m3.GetRow(0).IsClose(Vector4(150.0f, 160.0f, 170.0f, 180.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(1).IsClose(Vector4(358.0f, 384.0f, 410.0f, 436.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(2).IsClose(Vector4(566.0f, 608.0f, 650.0f, 692.0f)));
|
||||
AZ_TEST_ASSERT(m3.GetRow(3).IsClose(Vector4(774.0f, 832.0f, 890.0f, 948.0f)));
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(150.0f, 160.0f, 170.0f, 180.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(358.0f, 384.0f, 410.0f, 436.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(566.0f, 608.0f, 650.0f, 692.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(774.0f, 832.0f, 890.0f, 948.0f)));
|
||||
Matrix4x4 m4 = m1;
|
||||
m4 *= m2;
|
||||
AZ_TEST_ASSERT(m4.GetRow(0).IsClose(Vector4(150.0f, 160.0f, 170.0f, 180.0f)));
|
||||
AZ_TEST_ASSERT(m4.GetRow(1).IsClose(Vector4(358.0f, 384.0f, 410.0f, 436.0f)));
|
||||
AZ_TEST_ASSERT(m4.GetRow(2).IsClose(Vector4(566.0f, 608.0f, 650.0f, 692.0f)));
|
||||
AZ_TEST_ASSERT(m4.GetRow(3).IsClose(Vector4(774.0f, 832.0f, 890.0f, 948.0f)));
|
||||
EXPECT_THAT(m4.GetRow(0), IsClose(Vector4(150.0f, 160.0f, 170.0f, 180.0f)));
|
||||
EXPECT_THAT(m4.GetRow(1), IsClose(Vector4(358.0f, 384.0f, 410.0f, 436.0f)));
|
||||
EXPECT_THAT(m4.GetRow(2), IsClose(Vector4(566.0f, 608.0f, 650.0f, 692.0f)));
|
||||
EXPECT_THAT(m4.GetRow(3), IsClose(Vector4(774.0f, 832.0f, 890.0f, 948.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestVectorMultiplication)
|
||||
@@ -265,18 +265,148 @@ namespace UnitTest
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
|
||||
AZ_TEST_ASSERT((m1 * Vector3(1.0f, 2.0f, 3.0f)).IsClose(Vector3(18.0f, 46.0f, 74.0f)));
|
||||
AZ_TEST_ASSERT((m1 * Vector4(1.0f, 2.0f, 3.0f, 4.0f)).IsClose(Vector4(30.0f, 70.0f, 110.0f, 150.0f)));
|
||||
AZ_TEST_ASSERT(m1.TransposedMultiply3x3(Vector3(1.0f, 2.0f, 3.0f)).IsClose(Vector3(38.0f, 44.0f, 50.0f)));
|
||||
AZ_TEST_ASSERT(m1.Multiply3x3(Vector3(1.0f, 2.0f, 3.0f)).IsClose(Vector3(14.0f, 38.0f, 62.0f)));
|
||||
EXPECT_THAT((m1 * Vector3(1.0f, 2.0f, 3.0f)), IsClose(Vector3(18.0f, 46.0f, 74.0f)));
|
||||
EXPECT_THAT((m1 * Vector4(1.0f, 2.0f, 3.0f, 4.0f)), IsClose(Vector4(30.0f, 70.0f, 110.0f, 150.0f)));
|
||||
EXPECT_THAT(m1.TransposedMultiply3x3(Vector3(1.0f, 2.0f, 3.0f)), IsClose(Vector3(38.0f, 44.0f, 50.0f)));
|
||||
EXPECT_THAT(m1.Multiply3x3(Vector3(1.0f, 2.0f, 3.0f)), IsClose(Vector3(14.0f, 38.0f, 62.0f)));
|
||||
Vector3 v1(1.0f, 2.0f, 3.0f);
|
||||
AZ_TEST_ASSERT((v1 * m1).IsClose(Vector3(51.0f, 58.0f, 65.0f)));
|
||||
EXPECT_THAT((v1 * m1), IsClose(Vector3(51.0f, 58.0f, 65.0f)));
|
||||
v1 *= m1;
|
||||
AZ_TEST_ASSERT(v1.IsClose(Vector3(51.0f, 58.0f, 65.0f)));
|
||||
EXPECT_THAT(v1, IsClose(Vector3(51.0f, 58.0f, 65.0f)));
|
||||
Vector4 v2(1.0f, 2.0f, 3.0f, 4.0f);
|
||||
AZ_TEST_ASSERT((v2 * m1).IsClose(Vector4(90.0f, 100.0f, 110.0f, 120.0f)));
|
||||
EXPECT_THAT((v2 * m1), IsClose(Vector4(90.0f, 100.0f, 110.0f, 120.0f)));
|
||||
v2 *= m1;
|
||||
AZ_TEST_ASSERT(v2.IsClose(Vector4(90.0f, 100.0f, 110.0f, 120.0f)));
|
||||
EXPECT_THAT(v2, IsClose(Vector4(90.0f, 100.0f, 110.0f, 120.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestSum)
|
||||
{
|
||||
Matrix4x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
|
||||
Matrix4x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
m2.SetRow(3, 19.0f, 20.0f, 21.0f, 22.0f);
|
||||
|
||||
Matrix4x4 m3 = m1 + m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(8.0f, 10.0f, 12.0f, 14.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(16.0f, 18.0f, 20.0f, 22.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(24.0f, 26.0f, 28.0f, 30.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(32.0f, 34.0f, 36.0f, 38.0f)));
|
||||
|
||||
m3 = m1;
|
||||
m3 += m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(8.0f, 10.0f, 12.0f, 14.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(16.0f, 18.0f, 20.0f, 22.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(24.0f, 26.0f, 28.0f, 30.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(32.0f, 34.0f, 36.0f, 38.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestDifference)
|
||||
{
|
||||
Matrix4x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
|
||||
Matrix4x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
m2.SetRow(3, 19.0f, 20.0f, 21.0f, 22.0f);
|
||||
|
||||
Matrix4x4 m3 = m1 - m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
m3 = m1;
|
||||
m3 -= m2;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(-6.0f, -6.0f, -6.0f, -6.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestScalarMultiplication)
|
||||
{
|
||||
Matrix4x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
|
||||
Matrix4x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
m2.SetRow(3, 19.0f, 20.0f, 21.0f, 22.0f);
|
||||
|
||||
Matrix4x4 m3 = m1 * 2.0f;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(26.0f, 28.0f, 30.0f, 32.0f)));
|
||||
m3 = m1;
|
||||
m3 *= 2.0f;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(26.0f, 28.0f, 30.0f, 32.0f)));
|
||||
m3 = 2.0f * m1;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(26.0f, 28.0f, 30.0f, 32.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestScalarDivision)
|
||||
{
|
||||
Matrix4x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
|
||||
Matrix4x4 m2;
|
||||
m2.SetRow(0, 7.0f, 8.0f, 9.0f, 10.0f);
|
||||
m2.SetRow(1, 11.0f, 12.0f, 13.0f, 14.0f);
|
||||
m2.SetRow(2, 15.0f, 16.0f, 17.0f, 18.0f);
|
||||
m2.SetRow(3, 19.0f, 20.0f, 21.0f, 22.0f);
|
||||
|
||||
Matrix4x4 m3 = m1 / 0.5f;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(26.0f, 28.0f, 30.0f, 32.0f)));
|
||||
m3 = m1;
|
||||
m3 /= 0.5f;
|
||||
EXPECT_THAT(m3.GetRow(0), IsClose(Vector4(2.0f, 4.0f, 6.0f, 8.0f)));
|
||||
EXPECT_THAT(m3.GetRow(1), IsClose(Vector4(10.0f, 12.0f, 14.0f, 16.0f)));
|
||||
EXPECT_THAT(m3.GetRow(2), IsClose(Vector4(18.0f, 20.0f, 22.0f, 24.0f)));
|
||||
EXPECT_THAT(m3.GetRow(3), IsClose(Vector4(26.0f, 28.0f, 30.0f, 32.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestNegation)
|
||||
{
|
||||
Matrix4x4 m1;
|
||||
m1.SetRow(0, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
m1.SetRow(1, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
m1.SetRow(2, 9.0f, 10.0f, 11.0f, 12.0f);
|
||||
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
|
||||
EXPECT_THAT(-(-m1), IsClose(m1));
|
||||
EXPECT_THAT(-Matrix4x4::CreateZero(), IsClose(Matrix4x4::CreateZero()));
|
||||
|
||||
Matrix4x4 m2 = -m1;
|
||||
EXPECT_THAT(m2.GetRow(0), IsClose(Vector4(-1.0f, -2.0f, -3.0f, -4.0f)));
|
||||
EXPECT_THAT(m2.GetRow(1), IsClose(Vector4(-5.0f, -6.0f, -7.0f, -8.0f)));
|
||||
EXPECT_THAT(m2.GetRow(2), IsClose(Vector4(-9.0f, -10.0f, -11.0f, -12.0f)));
|
||||
EXPECT_THAT(m2.GetRow(3), IsClose(Vector4(-13.0f, -14.0f, -15.0f, -16.0f)));
|
||||
|
||||
Matrix4x4 m3 = m1 + (-m1);
|
||||
EXPECT_THAT(m3, IsClose(Matrix4x4::CreateZero()));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestTranspose)
|
||||
@@ -368,4 +498,36 @@ namespace UnitTest
|
||||
m1.SetRow(3, 13.0f, 14.0f, 15.0f, 16.0f);
|
||||
AZ_TEST_ASSERT(m1.GetDiagonal() == Vector4(1.0f, 6.0f, 11.0f, 16.0f));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestScaleAccess)
|
||||
{
|
||||
Matrix4x4 m1 = Matrix4x4::CreateRotationX(DegToRad(40.0f)) * Matrix4x4::CreateScale(Vector3(2.0f, 3.0f, 4.0f));
|
||||
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3(2.0f, 3.0f, 4.0f)));
|
||||
EXPECT_THAT(m1.ExtractScale(), IsClose(Vector3(2.0f, 3.0f, 4.0f)));
|
||||
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3::CreateOne()));
|
||||
m1.MultiplyByScale(Vector3(3.0f, 4.0f, 5.0f));
|
||||
EXPECT_THAT(m1.RetrieveScale(), IsClose(Vector3(3.0f, 4.0f, 5.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestScaleSqAccess)
|
||||
{
|
||||
Matrix4x4 m1 = Matrix4x4::CreateRotationX(DegToRad(40.0f)) * Matrix4x4::CreateScale(Vector3(2.0f, 3.0f, 4.0f));
|
||||
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3(4.0f, 9.0f, 16.0f)));
|
||||
m1.ExtractScale();
|
||||
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3::CreateOne()));
|
||||
m1.MultiplyByScale(Vector3(3.0f, 4.0f, 5.0f));
|
||||
EXPECT_THAT(m1.RetrieveScaleSq(), IsClose(Vector3(9.0f, 16.0f, 25.0f)));
|
||||
}
|
||||
|
||||
TEST(MATH_Matrix4x4, TestReciprocalScaled)
|
||||
{
|
||||
Matrix4x4 orthogonalMatrix = Matrix4x4::CreateRotationX(DegToRad(40.0f));
|
||||
EXPECT_THAT(orthogonalMatrix.GetReciprocalScaled(), IsClose(orthogonalMatrix));
|
||||
const AZ::Vector3 scale(2.8f, 0.7f, 1.3f);
|
||||
AZ::Matrix4x4 scaledMatrix = orthogonalMatrix;
|
||||
scaledMatrix.MultiplyByScale(scale);
|
||||
AZ::Matrix4x4 reciprocalScaledMatrix = orthogonalMatrix;
|
||||
reciprocalScaledMatrix.MultiplyByScale(scale.GetReciprocal());
|
||||
EXPECT_THAT(scaledMatrix.GetReciprocalScaled(), IsClose(reciprocalScaledMatrix));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1232,6 +1232,10 @@ namespace UnitTest
|
||||
void UnregisterComponentDescriptor(const ComponentDescriptor*) override { }
|
||||
void RegisterEntityAddedEventHandler(EntityAddedEvent::Handler&) override { }
|
||||
void RegisterEntityRemovedEventHandler(EntityRemovedEvent::Handler&) override { }
|
||||
void RegisterEntityActivatedEventHandler(EntityActivatedEvent::Handler&) override { }
|
||||
void RegisterEntityDeactivatedEventHandler(EntityDeactivatedEvent::Handler&) override { }
|
||||
void SignalEntityActivated(Entity*) override { }
|
||||
void SignalEntityDeactivated(Entity*) override { }
|
||||
bool AddEntity(Entity*) override { return false; }
|
||||
bool RemoveEntity(Entity*) override { return false; }
|
||||
bool DeleteEntity(const EntityId&) override { return false; }
|
||||
@@ -1252,6 +1256,7 @@ namespace UnitTest
|
||||
m_serializeContext.reset(aznew AZ::SerializeContext());
|
||||
|
||||
ComponentApplicationBus::Handler::BusConnect();
|
||||
AZ::Interface<AZ::ComponentApplicationRequests>::Register(this);
|
||||
|
||||
AZ::AllocatorInstance<AZ::PoolAllocator>::Create();
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
|
||||
@@ -1270,6 +1275,7 @@ namespace UnitTest
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
|
||||
AZ::AllocatorInstance<AZ::PoolAllocator>::Destroy();
|
||||
|
||||
AZ::Interface<AZ::ComponentApplicationRequests>::Unregister(this);
|
||||
ComponentApplicationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace JsonSerializationTests
|
||||
EXPECT_EQ(42, value);
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueLoading_PointerInstance_ValueLoadedCorrectly)
|
||||
TEST_F(BaseJsonSerializerTests, ContinueLoading_ToPointerInstance_ValueLoadedCorrectly)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
@@ -119,13 +119,62 @@ namespace JsonSerializationTests
|
||||
int value = 0;
|
||||
int* ptrValue = &value;
|
||||
|
||||
ResultCode result = ContinueLoading(&ptrValue, azrtti_typeid<int>(), json, *m_jsonDeserializationContext, Flags::ResolvePointer);
|
||||
ResultCode result =
|
||||
ContinueLoading(&ptrValue, azrtti_typeid<int>(), json, *m_jsonDeserializationContext, ContinuationFlags::ResolvePointer);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
ASSERT_NE(nullptr, ptrValue);
|
||||
EXPECT_EQ(42, value);
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueLoading_ToNullPointer_ValueLoadedCorrectly)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
rapidjson::Value json;
|
||||
json.Set(42);
|
||||
int* ptrValue = nullptr;
|
||||
|
||||
ResultCode result =
|
||||
ContinueLoading(&ptrValue, azrtti_typeid<int>(), json, *m_jsonDeserializationContext, ContinuationFlags::ResolvePointer);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
ASSERT_NE(nullptr, ptrValue);
|
||||
EXPECT_EQ(42, *ptrValue);
|
||||
|
||||
azfree(ptrValue, AZ::SystemAllocator, sizeof(int), alignof(int));
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueLoading_DefaultToNullPointer_ValueLoadedCorrectly)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
rapidjson::Value json(rapidjson::kObjectType);
|
||||
int* ptrValue = nullptr;
|
||||
|
||||
ResultCode result =
|
||||
ContinueLoading(&ptrValue, azrtti_typeid<int>(), json, *m_jsonDeserializationContext, ContinuationFlags::ResolvePointer);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
ASSERT_NE(nullptr, ptrValue);
|
||||
|
||||
azfree(ptrValue, AZ::SystemAllocator, sizeof(int), alignof(int));
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueLoading_NullDeletesObject_ValueLoadedCorrectly)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
rapidjson::Value json(rapidjson::kNullType);
|
||||
int* ptrValue = reinterpret_cast<int*>(azmalloc(sizeof(int), alignof(int), AZ::SystemAllocator));
|
||||
|
||||
ResultCode result =
|
||||
ContinueLoading(&ptrValue, azrtti_typeid<int>(), json, *m_jsonDeserializationContext, ContinuationFlags::ResolvePointer);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
ASSERT_EQ(nullptr, ptrValue);
|
||||
}
|
||||
|
||||
//
|
||||
// ContinueStoring
|
||||
//
|
||||
@@ -149,21 +198,82 @@ namespace JsonSerializationTests
|
||||
int value = 42;
|
||||
int* ptrValue = &value;
|
||||
|
||||
ResultCode result = ContinueStoring(*m_jsonDocument, &ptrValue, nullptr, azrtti_typeid<int>(), *m_jsonSerializationContext,
|
||||
Flags::ResolvePointer);
|
||||
ResultCode result = ContinueStoring(
|
||||
*m_jsonDocument, &ptrValue, nullptr, azrtti_typeid<int>(), *m_jsonSerializationContext, ContinuationFlags::ResolvePointer);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
Expect_DocStrEq("42");
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueStoring_StorePointerToFullDefaultedInstance_ValueStoredCorrectly)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
int value = 42;
|
||||
int* ptrValue = &value;
|
||||
int value2 = 42;
|
||||
int* defaultPtrValue = &value2;
|
||||
|
||||
ResultCode result = ContinueStoring(
|
||||
*m_jsonDocument, &ptrValue, &defaultPtrValue, azrtti_typeid<int>(), *m_jsonSerializationContext,
|
||||
ContinuationFlags::ResolvePointer);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
Expect_DocStrEq("{}");
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueStoring_StorePointerToNullptr_ValueStoredCorrectly)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
int* ptrValue = nullptr;
|
||||
|
||||
ResultCode result = ContinueStoring(
|
||||
*m_jsonDocument, &ptrValue, nullptr, azrtti_typeid<int>(), *m_jsonSerializationContext, ContinuationFlags::ResolvePointer);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
Expect_DocStrEq("null");
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueStoring_StorePointerToNullptrWithValueDefault_ValueStoredCorrectly)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
int* ptrValue = nullptr;
|
||||
int value2 = 42;
|
||||
int* defaultPtrValue = &value2;
|
||||
|
||||
ResultCode result = ContinueStoring(
|
||||
*m_jsonDocument, &ptrValue, &defaultPtrValue, azrtti_typeid<int>(), *m_jsonSerializationContext,
|
||||
ContinuationFlags::ResolvePointer);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
Expect_DocStrEq("null");
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueStoring_StorePointerToNullptrWithNullPtrDefault_NullPtrIsStored)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
int* ptrValue = nullptr;
|
||||
int* defaultPtrValue = nullptr;
|
||||
|
||||
ResultCode result = ContinueStoring(
|
||||
*m_jsonDocument, &ptrValue, &defaultPtrValue, azrtti_typeid<int>(), *m_jsonSerializationContext,
|
||||
ContinuationFlags::ResolvePointer);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
Expect_DocStrEq("null");
|
||||
}
|
||||
|
||||
TEST_F(BaseJsonSerializerTests, ContinueStoring_ReplaceDefault_ValueStoredCorrectly)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
int value = 42;
|
||||
|
||||
ResultCode result = ContinueStoring(*m_jsonDocument, &value, nullptr, azrtti_typeid<int>(), *m_jsonSerializationContext,
|
||||
Flags::ReplaceDefault);
|
||||
ResultCode result = ContinueStoring(
|
||||
*m_jsonDocument, &value, nullptr, azrtti_typeid<int>(), *m_jsonSerializationContext, ContinuationFlags::ReplaceDefault);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
Expect_DocStrEq("42");
|
||||
@@ -177,7 +287,7 @@ namespace JsonSerializationTests
|
||||
int* ptrValue = &value;
|
||||
|
||||
ResultCode result = ContinueStoring(*m_jsonDocument, &ptrValue, nullptr, azrtti_typeid<int>(), *m_jsonSerializationContext,
|
||||
Flags::ResolvePointer | Flags::ReplaceDefault);
|
||||
ContinuationFlags::ResolvePointer | ContinuationFlags::ReplaceDefault);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
Expect_DocStrEq("42");
|
||||
@@ -190,8 +300,8 @@ namespace JsonSerializationTests
|
||||
int value = 42;
|
||||
AZ::Uuid unknownType("{09AE3CEC-EBFC-41EC-A7F6-949721521716}");
|
||||
|
||||
ResultCode result = ContinueStoring(*m_jsonDocument, &value, nullptr, unknownType, *m_jsonSerializationContext,
|
||||
Flags::ReplaceDefault);
|
||||
ResultCode result =
|
||||
ContinueStoring(*m_jsonDocument, &value, nullptr, unknownType, *m_jsonSerializationContext, ContinuationFlags::ReplaceDefault);
|
||||
|
||||
EXPECT_EQ(Processing::Halted, result.GetProcessing());
|
||||
}
|
||||
|
||||
@@ -90,9 +90,14 @@ namespace JsonSerializationTests
|
||||
virtual ~JsonSerializerConformityTestDescriptor() = default;
|
||||
|
||||
virtual AZStd::shared_ptr<AZ::BaseJsonSerializer> CreateSerializer() = 0;
|
||||
|
||||
|
||||
//! Create an instance of the target type with all values set to default.
|
||||
virtual AZStd::shared_ptr<T> CreateDefaultInstance() = 0;
|
||||
//! Create an instance of the target type that constructed with default constructor.
|
||||
//! This will be the same instance that Json Serialization creates for dynamic types. Typically it's the same
|
||||
//! as from CreateDefaultInstance(), except of types, such as pointers, that need to do minimal (de)serialization
|
||||
//! to initialize an object.
|
||||
virtual AZStd::shared_ptr<T> CreateDefaultConstructedInstance() { return CreateDefaultInstance(); }
|
||||
//! Create an instance of the target type with some values set and some kept on defaults.
|
||||
//! If the target type doesn't support partial specialization this can be ignored and
|
||||
//! tests for partial support will be skipped.
|
||||
@@ -316,10 +321,10 @@ namespace JsonSerializationTests
|
||||
ASSERT_FALSE(this->m_jsonDocument->HasParseError());
|
||||
|
||||
auto serializer = this->m_description.CreateSerializer();
|
||||
auto instance = this->m_description.CreateDefaultInstance();
|
||||
auto instance = this->m_description.CreateDefaultConstructedInstance();
|
||||
auto original = this->m_description.CreateDefaultInstance();
|
||||
|
||||
ResultCode result = serializer->Load(instance.get(), azrtti_typeid(*original),
|
||||
ResultCode result = serializer->Load(instance.get(), azrtti_typeid(*instance),
|
||||
*this->m_jsonDocument, *this->m_jsonDeserializationContext);
|
||||
|
||||
if (this->m_features.m_mandatoryFields.empty())
|
||||
@@ -339,6 +344,42 @@ namespace JsonSerializationTests
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(JsonSerializerConformityTests, Load_DeserializeEmptyObjectThroughMainLoad_SucceedsAndObjectMatchesDefaults)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
if (this->m_features.SupportsJsonType(rapidjson::kObjectType))
|
||||
{
|
||||
this->m_jsonDocument->Parse("{}");
|
||||
ASSERT_FALSE(this->m_jsonDocument->HasParseError());
|
||||
|
||||
auto serializer = this->m_description.CreateSerializer();
|
||||
auto instance = this->m_description.CreateDefaultConstructedInstance();
|
||||
auto original = this->m_description.CreateDefaultInstance();
|
||||
|
||||
AZ::JsonDeserializerSettings settings;
|
||||
settings.m_serializeContext = this->m_jsonDeserializationContext->GetSerializeContext();
|
||||
settings.m_registrationContext = this->m_jsonDeserializationContext->GetRegistrationContext();
|
||||
ResultCode result = AZ::JsonSerialization::Load(
|
||||
instance.get(), azrtti_typeid(*instance), *this->m_jsonDocument, settings);
|
||||
|
||||
if (this->m_features.m_mandatoryFields.empty())
|
||||
{
|
||||
EXPECT_EQ(Outcomes::DefaultsUsed, result.GetOutcome());
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_EQ(Outcomes::Unsupported, result.GetOutcome());
|
||||
bool validProcessing =
|
||||
result.GetProcessing() == Processing::Altered ||
|
||||
result.GetProcessing() == Processing::PartialAlter;
|
||||
EXPECT_TRUE(validProcessing);
|
||||
}
|
||||
EXPECT_TRUE(this->m_description.AreEqual(*original, *instance));
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(JsonSerializerConformityTests, Load_DeserializeEmptyArray_SucceedsAndObjectMatchesDefaults)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
@@ -349,7 +390,7 @@ namespace JsonSerializationTests
|
||||
ASSERT_FALSE(this->m_jsonDocument->HasParseError());
|
||||
|
||||
auto serializer = this->m_description.CreateSerializer();
|
||||
auto instance = this->m_description.CreateDefaultInstance();
|
||||
auto instance = this->m_description.CreateDefaultConstructedInstance();
|
||||
auto original = this->m_description.CreateDefaultInstance();
|
||||
|
||||
this->m_deserializationSettings->m_clearContainers = false;
|
||||
@@ -384,7 +425,7 @@ namespace JsonSerializationTests
|
||||
ASSERT_FALSE(this->m_jsonDocument->HasParseError());
|
||||
|
||||
auto serializer = this->m_description.CreateSerializer();
|
||||
auto instance = this->m_description.CreateDefaultInstance();
|
||||
auto instance = this->m_description.CreateDefaultConstructedInstance();
|
||||
auto original = this->m_description.CreateDefaultInstance();
|
||||
|
||||
this->m_deserializationSettings->m_clearContainers = true;
|
||||
@@ -488,7 +529,7 @@ namespace JsonSerializationTests
|
||||
ASSERT_FALSE(this->m_jsonDocument->HasParseError());
|
||||
|
||||
auto serializer = this->m_description.CreateSerializer();
|
||||
auto instance = this->m_description.CreateDefaultInstance();
|
||||
auto instance = this->m_description.CreateDefaultConstructedInstance();
|
||||
auto compare = this->m_description.CreateFullySetInstance();
|
||||
|
||||
ResultCode result = serializer->Load(instance.get(), azrtti_typeid(*instance),
|
||||
@@ -499,6 +540,28 @@ namespace JsonSerializationTests
|
||||
EXPECT_TRUE(this->m_description.AreEqual(*instance, *compare));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(JsonSerializerConformityTests, Load_DeserializeFullySetInstanceThroughMainLoad_SucceedsAndObjectMatchesFullySetInstance)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
AZStd::string_view json = this->m_description.GetJsonFor_Load_DeserializeFullySetInstance();
|
||||
this->m_jsonDocument->Parse(json.data());
|
||||
ASSERT_FALSE(this->m_jsonDocument->HasParseError());
|
||||
|
||||
auto serializer = this->m_description.CreateSerializer();
|
||||
auto instance = this->m_description.CreateDefaultConstructedInstance();
|
||||
auto compare = this->m_description.CreateFullySetInstance();
|
||||
|
||||
AZ::JsonDeserializerSettings settings;
|
||||
settings.m_serializeContext = this->m_jsonDeserializationContext->GetSerializeContext();
|
||||
settings.m_registrationContext = this->m_jsonDeserializationContext->GetRegistrationContext();
|
||||
ResultCode result = AZ::JsonSerialization::Load(instance.get(), azrtti_typeid(*instance), *this->m_jsonDocument, settings);
|
||||
|
||||
EXPECT_EQ(Outcomes::Success, result.GetOutcome());
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
EXPECT_TRUE(this->m_description.AreEqual(*instance, *compare));
|
||||
}
|
||||
|
||||
TYPED_TEST_P(JsonSerializerConformityTests, Load_DeserializeWithMissingMandatoryField_LoadFailedAndUnsupportedReported)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
@@ -518,7 +581,7 @@ namespace JsonSerializationTests
|
||||
ASSERT_NE(this->m_jsonDocument->MemberEnd(), memberToErase);
|
||||
this->m_jsonDocument->RemoveMember(memberToErase);
|
||||
|
||||
auto instance = this->m_description.CreateDefaultInstance();
|
||||
auto instance = this->m_description.CreateDefaultConstructedInstance();
|
||||
|
||||
ResultCode result = serializer->Load(instance.get(), azrtti_typeid(*instance),
|
||||
*this->m_jsonDocument, *this->m_jsonDeserializationContext);
|
||||
@@ -546,7 +609,7 @@ namespace JsonSerializationTests
|
||||
ASSERT_FALSE(this->m_jsonDocument->HasParseError());
|
||||
|
||||
auto serializer = this->m_description.CreateSerializer();
|
||||
auto instance = this->m_description.CreateDefaultInstance();
|
||||
auto instance = this->m_description.CreateDefaultConstructedInstance();
|
||||
auto compare = this->m_description.CreatePartialDefaultInstance();
|
||||
ASSERT_NE(nullptr, compare);
|
||||
|
||||
@@ -567,7 +630,7 @@ namespace JsonSerializationTests
|
||||
ASSERT_FALSE(this->m_jsonDocument->HasParseError());
|
||||
|
||||
auto serializer = this->m_description.CreateSerializer();
|
||||
auto instance = this->m_description.CreateDefaultInstance();
|
||||
auto instance = this->m_description.CreateDefaultConstructedInstance();
|
||||
|
||||
AZ::ScopedContextReporter reporter(*this->m_jsonDeserializationContext,
|
||||
[](AZStd::string_view message, ResultCode result, AZStd::string_view path) -> ResultCode
|
||||
@@ -604,7 +667,7 @@ namespace JsonSerializationTests
|
||||
}
|
||||
|
||||
auto serializer = this->m_description.CreateSerializer();
|
||||
auto instance = this->m_description.CreateDefaultInstance();
|
||||
auto instance = this->m_description.CreateDefaultConstructedInstance();
|
||||
auto compare = this->m_description.CreateFullySetInstance();
|
||||
|
||||
ResultCode result = serializer->Load(instance.get(), azrtti_typeid(*instance),
|
||||
@@ -635,7 +698,7 @@ namespace JsonSerializationTests
|
||||
}
|
||||
|
||||
auto serializer = this->m_description.CreateSerializer();
|
||||
auto instance = this->m_description.CreateDefaultInstance();
|
||||
auto instance = this->m_description.CreateDefaultConstructedInstance();
|
||||
|
||||
ResultCode result = serializer->Load(instance.get(), azrtti_typeid(*instance),
|
||||
*this->m_jsonDocument, *this->m_jsonDeserializationContext);
|
||||
@@ -693,6 +756,36 @@ namespace JsonSerializationTests
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(JsonSerializerConformityTests, Store_SerializeDefaultInstanceThroughMainStore_EmptyJsonReturned)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
auto serializer = this->m_description.CreateSerializer();
|
||||
auto instance = this->m_description.CreateDefaultInstance();
|
||||
rapidjson::Value convertedValue = this->CreateExplicitDefault();
|
||||
|
||||
AZ::JsonSerializerSettings settings;
|
||||
settings.m_serializeContext = this->m_jsonDeserializationContext->GetSerializeContext();
|
||||
settings.m_registrationContext = this->m_jsonDeserializationContext->GetRegistrationContext();
|
||||
ResultCode result = AZ::JsonSerialization::Store(
|
||||
convertedValue, this->m_jsonDocument->GetAllocator(), instance.get(), instance.get(), azrtti_typeid(*instance), settings);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
if (convertedValue.IsObject() && !this->m_features.m_mandatoryFields.empty())
|
||||
{
|
||||
ASSERT_EQ(convertedValue.MemberCount(), this->m_features.m_mandatoryFields.size());
|
||||
for (const AZStd::string& mandatoryField : this->m_features.m_mandatoryFields)
|
||||
{
|
||||
EXPECT_NE(convertedValue.MemberEnd(), convertedValue.FindMember(mandatoryField.c_str()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_EQ(Outcomes::DefaultsUsed, result.GetOutcome());
|
||||
this->Expect_ExplicitDefault(convertedValue);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(JsonSerializerConformityTests, Store_SerializeWithDefaultsKept_FullyWrittenJson)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
@@ -924,6 +1017,20 @@ namespace JsonSerializationTests
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST_P(JsonSerializerConformityTests, GetOperationsFlags_ManualDefaultSetIfNeeded_ManualDefaultOperationSetIfMandatoryFieldsAreDeclared)
|
||||
{
|
||||
if (this->m_features.SupportsJsonType(rapidjson::kObjectType))
|
||||
{
|
||||
if (!this->m_features.m_mandatoryFields.empty())
|
||||
{
|
||||
auto serializer = this->m_description.CreateSerializer();
|
||||
bool manuallyHandlesDefaults = (serializer->GetOperationsFlags() & AZ::BaseJsonSerializer::OperationFlags::ManualDefault) ==
|
||||
AZ::BaseJsonSerializer::OperationFlags::ManualDefault;
|
||||
EXPECT_TRUE(manuallyHandlesDefaults);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_TYPED_TEST_CASE_P(JsonSerializerConformityTests,
|
||||
Registration_SerializerIsRegisteredWithContext_SerializerFound,
|
||||
|
||||
@@ -934,14 +1041,16 @@ namespace JsonSerializationTests
|
||||
Load_InvalidTypeOfArrayType_ReturnsUnsupported,
|
||||
Load_InvalidTypeOfStringType_ReturnsUnsupported,
|
||||
Load_InvalidTypeOfNumberType_ReturnsUnsupported,
|
||||
|
||||
|
||||
Load_DeserializeUnreflectedType_ReturnsUnsupported,
|
||||
Load_DeserializeEmptyObject_SucceedsAndObjectMatchesDefaults,
|
||||
Load_DeserializeEmptyObjectThroughMainLoad_SucceedsAndObjectMatchesDefaults,
|
||||
Load_DeserializeEmptyArray_SucceedsAndObjectMatchesDefaults,
|
||||
Load_DeserializeEmptyArrayWithClearEnabled_SucceedsAndObjectMatchesDefaults,
|
||||
Load_DeserializeEmptyArrayWithClearedTarget_SucceedsAndObjectMatchesDefaults,
|
||||
Load_InterruptClearingTarget_ContainerIsNotCleared,
|
||||
Load_DeserializeFullySetInstance_SucceedsAndObjectMatchesFullySetInstance,
|
||||
Load_DeserializeFullySetInstanceThroughMainLoad_SucceedsAndObjectMatchesFullySetInstance,
|
||||
Load_DeserializePartialInstance_SucceedsAndObjectMatchesParialInstance,
|
||||
Load_DeserializeWithMissingMandatoryField_LoadFailedAndUnsupportedReported,
|
||||
Load_InsertAdditionalData_SucceedsAndObjectMatchesFullySetInstance,
|
||||
@@ -950,6 +1059,7 @@ namespace JsonSerializationTests
|
||||
|
||||
Store_SerializeUnreflectedType_ReturnsUnsupported,
|
||||
Store_SerializeDefaultInstance_EmptyJsonReturned,
|
||||
Store_SerializeDefaultInstanceThroughMainStore_EmptyJsonReturned,
|
||||
Store_SerializeWithDefaultsKept_FullyWrittenJson,
|
||||
Store_SerializeFullySetInstance_StoredSuccessfullyAndJsonMatches,
|
||||
Store_SerializeWithoutDefault_StoredSuccessfullyAndJsonMatches,
|
||||
@@ -957,10 +1067,12 @@ namespace JsonSerializationTests
|
||||
Store_SerializePartialInstance_StoredSuccessfullyAndJsonMatches,
|
||||
Store_SerializeEmptyArray_StoredSuccessfullyAndJsonMatches,
|
||||
Store_HaltedThroughCallback_StoreFailsAndHaltReported,
|
||||
|
||||
|
||||
StoreLoad_RoundTripWithPartialDefault_IdenticalInstances,
|
||||
StoreLoad_RoundTripWithFullSet_IdenticalInstances,
|
||||
StoreLoad_RoundTripWithDefaultsKept_IdenticalInstances);
|
||||
StoreLoad_RoundTripWithDefaultsKept_IdenticalInstances,
|
||||
|
||||
GetOperationsFlags_ManualDefaultSetIfNeeded_ManualDefaultOperationSetIfMandatoryFieldsAreDeclared);
|
||||
} // namespace JsonSerializationTests
|
||||
|
||||
namespace AZ
|
||||
|
||||
@@ -0,0 +1,562 @@
|
||||
/*
|
||||
* 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/Math/MathMatrixSerializer.h>
|
||||
#include <AzCore/Math/Matrix3x3.h>
|
||||
#include <AzCore/Math/Matrix3x4.h>
|
||||
#include <AzCore/Math/Matrix4x4.h>
|
||||
#include <AzCore/Math/Random.h>
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
#include <AzCore/Serialization/Json/DoubleSerializer.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
#include <Tests/Serialization/Json/BaseJsonSerializerFixture.h>
|
||||
#include <Tests/Serialization/Json/JsonSerializerConformityTests.h>
|
||||
|
||||
namespace JsonSerializationTests
|
||||
{
|
||||
namespace DataHelper
|
||||
{
|
||||
// Build Matrix
|
||||
|
||||
template <typename MatrixType>
|
||||
MatrixType BuildMatrixRotationWithSale(const AZ::Vector3& angles, float scale)
|
||||
{
|
||||
// start a matrix with angle degrees
|
||||
const AZ::Vector3 eulerRadians = AZ::Vector3DegToRad(angles);
|
||||
const auto rotX = MatrixType::CreateRotationX(eulerRadians.GetX());
|
||||
const auto rotY = MatrixType::CreateRotationY(eulerRadians.GetY());
|
||||
const auto rotZ = MatrixType::CreateRotationZ(eulerRadians.GetZ());
|
||||
auto matrix = rotX * rotY * rotZ;
|
||||
|
||||
// apply a scale
|
||||
matrix.MultiplyByScale(AZ::Vector3{ scale });
|
||||
return matrix;
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
MatrixType BuildMatrix(const AZ::Vector3& angles, float scale, const AZ::Vector3& translation)
|
||||
{
|
||||
auto matrix = BuildMatrixRotationWithSale<MatrixType>(angles, scale);
|
||||
matrix.SetTranslation(translation);
|
||||
return matrix;
|
||||
}
|
||||
|
||||
template <>
|
||||
AZ::Matrix3x3 BuildMatrix(const AZ::Vector3& angles, float scale, const AZ::Vector3&)
|
||||
{
|
||||
return BuildMatrixRotationWithSale<AZ::Matrix3x3>(angles, scale);
|
||||
}
|
||||
|
||||
// Arbitrary Matrix
|
||||
|
||||
template <typename MatrixType>
|
||||
MatrixType CreateArbitraryMatrixRotationAndSale(AZ::SimpleLcgRandom& random)
|
||||
{
|
||||
// start a matrix with arbitrary degrees
|
||||
float roll = random.GetRandomFloat() * 360.0f;
|
||||
float pitch = random.GetRandomFloat() * 360.0f;
|
||||
float yaw = random.GetRandomFloat() * 360.0f;
|
||||
const AZ::Vector3 eulerRadians = AZ::Vector3DegToRad(AZ::Vector3{ roll, pitch, yaw });
|
||||
const auto rotX = MatrixType::CreateRotationX(eulerRadians.GetX());
|
||||
const auto rotY = MatrixType::CreateRotationY(eulerRadians.GetY());
|
||||
const auto rotZ = MatrixType::CreateRotationZ(eulerRadians.GetZ());
|
||||
auto matrix = rotX * rotY * rotZ;
|
||||
|
||||
// apply a scale
|
||||
matrix.MultiplyByScale(AZ::Vector3{ random.GetRandomFloat() });
|
||||
return matrix;
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
void AssignArbitrarySetTranslation(MatrixType& matrix, AZ::SimpleLcgRandom& random)
|
||||
{
|
||||
float x = random.GetRandomFloat() * 10000.0f;
|
||||
float y = random.GetRandomFloat() * 10000.0f;
|
||||
float z = random.GetRandomFloat() * 10000.0f;
|
||||
matrix.SetTranslation(AZ::Vector3{ x, y, z });
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
MatrixType CreateArbitraryMatrix(size_t seed);
|
||||
|
||||
template <>
|
||||
AZ::Matrix3x3 CreateArbitraryMatrix(size_t seed)
|
||||
{
|
||||
AZ::SimpleLcgRandom random(seed);
|
||||
return CreateArbitraryMatrixRotationAndSale<AZ::Matrix3x3>(random);
|
||||
}
|
||||
|
||||
template <>
|
||||
AZ::Matrix3x4 CreateArbitraryMatrix(size_t seed)
|
||||
{
|
||||
AZ::SimpleLcgRandom random(seed);
|
||||
auto matrix = CreateArbitraryMatrixRotationAndSale<AZ::Matrix3x4>(random);
|
||||
AssignArbitrarySetTranslation<AZ::Matrix3x4>(matrix, random);
|
||||
return matrix;
|
||||
}
|
||||
|
||||
template <>
|
||||
AZ::Matrix4x4 CreateArbitraryMatrix(size_t seed)
|
||||
{
|
||||
AZ::SimpleLcgRandom random(seed);
|
||||
auto matrix = CreateArbitraryMatrixRotationAndSale<AZ::Matrix4x4>(random);
|
||||
AssignArbitrarySetTranslation<AZ::Matrix4x4>(matrix, random);
|
||||
return matrix;
|
||||
}
|
||||
|
||||
// CreateQuaternion
|
||||
|
||||
template<typename MatrixType>
|
||||
AZ::Quaternion CreateQuaternion(const MatrixType& matrix);
|
||||
|
||||
template<>
|
||||
AZ::Quaternion CreateQuaternion<AZ::Matrix3x3>(const AZ::Matrix3x3& matrix)
|
||||
{
|
||||
return AZ::Quaternion::CreateFromMatrix3x3(matrix);
|
||||
}
|
||||
|
||||
template<>
|
||||
AZ::Quaternion CreateQuaternion<AZ::Matrix3x4>(const AZ::Matrix3x4& matrix)
|
||||
{
|
||||
return AZ::Quaternion::CreateFromMatrix3x4(matrix);
|
||||
}
|
||||
|
||||
template<>
|
||||
AZ::Quaternion CreateQuaternion<AZ::Matrix4x4>(const AZ::Matrix4x4& matrix)
|
||||
{
|
||||
return AZ::Quaternion::CreateFromMatrix4x4(matrix);
|
||||
}
|
||||
|
||||
template<typename MatrixType>
|
||||
void AddRotation(rapidjson::Value& value, const MatrixType& matrix, rapidjson::Document::AllocatorType& allocator)
|
||||
{
|
||||
AZ::Quaternion rotation = CreateQuaternion<MatrixType>(matrix);
|
||||
const auto degrees = rotation.GetEulerDegrees();
|
||||
value.AddMember("yaw", degrees.GetX(), allocator);
|
||||
value.AddMember("pitch", degrees.GetY(), allocator);
|
||||
value.AddMember("roll", degrees.GetZ(), allocator);
|
||||
}
|
||||
|
||||
void AddScale(rapidjson::Value& value, float scale, rapidjson::Document::AllocatorType& allocator)
|
||||
{
|
||||
value.AddMember("scale", scale, allocator);
|
||||
}
|
||||
|
||||
void AddTranslation(rapidjson::Value& value, const AZ::Vector3& translation, rapidjson::Document::AllocatorType& allocator)
|
||||
{
|
||||
value.AddMember("x", translation.GetX(), allocator);
|
||||
value.AddMember("y", translation.GetY(), allocator);
|
||||
value.AddMember("z", translation.GetZ(), allocator);
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
void AddData(rapidjson::Value& value, const MatrixType& matrix, rapidjson::Document::AllocatorType& allocator);
|
||||
|
||||
template <>
|
||||
void AddData(rapidjson::Value& value, const AZ::Matrix3x3& matrix, rapidjson::Document::AllocatorType& allocator)
|
||||
{
|
||||
AddScale(value, matrix.RetrieveScale().GetX(), allocator);
|
||||
AddRotation(value, matrix, allocator);
|
||||
}
|
||||
|
||||
template <>
|
||||
void AddData(rapidjson::Value& value, const AZ::Matrix3x4& matrix, rapidjson::Document::AllocatorType& allocator)
|
||||
{
|
||||
AddScale(value, matrix.RetrieveScale().GetX(), allocator);
|
||||
AddTranslation(value, matrix.GetTranslation(), allocator);
|
||||
AddRotation(value, matrix, allocator);
|
||||
}
|
||||
|
||||
template <>
|
||||
void AddData(rapidjson::Value& value, const AZ::Matrix4x4& matrix, rapidjson::Document::AllocatorType& allocator)
|
||||
{
|
||||
AddScale(value, matrix.RetrieveScale().GetX(), allocator);
|
||||
AddTranslation(value, matrix.GetTranslation(), allocator);
|
||||
AddRotation(value, matrix, allocator);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename MatrixType, size_t RowCount, size_t ColumnCount, typename Serializer>
|
||||
class MathMatrixSerializerTestDescription :
|
||||
public JsonSerializerConformityTestDescriptor<MatrixType>
|
||||
{
|
||||
public:
|
||||
AZStd::shared_ptr<AZ::BaseJsonSerializer> CreateSerializer() override
|
||||
{
|
||||
return AZStd::make_shared<Serializer>();
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<MatrixType> CreateDefaultInstance() override
|
||||
{
|
||||
return AZStd::make_shared<MatrixType>(MatrixType::CreateIdentity());
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<MatrixType> CreateFullySetInstance() override
|
||||
{
|
||||
auto angles = AZ::Vector3 { 0.0f, 0.0f, 0.0f };
|
||||
auto scale = 10.0f;
|
||||
auto translation = AZ::Vector3{ 10.0f, 20.0f, 30.0f };
|
||||
auto matrix = DataHelper::BuildMatrix<MatrixType>(angles, scale, translation);
|
||||
return AZStd::make_shared<MatrixType>(matrix);
|
||||
}
|
||||
|
||||
AZStd::string_view GetJsonForFullySetInstance() override
|
||||
{
|
||||
if constexpr (RowCount * ColumnCount == 9)
|
||||
{
|
||||
return "{\"roll\":0.0,\"pitch\":0.0,\"yaw\":0.0,\"scale\":10.0}";
|
||||
}
|
||||
else if constexpr (RowCount * ColumnCount == 12)
|
||||
{
|
||||
return "{\"roll\":0.0,\"pitch\":0.0,\"yaw\":0.0,\"scale\":10.0,\"x\":10.0,\"y\":20.0,\"z\":30.0}";
|
||||
}
|
||||
else if constexpr (RowCount * ColumnCount == 16)
|
||||
{
|
||||
return "{\"roll\":0.0,\"pitch\":0.0,\"yaw\":0.0,\"scale\":10.0,\"x\":10.0,\"y\":20.0,\"z\":30.0}";
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert((RowCount >= 3 && RowCount <= 4) && (ColumnCount >= 3 && ColumnCount <= 4),
|
||||
"Only matrix 3x3, 3x4 or 4x4 are supported by this test.");
|
||||
}
|
||||
return "{}";
|
||||
}
|
||||
|
||||
void ConfigureFeatures(JsonSerializerConformityTestDescriptorFeatures& features) override
|
||||
{
|
||||
features.EnableJsonType(rapidjson::kArrayType);
|
||||
features.EnableJsonType(rapidjson::kObjectType);
|
||||
features.m_fixedSizeArray = true;
|
||||
features.m_supportsPartialInitialization = false;
|
||||
features.m_supportsInjection = false;
|
||||
}
|
||||
|
||||
bool AreEqual(const MatrixType& lhs, const MatrixType& rhs) override
|
||||
{
|
||||
for (int r = 0; r < RowCount; ++r)
|
||||
{
|
||||
for (int c = 0; c < ColumnCount; ++c)
|
||||
{
|
||||
if (!AZ::IsClose(lhs.GetElement(r, c), rhs.GetElement(r, c), AZ::Constants::Tolerance))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
using MathMatrixSerializerConformityTestTypes = ::testing::Types<
|
||||
MathMatrixSerializerTestDescription<AZ::Matrix3x3, 3, 3, AZ::JsonMatrix3x3Serializer>,
|
||||
MathMatrixSerializerTestDescription<AZ::Matrix3x4, 3, 4, AZ::JsonMatrix3x4Serializer>,
|
||||
MathMatrixSerializerTestDescription<AZ::Matrix4x4, 4, 4, AZ::JsonMatrix4x4Serializer>
|
||||
>;
|
||||
INSTANTIATE_TYPED_TEST_CASE_P(JsonMathMatrixSerializer, JsonSerializerConformityTests, MathMatrixSerializerConformityTestTypes);
|
||||
|
||||
template<typename T>
|
||||
class JsonMathMatrixSerializerTests
|
||||
: public BaseJsonSerializerFixture
|
||||
{
|
||||
public:
|
||||
using Descriptor = T;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
BaseJsonSerializerFixture::SetUp();
|
||||
m_serializer = AZStd::make_unique<typename T::Serializer>();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_serializer.reset();
|
||||
BaseJsonSerializerFixture::TearDown();
|
||||
}
|
||||
|
||||
protected:
|
||||
AZStd::unique_ptr<typename T::Serializer> m_serializer;
|
||||
};
|
||||
|
||||
struct Matrix3x3Descriptor
|
||||
{
|
||||
using MatrixType = AZ::Matrix3x3;
|
||||
using Serializer = AZ::JsonMatrix3x3Serializer;
|
||||
constexpr static size_t RowCount = 3;
|
||||
constexpr static size_t ColumnCount = 3;
|
||||
constexpr static size_t ElementCount = RowCount * ColumnCount;
|
||||
constexpr static bool HasTranslation = false;
|
||||
};
|
||||
|
||||
struct Matrix3x4Descriptor
|
||||
{
|
||||
using MatrixType = AZ::Matrix3x4;
|
||||
using Serializer = AZ::JsonMatrix3x4Serializer;
|
||||
constexpr static size_t RowCount = 3;
|
||||
constexpr static size_t ColumnCount = 4;
|
||||
constexpr static size_t ElementCount = RowCount * ColumnCount;
|
||||
constexpr static bool HasTranslation = true;
|
||||
};
|
||||
|
||||
struct Matrix4x4Descriptor
|
||||
{
|
||||
using MatrixType = AZ::Matrix4x4;
|
||||
using Serializer = AZ::JsonMatrix4x4Serializer;
|
||||
constexpr static size_t RowCount = 4;
|
||||
constexpr static size_t ColumnCount = 4;
|
||||
constexpr static size_t ElementCount = RowCount * ColumnCount;
|
||||
constexpr static bool HasTranslation = true;
|
||||
};
|
||||
|
||||
using JsonMathMatrixSerializerTypes = ::testing::Types <
|
||||
Matrix3x3Descriptor, Matrix3x4Descriptor, Matrix4x4Descriptor>;
|
||||
TYPED_TEST_CASE(JsonMathMatrixSerializerTests, JsonMathMatrixSerializerTypes);
|
||||
|
||||
// Load array tests
|
||||
|
||||
TYPED_TEST(JsonMathMatrixSerializerTests, Load_Array_ReturnsConvertAndLoadsMatrix)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
rapidjson::Value& arrayValue = this->m_jsonDocument->SetArray();
|
||||
for (size_t i = 0; i < JsonMathMatrixSerializerTests<TypeParam>::Descriptor::ElementCount; ++i)
|
||||
{
|
||||
arrayValue.PushBack(static_cast<float>(i + 1), this->m_jsonDocument->GetAllocator());
|
||||
}
|
||||
|
||||
auto output = JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType::CreateZero();
|
||||
ResultCode result = this->m_serializer->Load(
|
||||
&output,
|
||||
azrtti_typeid<typename JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType>(),
|
||||
*this->m_jsonDocument,
|
||||
*this->m_jsonDeserializationContext);
|
||||
ASSERT_EQ(Outcomes::Success, result.GetOutcome());
|
||||
|
||||
for (int r = 0; r < JsonMathMatrixSerializerTests<TypeParam>::Descriptor::RowCount; ++r)
|
||||
{
|
||||
for (int c = 0; c < JsonMathMatrixSerializerTests<TypeParam>::Descriptor::ColumnCount; ++c)
|
||||
{
|
||||
auto testValue = static_cast<float>((r * JsonMathMatrixSerializerTests<TypeParam>::Descriptor::ColumnCount) + c + 1);
|
||||
EXPECT_FLOAT_EQ(testValue, output.GetElement(r, c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(JsonMathMatrixSerializerTests, Load_InvalidEntries_ReturnsUnsupportedAndLeavesMatrixUntouched)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
rapidjson::Value& arrayValue = this->m_jsonDocument->SetArray();
|
||||
for (size_t i = 0; i < JsonMathMatrixSerializerTests<TypeParam>::Descriptor::ElementCount; ++i)
|
||||
{
|
||||
if (i == 1)
|
||||
{
|
||||
arrayValue.PushBack(rapidjson::StringRef("Invalid"), this->m_jsonDocument->GetAllocator());
|
||||
}
|
||||
else
|
||||
{
|
||||
arrayValue.PushBack(static_cast<float>(i + 1), this->m_jsonDocument->GetAllocator());
|
||||
}
|
||||
}
|
||||
|
||||
auto output = JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType::CreateZero();
|
||||
ResultCode result = this->m_serializer->Load(
|
||||
&output,
|
||||
azrtti_typeid<typename JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType>(),
|
||||
*this->m_jsonDocument,
|
||||
*this->m_jsonDeserializationContext);
|
||||
EXPECT_EQ(Outcomes::Unsupported, result.GetOutcome());
|
||||
|
||||
for (int r = 0; r < JsonMathMatrixSerializerTests<TypeParam>::Descriptor::RowCount; ++r)
|
||||
{
|
||||
for (int c = 0; c < JsonMathMatrixSerializerTests<TypeParam>::Descriptor::ColumnCount; ++c)
|
||||
{
|
||||
EXPECT_FLOAT_EQ(0.0f, output.GetElement(r, c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(JsonMathMatrixSerializerTests, Load_FloatSerializerMissingForArray_ReturnsCatastrophic)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
this->m_jsonRegistrationContext->EnableRemoveReflection();
|
||||
this->m_jsonRegistrationContext->template Serializer<AZ::JsonFloatSerializer>()->template HandlesType<float>();
|
||||
this->m_jsonRegistrationContext->DisableRemoveReflection();
|
||||
|
||||
rapidjson::Value& arrayValue = this->m_jsonDocument->SetArray();
|
||||
for (size_t i = 0; i < JsonMathMatrixSerializerTests<TypeParam>::Descriptor::ElementCount + 1; ++i)
|
||||
{
|
||||
arrayValue.PushBack(static_cast<float>(i + 1), this->m_jsonDocument->GetAllocator());
|
||||
}
|
||||
|
||||
typename JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType output;
|
||||
ResultCode result = this->m_serializer->Load(
|
||||
&output,
|
||||
azrtti_typeid<typename JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType>(),
|
||||
*this->m_jsonDocument,
|
||||
*this->m_jsonDeserializationContext);
|
||||
EXPECT_EQ(Outcomes::Catastrophic, result.GetOutcome());
|
||||
|
||||
this->m_jsonRegistrationContext->template Serializer<AZ::JsonFloatSerializer>()->template HandlesType<float>();
|
||||
}
|
||||
|
||||
// Load object tests
|
||||
TYPED_TEST(JsonMathMatrixSerializerTests, Load_ValidObjectLowerCase_ReturnsSuccessAndLoadsMatrix)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
rapidjson::Value& objectValue = this->m_jsonDocument->SetObject();
|
||||
auto input = JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType::CreateIdentity();
|
||||
DataHelper::AddData(objectValue, input, this->m_jsonDocument->GetAllocator());
|
||||
|
||||
auto output = JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType::CreateZero();
|
||||
ResultCode result = this->m_serializer->Load(
|
||||
&output,
|
||||
azrtti_typeid<typename JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType>(),
|
||||
*this->m_jsonDocument,
|
||||
*this->m_jsonDeserializationContext);
|
||||
ASSERT_EQ(Outcomes::DefaultsUsed, result.GetOutcome());
|
||||
EXPECT_TRUE(input == output);
|
||||
}
|
||||
|
||||
TYPED_TEST(JsonMathMatrixSerializerTests, Load_ValidObjectWithExtraFields_ReturnsPartialConvertAndLoadsMatrix)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
rapidjson::Value& objectValue = this->m_jsonDocument->SetObject();
|
||||
auto input = JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType::CreateIdentity();
|
||||
DataHelper::AddScale(objectValue, input.RetrieveScale().GetX(), this->m_jsonDocument->GetAllocator());
|
||||
DataHelper::AddRotation(objectValue, input, this->m_jsonDocument->GetAllocator());
|
||||
objectValue.AddMember(rapidjson::StringRef("extra"), "no value", this->m_jsonDocument->GetAllocator());
|
||||
|
||||
auto output = JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType::CreateZero();
|
||||
ResultCode result = this->m_serializer->Load(
|
||||
&output,
|
||||
azrtti_typeid<typename JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType>(),
|
||||
*this->m_jsonDocument,
|
||||
*this->m_jsonDeserializationContext);
|
||||
ASSERT_EQ(Outcomes::DefaultsUsed, result.GetOutcome());
|
||||
EXPECT_TRUE(input == output);
|
||||
}
|
||||
|
||||
TYPED_TEST(JsonMathMatrixSerializerTests, SaveLoad_Identity_LoadsDefaultMatrixWithIdentity)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
auto defaultValue = JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType::CreateIdentity();
|
||||
|
||||
rapidjson::Value& objectInput = this->m_jsonDocument->SetObject();
|
||||
this->m_serializer->Store(
|
||||
objectInput,
|
||||
&defaultValue,
|
||||
&defaultValue,
|
||||
azrtti_typeid<typename JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType>(),
|
||||
*this->m_jsonSerializationContext);
|
||||
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||
objectInput.Accept(writer);
|
||||
|
||||
auto output = defaultValue;
|
||||
ResultCode result = this->m_serializer->Load(
|
||||
&output,
|
||||
azrtti_typeid<typename JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType>(),
|
||||
*this->m_jsonDocument,
|
||||
*this->m_jsonDeserializationContext);
|
||||
|
||||
EXPECT_TRUE(defaultValue == output);
|
||||
}
|
||||
|
||||
TYPED_TEST(JsonMathMatrixSerializerTests, LoadSave_Zero_SavesAndLoadsIdentityMatrix)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
|
||||
auto defaultValue = JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType::CreateIdentity();
|
||||
auto input = JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType::CreateZero();
|
||||
|
||||
rapidjson::Value& objectInput = this->m_jsonDocument->SetObject();
|
||||
this->m_serializer->Store(
|
||||
objectInput,
|
||||
&input,
|
||||
&defaultValue,
|
||||
azrtti_typeid<typename JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType>(),
|
||||
*this->m_jsonSerializationContext);
|
||||
|
||||
auto output = defaultValue;
|
||||
ResultCode result = this->m_serializer->Load(
|
||||
&output,
|
||||
azrtti_typeid<typename JsonMathMatrixSerializerTests<TypeParam>::Descriptor::MatrixType>(),
|
||||
*this->m_jsonDocument,
|
||||
*this->m_jsonDeserializationContext);
|
||||
|
||||
ASSERT_EQ(Outcomes::Unsupported, result.GetOutcome());
|
||||
EXPECT_TRUE(defaultValue == output);
|
||||
}
|
||||
|
||||
TYPED_TEST(JsonMathMatrixSerializerTests, Load_InvalidFields_ReturnsUnsupportedAndLeavesMatrixUntouched)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
using Descriptor = typename JsonMathMatrixSerializerTests<TypeParam>::Descriptor;
|
||||
|
||||
const auto defaultValue = Descriptor::MatrixType::CreateIdentity();
|
||||
rapidjson::Value& objectValue = this->m_jsonDocument->SetObject();
|
||||
auto input = Descriptor::MatrixType::CreateIdentity();
|
||||
DataHelper::AddData(objectValue, input, this->m_jsonDocument->GetAllocator());
|
||||
objectValue["yaw"] = "Invalid";
|
||||
|
||||
auto output = Descriptor::MatrixType::CreateZero();
|
||||
ResultCode result = this->m_serializer->Load(
|
||||
&output,
|
||||
azrtti_typeid<typename Descriptor::MatrixType>(),
|
||||
*this->m_jsonDocument,
|
||||
*this->m_jsonDeserializationContext);
|
||||
ASSERT_EQ(Outcomes::Unsupported, result.GetOutcome());
|
||||
EXPECT_TRUE(input == output);
|
||||
}
|
||||
|
||||
TYPED_TEST(JsonMathMatrixSerializerTests, LoadSave_Arbitrary_SavesAndLoadsArbitraryMatrix)
|
||||
{
|
||||
using namespace AZ::JsonSerializationResult;
|
||||
using Descriptor = typename JsonMathMatrixSerializerTests<TypeParam>::Descriptor;
|
||||
|
||||
auto defaultValue = Descriptor::MatrixType::CreateIdentity();
|
||||
size_t elementCount = Descriptor::RowCount * Descriptor::ColumnCount;
|
||||
auto input = DataHelper::CreateArbitraryMatrix<typename Descriptor::MatrixType>(elementCount);
|
||||
|
||||
rapidjson::Value& objectInput = this->m_jsonDocument->SetObject();
|
||||
this->m_serializer->Store(
|
||||
objectInput,
|
||||
&input,
|
||||
&defaultValue,
|
||||
azrtti_typeid<typename Descriptor::MatrixType>(),
|
||||
*this->m_jsonSerializationContext);
|
||||
|
||||
auto output = defaultValue;
|
||||
ResultCode result = this->m_serializer->Load(
|
||||
&output,
|
||||
azrtti_typeid<typename Descriptor::MatrixType>(),
|
||||
*this->m_jsonDocument,
|
||||
*this->m_jsonDeserializationContext);
|
||||
|
||||
EXPECT_EQ(Processing::Completed, result.GetProcessing());
|
||||
|
||||
for (int r = 0; r < Descriptor::RowCount; ++r)
|
||||
{
|
||||
for (int c = 0; c < Descriptor::ColumnCount; ++c)
|
||||
{
|
||||
EXPECT_NEAR(input.GetElement(r, c), output.GetElement(r, c), AZ::Constants::Tolerance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace JsonSerializationTests
|
||||
@@ -32,7 +32,7 @@ namespace JsonSerializationTests
|
||||
return AZStd::make_shared<AZ::JsonSmartPointerSerializer>();
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultConstructedInstance() override
|
||||
{
|
||||
return AZStd::make_shared<SmartPointer>();
|
||||
}
|
||||
@@ -51,6 +51,13 @@ namespace JsonSerializationTests
|
||||
using SmartPointer = T<SimpleClass>;
|
||||
using Base = SmartPointerBaseTestDescription<SmartPointer>;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
|
||||
{
|
||||
auto result = AZStd::make_shared<SmartPointer>();
|
||||
*result = SmartPointer(aznew SimpleClass());
|
||||
return result;
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateFullySetInstance() override
|
||||
{
|
||||
auto result = AZStd::make_shared<SmartPointer>();
|
||||
@@ -106,21 +113,6 @@ namespace JsonSerializationTests
|
||||
}
|
||||
};
|
||||
|
||||
template<template<typename...> class T>
|
||||
class SmartPointerSimpleClassWithInstanceTestDescription :
|
||||
public SmartPointerSimpleClassTestDescription<T>
|
||||
{
|
||||
public:
|
||||
using SmartPointer = typename SmartPointerSimpleClassTestDescription<T>::SmartPointer;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
|
||||
{
|
||||
auto result = AZStd::make_shared<SmartPointer>();
|
||||
*result = SmartPointer(aznew SimpleClass());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template<template<typename...> class T>
|
||||
class SmartPointerSimpleDerivedClassTestDescription :
|
||||
public SmartPointerBaseTestDescription<T<BaseClass>>
|
||||
@@ -129,6 +121,13 @@ namespace JsonSerializationTests
|
||||
using SmartPointer = T<BaseClass>;
|
||||
using Base = SmartPointerBaseTestDescription<SmartPointer>;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
|
||||
{
|
||||
auto result = AZStd::make_shared<SmartPointer>();
|
||||
*result = SmartPointer(aznew BaseClass());
|
||||
return result;
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateFullySetInstance() override
|
||||
{
|
||||
auto* instance = aznew SimpleInheritence();
|
||||
@@ -234,13 +233,19 @@ namespace JsonSerializationTests
|
||||
public:
|
||||
using SmartPointer = typename SmartPointerSimpleDerivedClassTestDescription<T>::SmartPointer;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
|
||||
// This test is specific for derived classes being used as a default value.
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultConstructedInstance() override
|
||||
{
|
||||
auto result = AZStd::make_shared<SmartPointer>();
|
||||
*result = SmartPointer(aznew SimpleInheritence());
|
||||
return result;
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
|
||||
{
|
||||
return CreateDefaultConstructedInstance();
|
||||
}
|
||||
|
||||
AZStd::string_view GetJsonForPartialDefaultInstance() override
|
||||
{
|
||||
return R"(
|
||||
@@ -272,6 +277,13 @@ namespace JsonSerializationTests
|
||||
using SmartPointer = T<BaseClass2>;
|
||||
using Base = SmartPointerBaseTestDescription<SmartPointer>;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
|
||||
{
|
||||
auto result = AZStd::make_shared<SmartPointer>();
|
||||
*result = SmartPointer(aznew BaseClass2());
|
||||
return result;
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateFullySetInstance() override
|
||||
{
|
||||
auto* instance = aznew MultipleInheritence();
|
||||
@@ -385,13 +397,19 @@ namespace JsonSerializationTests
|
||||
public:
|
||||
using SmartPointer = typename SmartPointerComplexDerivedClassTestDescription<T>::SmartPointer;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
|
||||
// This test is specific for derived classes being used as a default value.
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultConstructedInstance() override
|
||||
{
|
||||
auto result = AZStd::make_shared<SmartPointer>();
|
||||
*result = SmartPointer(aznew MultipleInheritence());
|
||||
return result;
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> CreateDefaultInstance() override
|
||||
{
|
||||
return CreateDefaultConstructedInstance();
|
||||
}
|
||||
|
||||
AZStd::string_view GetJsonForPartialDefaultInstance() override
|
||||
{
|
||||
return R"(
|
||||
@@ -424,9 +442,6 @@ namespace JsonSerializationTests
|
||||
SmartPointerSimpleClassTestDescription<AZStd::unique_ptr>,
|
||||
SmartPointerSimpleClassTestDescription<AZStd::shared_ptr>,
|
||||
SmartPointerSimpleClassTestDescription<AZStd::intrusive_ptr>,
|
||||
SmartPointerSimpleClassWithInstanceTestDescription<AZStd::unique_ptr>,
|
||||
SmartPointerSimpleClassWithInstanceTestDescription<AZStd::shared_ptr>,
|
||||
SmartPointerSimpleClassWithInstanceTestDescription<AZStd::intrusive_ptr>,
|
||||
// Simple derived class, include single inheritance.
|
||||
SmartPointerSimpleDerivedClassTestDescription<AZStd::unique_ptr>,
|
||||
SmartPointerSimpleDerivedClassTestDescription<AZStd::shared_ptr>,
|
||||
@@ -551,6 +566,37 @@ namespace JsonSerializationTests
|
||||
EXPECT_EQ(nullptr, *instance);
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Load_DefaultInstanceToNullptr_ReturnsSuccess)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
SmartPointer instance;
|
||||
AZStd::shared_ptr<SmartPointer> compare = m_description.CreateDefaultInstance();
|
||||
m_jsonDocument->SetObject();
|
||||
|
||||
JSR::ResultCode result =
|
||||
m_serializer.Load(&instance, azrtti_typeid<SmartPointer>(), *m_jsonDocument, *m_jsonDeserializationContext);
|
||||
|
||||
EXPECT_EQ(JSR::Processing::Completed, result.GetProcessing());
|
||||
EXPECT_NE(nullptr, instance);
|
||||
EXPECT_TRUE(m_description.AreEqual(instance, *compare));
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Load_DefaultObjectDoesNotUpdateInstance_ReturnsSuccess)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> instance = m_description.CreateFullySetInstance();
|
||||
AZStd::shared_ptr<SmartPointer> compare = m_description.CreateFullySetInstance();
|
||||
m_jsonDocument->SetObject();
|
||||
|
||||
JSR::ResultCode result =
|
||||
m_serializer.Load(instance.get(), azrtti_typeid<SmartPointer>(), *m_jsonDocument, *m_jsonDeserializationContext);
|
||||
|
||||
EXPECT_EQ(JSR::Processing::Completed, result.GetProcessing());
|
||||
EXPECT_TRUE(m_description.AreEqual(*instance, *compare));
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Load_InstanceBeingReplacedWithDifferentType_ReturnsSuccess)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
@@ -720,13 +766,66 @@ namespace JsonSerializationTests
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> instance = m_description.CreateFullySetInstance();
|
||||
SmartPointer nullPtr;
|
||||
JSR::ResultCode result = m_serializer.Store(*m_jsonDocument, instance.get(), &nullPtr,
|
||||
SmartPointer defaultInstance;
|
||||
JSR::ResultCode result = m_serializer.Store(
|
||||
*m_jsonDocument, instance.get(), &defaultInstance,
|
||||
azrtti_typeid<SmartPointer>(), *m_jsonSerializationContext);
|
||||
|
||||
EXPECT_EQ(JSR::Outcomes::Success, result.GetOutcome());
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Store_ValuePointerIsNullPtr_ReturnsSuccessAndStoresNull)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
SmartPointer instance;
|
||||
AZStd::shared_ptr<SmartPointer> defaultInstance = m_description.CreateFullySetInstance();
|
||||
JSR::ResultCode result = m_serializer.Store(
|
||||
*m_jsonDocument, &instance, defaultInstance.get(), azrtti_typeid<SmartPointer>(), *m_jsonSerializationContext);
|
||||
|
||||
EXPECT_EQ(JSR::Outcomes::Success, result.GetOutcome());
|
||||
EXPECT_TRUE(m_jsonDocument->IsNull());
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Store_ValueAndDefaultPointersAreNullPtr_ReturnsSuccessAndStoresNull)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
SmartPointer instance;
|
||||
SmartPointer defaultInstance;
|
||||
JSR::ResultCode result =
|
||||
m_serializer.Store(*m_jsonDocument, &instance, &defaultInstance, azrtti_typeid<SmartPointer>(), *m_jsonSerializationContext);
|
||||
|
||||
EXPECT_EQ(JSR::Outcomes::DefaultsUsed, result.GetOutcome());
|
||||
EXPECT_TRUE(m_jsonDocument->IsNull());
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Store_ValueAndDefaultPointersAreBothDefault_ReturnsSuccess)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> instance = m_description.CreateDefaultInstance();
|
||||
AZStd::shared_ptr<SmartPointer> defaultInstance = m_description.CreateDefaultInstance();
|
||||
JSR::ResultCode result =
|
||||
m_serializer.Store(*m_jsonDocument, instance.get(), defaultInstance.get(), azrtti_typeid<SmartPointer>(), *m_jsonSerializationContext);
|
||||
|
||||
EXPECT_EQ(JSR::Outcomes::DefaultsUsed, result.GetOutcome());
|
||||
Expect_ExplicitDefault(*m_jsonDocument);
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Store_ValueHasDefaultValuesAndDefaultHasNullPointer_ReturnsSuccess)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
AZStd::shared_ptr<SmartPointer> instance = m_description.CreateDefaultInstance();
|
||||
SmartPointer defaultInstance;
|
||||
JSR::ResultCode result = m_serializer.Store(
|
||||
*m_jsonDocument, instance.get(), &defaultInstance, azrtti_typeid<SmartPointer>(), *m_jsonSerializationContext);
|
||||
|
||||
EXPECT_EQ(JSR::Outcomes::DefaultsUsed, result.GetOutcome());
|
||||
Expect_ExplicitDefault(*m_jsonDocument);
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Store_DefaultPointerIsOtherClass_CompletesButDoesNotReturnDefaults)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
@@ -749,7 +848,7 @@ namespace JsonSerializationTests
|
||||
EXPECT_EQ(JSR::Processing::Completed, result.GetProcessing());
|
||||
}
|
||||
|
||||
TEST_F(JsonSmartPointerSerializerTests, Store_SaveAnClassThatIsNotReflected_ReturnsUnknown)
|
||||
TEST_F(JsonSmartPointerSerializerTests, Store_ClassThatIsNotReflected_ReturnsUnknown)
|
||||
{
|
||||
namespace JSR = AZ::JsonSerializationResult;
|
||||
|
||||
|
||||
@@ -111,6 +111,7 @@ set(FILES
|
||||
Serialization/Json/JsonSerializerMock.h
|
||||
Serialization/Json/MapSerializerTests.cpp
|
||||
Serialization/Json/MathVectorSerializerTests.cpp
|
||||
Serialization/Json/MathMatrixSerializerTests.cpp
|
||||
Serialization/Json/SmartPointerSerializerTests.cpp
|
||||
Serialization/Json/StringSerializerTests.cpp
|
||||
Serialization/Json/TestCases.h
|
||||
|
||||
@@ -51,7 +51,6 @@ namespace AZ::IO
|
||||
: ArchiveLocationPriority::ePakPriorityFileFirst }; // Which file location to favor (loose vs. pak files)
|
||||
int nMessageInvalidFileAccess{};
|
||||
int nLogInvalidFileAccess{ IsReleaseConfig ? 0 : 1 };
|
||||
int nLoadFrontendShaderCache{ FRONTEND_SHADER_CACHE_DEFAULT };
|
||||
int nDisableNonLevelRelatedPaks{ 1 };
|
||||
int nWarnOnPakAccessFails{ 1 }; // Whether to treat failed pak access as a warning or log message
|
||||
int nSetLogLevel{ 3 };
|
||||
|
||||
@@ -36,6 +36,8 @@ namespace AzFramework
|
||||
|
||||
void NonUniformScaleComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC_CE("NonUniformScaleService"));
|
||||
|
||||
incompatible.push_back(AZ_CRC_CE("DebugDrawObbService"));
|
||||
incompatible.push_back(AZ_CRC_CE("DebugDrawService"));
|
||||
incompatible.push_back(AZ_CRC_CE("EMotionFXActorService"));
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
*/
|
||||
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <AzFramework/Visibility/EntityBoundsUnionBus.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/Math/Quaternion.h>
|
||||
|
||||
@@ -693,9 +695,8 @@ namespace AzFramework
|
||||
parentId = handler->GetParentId();
|
||||
}
|
||||
#endif
|
||||
|
||||
AZ::Entity* parentEntity = nullptr;
|
||||
EBUS_EVENT_RESULT(parentEntity, AZ::ComponentApplicationBus, FindEntity, parentEntityId);
|
||||
AZ::ComponentApplicationRequests* componentApplication = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
|
||||
AZ::Entity* parentEntity = (componentApplication != nullptr) ? componentApplication->FindEntity(parentEntityId) : nullptr;
|
||||
AZ_Assert(parentEntity, "We expect to have a parent entity associated with the provided parent's entity Id.");
|
||||
if (parentEntity)
|
||||
{
|
||||
@@ -744,8 +745,8 @@ namespace AzFramework
|
||||
m_parentId = parentId;
|
||||
if (m_parentId.IsValid())
|
||||
{
|
||||
AZ::Entity* parentEntity = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(parentEntity, &AZ::ComponentApplicationBus::Events::FindEntity, m_parentId);
|
||||
AZ::ComponentApplicationRequests* componentApplication = AZ::Interface<AZ::ComponentApplicationRequests>::Get();
|
||||
AZ::Entity* parentEntity = (componentApplication != nullptr) ? componentApplication->FindEntity(m_parentId) : nullptr;
|
||||
m_parentActive = parentEntity && (parentEntity->GetState() == AZ::Entity::State::Active);
|
||||
|
||||
m_onNewParentKeepWorldTM = isKeepWorldTM;
|
||||
@@ -832,6 +833,12 @@ namespace AzFramework
|
||||
|
||||
EBUS_EVENT_PTR(m_notificationBus, AZ::TransformNotificationBus, OnTransformChanged, m_localTM, m_worldTM);
|
||||
m_transformChangedEvent.Signal(m_localTM, m_worldTM);
|
||||
|
||||
AzFramework::IEntityBoundsUnion* boundsUnion = AZ::Interface<AzFramework::IEntityBoundsUnion>::Get();
|
||||
if (boundsUnion != nullptr)
|
||||
{
|
||||
boundsUnion->OnTransformUpdated(GetEntity());
|
||||
}
|
||||
}
|
||||
|
||||
void TransformComponent::ComputeWorldTM()
|
||||
|
||||
@@ -34,6 +34,8 @@ class ITexture;
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
inline constexpr AZ::s32 g_defaultSceneEntityDebugDisplayId = AZ_CRC_CE("MainViewportEntityDebugDisplayId"); // default id to draw to all viewports in the default scene
|
||||
|
||||
/// DebugDisplayRequests provides a debug draw api to be used by components and viewport features.
|
||||
class DebugDisplayRequests
|
||||
: public AZ::EBusTraits
|
||||
|
||||
@@ -93,6 +93,8 @@ namespace AzFramework
|
||||
InitContext();
|
||||
|
||||
GameEntityContextRequestBus::Handler::BusConnect();
|
||||
|
||||
m_entityVisibilityBoundsUnionSystem.Connect();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
@@ -100,6 +102,8 @@ namespace AzFramework
|
||||
//=========================================================================
|
||||
void GameEntityContextComponent::Deactivate()
|
||||
{
|
||||
m_entityVisibilityBoundsUnionSystem.Disconnect();
|
||||
|
||||
GameEntityContextRequestBus::Handler::BusDisconnect();
|
||||
|
||||
DestroyContext();
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzFramework/Entity/GameEntityContextBus.h>
|
||||
#include <AzFramework/Entity/SliceGameEntityOwnershipService.h>
|
||||
#include <AzFramework/Visibility/EntityVisibilityBoundsUnionSystem.h>
|
||||
|
||||
#include "EntityContext.h"
|
||||
|
||||
@@ -91,6 +92,9 @@ namespace AzFramework
|
||||
{
|
||||
required.push_back(AZ_CRC("SliceSystemService", 0x1a5b7aad));
|
||||
}
|
||||
|
||||
private:
|
||||
AzFramework::EntityVisibilityBoundsUnionSystem m_entityVisibilityBoundsUnionSystem;
|
||||
};
|
||||
} // namespace AzFramework
|
||||
|
||||
|
||||
+13
-28
@@ -19,44 +19,29 @@
|
||||
|
||||
namespace AzPhysics
|
||||
{
|
||||
struct SimulatedBody;
|
||||
}
|
||||
|
||||
namespace Physics
|
||||
{
|
||||
//! Requests for generic physical world bodies
|
||||
class WorldBodyRequests
|
||||
//! Requests for physics simulated body components.
|
||||
class SimulatedBodyComponentRequests
|
||||
: public AZ::ComponentBus
|
||||
{
|
||||
public:
|
||||
using MutexType = AZStd::recursive_mutex;
|
||||
|
||||
//! Enable physics for this body
|
||||
//! Enable physics for this body.
|
||||
virtual void EnablePhysics() = 0;
|
||||
//! Disable physics for this body
|
||||
//! Disable physics for this body.
|
||||
virtual void DisablePhysics() = 0;
|
||||
//! Retrieve whether physics is enabled for this body
|
||||
//! Retrieve whether physics is enabled for this body.
|
||||
virtual bool IsPhysicsEnabled() const = 0;
|
||||
|
||||
//! Retrieves the AABB(aligned-axis bounding box) for this body
|
||||
//! Retrieves the AABB(aligned-axis bounding box) for this body.
|
||||
virtual AZ::Aabb GetAabb() const = 0;
|
||||
//! Retrieves current WorldBody* for this body. Note: Do not hold a reference to AzPhysics::SimulatedBody* as could be deleted
|
||||
virtual AzPhysics::SimulatedBody* GetWorldBody() = 0;
|
||||
|
||||
//! Perform a single-object raycast against this body
|
||||
//! Get the Simulated Body Handle for this body.
|
||||
virtual AzPhysics::SimulatedBodyHandle GetSimulatedBodyHandle() const = 0;
|
||||
//! Retrieves current WorldBody* for this body.
|
||||
//! @note Do not hold a reference to AzPhysics::SimulatedBody* as it could be deleted or moved.
|
||||
virtual AzPhysics::SimulatedBody* GetSimulatedBody() = 0;
|
||||
//! Perform a single-object raycast against this body.
|
||||
virtual AzPhysics::SceneQueryHit RayCast(const AzPhysics::RayCastRequest& request) = 0;
|
||||
};
|
||||
using WorldBodyRequestBus = AZ::EBus<WorldBodyRequests>;
|
||||
|
||||
//! Notifications for generic physical world bodies
|
||||
class WorldBodyNotifications
|
||||
: public AZ::ComponentBus
|
||||
{
|
||||
public:
|
||||
//! Notification for physics enabled
|
||||
virtual void OnPhysicsEnabled() = 0;
|
||||
//! Notification for physics disabled
|
||||
virtual void OnPhysicsDisabled() = 0;
|
||||
};
|
||||
using WorldBodyNotificationBus = AZ::EBus<WorldBodyNotifications>;
|
||||
using SimulatedBodyComponentRequestsBus = AZ::EBus<SimulatedBodyComponentRequests>;
|
||||
}
|
||||
@@ -48,6 +48,9 @@ namespace Physics
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext
|
||||
->RegisterGenericType<AZStd::shared_ptr<SphereShapeConfiguration>>();
|
||||
|
||||
serializeContext->Class<SphereShapeConfiguration, ShapeConfiguration>()
|
||||
->Version(1)
|
||||
->Field("Radius", &SphereShapeConfiguration::m_radius)
|
||||
@@ -76,6 +79,9 @@ namespace Physics
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext
|
||||
->RegisterGenericType<AZStd::shared_ptr<BoxShapeConfiguration>>();
|
||||
|
||||
serializeContext->Class<BoxShapeConfiguration, ShapeConfiguration>()
|
||||
->Version(1)
|
||||
->Field("Configuration", &BoxShapeConfiguration::m_dimensions)
|
||||
@@ -104,6 +110,9 @@ namespace Physics
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext
|
||||
->RegisterGenericType<AZStd::shared_ptr<CapsuleShapeConfiguration>>();
|
||||
|
||||
serializeContext->Class<CapsuleShapeConfiguration, ShapeConfiguration>()
|
||||
->Version(1)
|
||||
->Field("Height", &CapsuleShapeConfiguration::m_height)
|
||||
@@ -153,6 +162,9 @@ namespace Physics
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext
|
||||
->RegisterGenericType<AZStd::shared_ptr<PhysicsAssetShapeConfiguration>>();
|
||||
|
||||
serializeContext->Class<PhysicsAssetShapeConfiguration, ShapeConfiguration>()
|
||||
->Version(1)
|
||||
->Field("PhysicsAsset", &PhysicsAssetShapeConfiguration::m_asset)
|
||||
@@ -185,6 +197,9 @@ namespace Physics
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext
|
||||
->RegisterGenericType<AZStd::shared_ptr<NativeShapeConfiguration>>();
|
||||
|
||||
serializeContext->Class<NativeShapeConfiguration, ShapeConfiguration>()
|
||||
->Version(1)
|
||||
->Field("Scale", &NativeShapeConfiguration::m_nativeShapeScale)
|
||||
@@ -208,6 +223,9 @@ namespace Physics
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext
|
||||
->RegisterGenericType<AZStd::shared_ptr<CookedMeshShapeConfiguration>>();
|
||||
|
||||
serializeContext->Class<CookedMeshShapeConfiguration, ShapeConfiguration>()
|
||||
->Version(1)
|
||||
->Field("CookedData", &CookedMeshShapeConfiguration::m_cookedData)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <AzFramework/Physics/ShapeConfiguration.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzFramework/Physics/CollisionBus.h>
|
||||
#include <AzFramework/Physics/WorldBodyBus.h>
|
||||
#include <AzFramework/Physics/Components/SimulatedBodyComponentBus.h>
|
||||
#include <AzFramework/Physics/WindBus.h>
|
||||
#include <AzFramework/Physics/PhysicsSystem.h>
|
||||
#include <AzFramework/Physics/Collision/CollisionEvents.h>
|
||||
@@ -39,19 +39,19 @@ namespace Physics
|
||||
{
|
||||
namespace ReflectionUtils
|
||||
{
|
||||
void ReflectWorldBodyBus(AZ::ReflectContext* context)
|
||||
void ReflectSimulatedBodyComponentRequestsBus(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->EBus<Physics::WorldBodyRequestBus>("WorldBodyRequestBus")
|
||||
behaviorContext->EBus<AzPhysics::SimulatedBodyComponentRequestsBus>("SimulatedBodyComponentRequestBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Module, "physics")
|
||||
->Attribute(AZ::Script::Attributes::Category, "PhysX")
|
||||
->Event("EnablePhysics", &WorldBodyRequests::EnablePhysics)
|
||||
->Event("DisablePhysics", &WorldBodyRequests::DisablePhysics)
|
||||
->Event("IsPhysicsEnabled", &WorldBodyRequests::IsPhysicsEnabled)
|
||||
->Event("GetAabb", &WorldBodyRequests::GetAabb)
|
||||
->Event("RayCast", &WorldBodyRequests::RayCast)
|
||||
->Event("EnablePhysics", &AzPhysics::SimulatedBodyComponentRequests::EnablePhysics)
|
||||
->Event("DisablePhysics", &AzPhysics::SimulatedBodyComponentRequests::DisablePhysics)
|
||||
->Event("IsPhysicsEnabled", &AzPhysics::SimulatedBodyComponentRequests::IsPhysicsEnabled)
|
||||
->Event("GetAabb", &AzPhysics::SimulatedBodyComponentRequests::GetAabb)
|
||||
->Event("RayCast", &AzPhysics::SimulatedBodyComponentRequests::RayCast)
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -131,7 +131,7 @@ namespace Physics
|
||||
AnimationConfiguration::Reflect(context);
|
||||
CharacterConfiguration::Reflect(context);
|
||||
AzPhysics::SimulatedBody::Reflect(context);
|
||||
ReflectWorldBodyBus(context);
|
||||
ReflectSimulatedBodyComponentRequestsBus(context);
|
||||
CollisionFilteringRequests::Reflect(context);
|
||||
AzPhysics::SceneQuery::ReflectSceneQueryObjects(context);
|
||||
ReflectWindBus(context);
|
||||
|
||||
@@ -137,7 +137,7 @@ namespace AzFramework::ProjectManager
|
||||
}
|
||||
AZ::IO::FixedMaxPath pythonPath = engineRootPath / "python";
|
||||
pythonPath /= AZ_TRAIT_AZFRAMEWORK_PYTHON_SHELL;
|
||||
auto cmdPath = AZ::IO::FixedMaxPathString::format("%s %s%s --executable_path=%s --parent_pid=%" PRId64, pythonPath.Native().c_str(),
|
||||
auto cmdPath = AZ::IO::FixedMaxPathString::format("%s %s%s --executable_path=%s --parent_pid=%" PRIu32, pythonPath.Native().c_str(),
|
||||
debugOption.c_str(), (projectManagerPath / projectsScript).c_str(), executablePath.c_str(), AZ::Platform::GetCurrentProcessId());
|
||||
|
||||
AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
|
||||
|
||||
@@ -139,7 +139,8 @@ namespace AzFramework
|
||||
"Implementers of IntersectionRequestBus must also implement BoundsRequestBus to ensure valid "
|
||||
"bounds are returned");
|
||||
|
||||
m_registeredEntities.Update({ entityId, CalculateEntityWorldBoundsUnion(entityId) });
|
||||
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId);
|
||||
m_registeredEntities.Update({ entityId, CalculateEntityWorldBoundsUnion(entity) });
|
||||
}
|
||||
|
||||
m_dirtyEntities.clear();
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool Scene::UnsetSubsystem(const T& system)
|
||||
bool Scene::UnsetSubsystem([[maybe_unused]] const T& system)
|
||||
{
|
||||
const AZ::TypeId& targetType = azrtti_typeid<T>();
|
||||
const size_t systemKeysCount = m_systemKeys.size();
|
||||
|
||||
@@ -148,6 +148,12 @@ namespace AzFramework
|
||||
//! Blocks until all operations made on the provided ticket before the barrier call have completed.
|
||||
virtual void Barrier(EntitySpawnTicket& ticket, BarrierCallback completionCallback) = 0;
|
||||
|
||||
//! Register a handler for OnSpawned events.
|
||||
virtual void AddOnSpawnedHandler(AZ::Event<AZ::Data::Asset<Spawnable>>::Handler& handler) = 0;
|
||||
|
||||
//! Register a handler for OnDespawned events.
|
||||
virtual void AddOnDespawnedHandler(AZ::Event<AZ::Data::Asset<Spawnable>>::Handler& handler) = 0;
|
||||
|
||||
protected:
|
||||
[[nodiscard]] virtual void* CreateTicket(AZ::Data::Asset<Spawnable>&& spawnable) = 0;
|
||||
virtual void DestroyTicket(void* ticket) = 0;
|
||||
|
||||
@@ -114,6 +114,16 @@ namespace AzFramework
|
||||
}
|
||||
}
|
||||
|
||||
void SpawnableEntitiesManager::AddOnSpawnedHandler(AZ::Event<AZ::Data::Asset<Spawnable>>::Handler& handler)
|
||||
{
|
||||
handler.Connect(m_onSpawnedEvent);
|
||||
}
|
||||
|
||||
void SpawnableEntitiesManager::AddOnDespawnedHandler(AZ::Event<AZ::Data::Asset<Spawnable>>::Handler& handler)
|
||||
{
|
||||
handler.Connect(m_onDespawnedEvent);
|
||||
}
|
||||
|
||||
auto SpawnableEntitiesManager::ProcessQueue() -> CommandQueueStatus
|
||||
{
|
||||
AZStd::queue<Requests> pendingRequestQueue;
|
||||
@@ -223,6 +233,8 @@ namespace AzFramework
|
||||
ticket.m_spawnedEntities.begin() + spawnedEntitiesCount, ticket.m_spawnedEntities.end()));
|
||||
}
|
||||
|
||||
m_onSpawnedEvent.Signal(ticket.m_spawnable);
|
||||
|
||||
ticket.m_currentTicketId++;
|
||||
return true;
|
||||
}
|
||||
@@ -257,6 +269,8 @@ namespace AzFramework
|
||||
ticket.m_spawnedEntities.begin() + spawnedEntitiesCount, ticket.m_spawnedEntities.end()));
|
||||
}
|
||||
|
||||
m_onSpawnedEvent.Signal(ticket.m_spawnable);
|
||||
|
||||
ticket.m_currentTicketId++;
|
||||
return true;
|
||||
}
|
||||
@@ -289,6 +303,8 @@ namespace AzFramework
|
||||
request.m_completionCallback(*request.m_ticket);
|
||||
}
|
||||
|
||||
m_onDespawnedEvent.Signal(ticket.m_spawnable);
|
||||
|
||||
ticket.m_currentTicketId++;
|
||||
return true;
|
||||
}
|
||||
@@ -315,6 +331,8 @@ namespace AzFramework
|
||||
&GameEntityContextRequestBus::Events::DestroyGameEntityAndDescendants, entity->GetId());
|
||||
}
|
||||
}
|
||||
|
||||
m_onDespawnedEvent.Signal(ticket.m_spawnable);
|
||||
|
||||
// Rebuild the list of entities.
|
||||
ticket.m_spawnedEntities.clear();
|
||||
@@ -350,6 +368,9 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
ticket.m_currentTicketId++;
|
||||
|
||||
m_onSpawnedEvent.Signal(ticket.m_spawnable);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -60,6 +60,9 @@ namespace AzFramework
|
||||
|
||||
void Barrier(EntitySpawnTicket& spawnInfo, BarrierCallback completionCallback) override;
|
||||
|
||||
void AddOnSpawnedHandler(AZ::Event<AZ::Data::Asset<Spawnable>>::Handler& handler) override;
|
||||
void AddOnDespawnedHandler(AZ::Event<AZ::Data::Asset<Spawnable>>::Handler& handler) override;
|
||||
|
||||
//
|
||||
// The following function is thread safe but intended to be run from the main thread.
|
||||
//
|
||||
@@ -156,5 +159,8 @@ namespace AzFramework
|
||||
AZStd::deque<Requests> m_delayedQueue; //!< Requests that were processed before, but couldn't be completed.
|
||||
AZStd::queue<Requests> m_pendingRequestQueue;
|
||||
AZStd::mutex m_pendingRequestQueueMutex;
|
||||
|
||||
AZ::Event<AZ::Data::Asset<Spawnable>> m_onSpawnedEvent;
|
||||
AZ::Event<AZ::Data::Asset<Spawnable>> m_onDespawnedEvent;
|
||||
};
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -12,33 +12,173 @@
|
||||
|
||||
#include "CameraInput.h"
|
||||
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
#include <AzCore/Math/Plane.h>
|
||||
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/Windowing/WindowBus.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
void CameraSystem::HandleEvents(const InputEvent& event)
|
||||
AZ_CVAR(
|
||||
float, ed_cameraSystemDefaultPlaneHeight, 34.0f, nullptr, AZ::ConsoleFunctorFlags::Null,
|
||||
"The default height of the ground plane to do intersection tests against when orbiting");
|
||||
AZ_CVAR(float, ed_cameraSystemBoostMultiplier, 3.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemTranslateSpeed, 10.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemOrbitDollyScrollSpeed, 0.02f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemOrbitDollyCursorSpeed, 0.01f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemScrollTranslateSpeed, 0.02f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemMaxOrbitDistance, 60.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemLookSmoothness, 5.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemTranslateSmoothness, 5.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemRotateSpeed, 0.005f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemPanSpeed, 0.01f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(bool, ed_cameraSystemPanInvertX, true, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(bool, ed_cameraSystemPanInvertY, true, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(float, ed_cameraSystemLookDeadzone, 2.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
|
||||
AZ_CVAR(
|
||||
AZ::CVarFixedString, ed_cameraSystemTranslateForwardKey, "keyboard_key_alphanumeric_W", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(
|
||||
AZ::CVarFixedString, ed_cameraSystemTranslateBackwardKey, "keyboard_key_alphanumeric_S", nullptr, AZ::ConsoleFunctorFlags::Null,
|
||||
"");
|
||||
AZ_CVAR(
|
||||
AZ::CVarFixedString, ed_cameraSystemTranslateLeftKey, "keyboard_key_alphanumeric_A", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(
|
||||
AZ::CVarFixedString, ed_cameraSystemTranslateRightKey, "keyboard_key_alphanumeric_D", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemTranslateUpKey, "keyboard_key_alphanumeric_E", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(
|
||||
AZ::CVarFixedString, ed_cameraSystemTranslateDownKey, "keyboard_key_alphanumeric_Q", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(
|
||||
AZ::CVarFixedString, ed_cameraSystemTranslateBoostKey, "keyboard_key_modifier_shift_l", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemOrbitKey, "keyboard_key_modifier_alt_l", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
|
||||
AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemFreeLookButton, "mouse_button_right", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemFreePanButton, "mouse_button_middle", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemOrbitLookButton, "mouse_button_left", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemOrbitDollyButton, "mouse_button_right", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemOrbitPanButton, "mouse_button_middle", nullptr, AZ::ConsoleFunctorFlags::Null, "");
|
||||
|
||||
static InputChannelId CameraTranslateForwardId;
|
||||
static InputChannelId CameraTranslateBackwardId;
|
||||
static InputChannelId CameraTranslateLeftId;
|
||||
static InputChannelId CameraTranslateRightId;
|
||||
static InputChannelId CameraTranslateDownId;
|
||||
static InputChannelId CameraTranslateUpId;
|
||||
static InputChannelId CameraTranslateBoostId;
|
||||
static InputChannelId CameraOrbitId;
|
||||
|
||||
// externed elsewhere
|
||||
InputChannelId CameraFreeLookButton;
|
||||
InputChannelId CameraFreePanButton;
|
||||
InputChannelId CameraOrbitLookButton;
|
||||
InputChannelId CameraOrbitDollyButton;
|
||||
InputChannelId CameraOrbitPanButton;
|
||||
|
||||
void ReloadCameraKeyBindings()
|
||||
{
|
||||
if (const auto& cursor_motion = AZStd::get_if<CursorMotionEvent>(&event))
|
||||
const AZ::CVarFixedString& forward = ed_cameraSystemTranslateForwardKey;
|
||||
CameraTranslateForwardId = InputChannelId(forward.c_str());
|
||||
const AZ::CVarFixedString& backward = ed_cameraSystemTranslateBackwardKey;
|
||||
CameraTranslateBackwardId = InputChannelId(backward.c_str());
|
||||
const AZ::CVarFixedString& left = ed_cameraSystemTranslateLeftKey;
|
||||
CameraTranslateLeftId = InputChannelId(left.c_str());
|
||||
const AZ::CVarFixedString& right = ed_cameraSystemTranslateRightKey;
|
||||
CameraTranslateRightId = InputChannelId(right.c_str());
|
||||
const AZ::CVarFixedString& down = ed_cameraSystemTranslateDownKey;
|
||||
CameraTranslateDownId = InputChannelId(down.c_str());
|
||||
const AZ::CVarFixedString& up = ed_cameraSystemTranslateUpKey;
|
||||
CameraTranslateUpId = InputChannelId(up.c_str());
|
||||
const AZ::CVarFixedString& boost = ed_cameraSystemTranslateBoostKey;
|
||||
CameraTranslateBoostId = InputChannelId(boost.c_str());
|
||||
const AZ::CVarFixedString& orbit = ed_cameraSystemOrbitKey;
|
||||
CameraOrbitId = InputChannelId(orbit.c_str());
|
||||
const AZ::CVarFixedString& freeLook = ed_cameraSystemFreeLookButton;
|
||||
CameraFreeLookButton = InputChannelId(freeLook.c_str());
|
||||
const AZ::CVarFixedString& freePan = ed_cameraSystemFreePanButton;
|
||||
CameraFreePanButton = InputChannelId(freePan.c_str());
|
||||
const AZ::CVarFixedString& orbitLook = ed_cameraSystemOrbitLookButton;
|
||||
CameraOrbitLookButton = InputChannelId(orbitLook.c_str());
|
||||
const AZ::CVarFixedString& orbitDolly = ed_cameraSystemOrbitDollyButton;
|
||||
CameraOrbitDollyButton = InputChannelId(orbitDolly.c_str());
|
||||
const AZ::CVarFixedString& orbitPan = ed_cameraSystemOrbitPanButton;
|
||||
CameraOrbitPanButton = InputChannelId(orbitPan.c_str());
|
||||
}
|
||||
|
||||
static void ReloadCameraKeyBindingsConsole(const AZ::ConsoleCommandContainer&)
|
||||
{
|
||||
ReloadCameraKeyBindings();
|
||||
}
|
||||
|
||||
AZ_CONSOLEFREEFUNC(ReloadCameraKeyBindingsConsole, AZ::ConsoleFunctorFlags::Null, "Reload keybindings for the modern camera system");
|
||||
|
||||
// Based on paper by David Eberly - https://www.geometrictools.com/Documentation/EulerAngles.pdf
|
||||
AZ::Vector3 EulerAngles(const AZ::Matrix3x3& orientation)
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
||||
// 2.4 Factor as RzRyRx
|
||||
if (orientation.GetElement(2, 0) < 1.0f)
|
||||
{
|
||||
m_currentCursorPosition = cursor_motion->m_position;
|
||||
if (orientation.GetElement(2, 0) > -1.0f)
|
||||
{
|
||||
x = AZStd::atan2(orientation.GetElement(2, 1), orientation.GetElement(2, 2));
|
||||
y = AZStd::asin(-orientation.GetElement(2, 0));
|
||||
z = AZStd::atan2(orientation.GetElement(1, 0), orientation.GetElement(0, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
x = 0.0f;
|
||||
y = AZ::Constants::Pi * 0.5f;
|
||||
z = -AZStd::atan2(-orientation.GetElement(2, 1), orientation.GetElement(1, 1));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
x = 0.0f;
|
||||
y = -AZ::Constants::Pi * 0.5f;
|
||||
z = AZStd::atan2(-orientation.GetElement(1, 2), orientation.GetElement(1, 1));
|
||||
}
|
||||
|
||||
return {x, y, z};
|
||||
}
|
||||
|
||||
void UpdateCameraFromTransform(Camera& camera, const AZ::Transform& transform)
|
||||
{
|
||||
const auto eulerAngles = AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromTransform(transform));
|
||||
|
||||
camera.m_pitch = eulerAngles.GetX();
|
||||
camera.m_yaw = eulerAngles.GetZ();
|
||||
// note: m_lookDist is negative so we must invert it here
|
||||
camera.m_lookAt = transform.GetTranslation() + (camera.Rotation().GetBasisY() * -camera.m_lookDist);
|
||||
}
|
||||
|
||||
static ScreenVector CursorDelta(const AZStd::optional<ScreenPoint>& currentPosition, const AZStd::optional<ScreenPoint>& lastPosition)
|
||||
{
|
||||
return currentPosition.has_value() && lastPosition.has_value() ? currentPosition.value() - lastPosition.value()
|
||||
: ScreenVector(0, 0);
|
||||
}
|
||||
|
||||
bool CameraSystem::HandleEvents(const InputEvent& event)
|
||||
{
|
||||
if (const auto& cursor = AZStd::get_if<CursorEvent>(&event))
|
||||
{
|
||||
m_currentCursorPosition = cursor->m_position;
|
||||
}
|
||||
else if (const auto& scroll = AZStd::get_if<ScrollEvent>(&event))
|
||||
{
|
||||
m_scrollDelta = scroll->m_delta;
|
||||
}
|
||||
|
||||
m_cameras.HandleEvents(event);
|
||||
return m_cameras.HandleEvents(event, CursorDelta(m_currentCursorPosition, m_lastCursorPosition), m_scrollDelta);
|
||||
}
|
||||
|
||||
Camera CameraSystem::StepCamera(const Camera& targetCamera, float deltaTime)
|
||||
Camera CameraSystem::StepCamera(const Camera& targetCamera, const float deltaTime)
|
||||
{
|
||||
const auto cursorDelta = m_currentCursorPosition.has_value() && m_lastCursorPosition.has_value()
|
||||
? m_currentCursorPosition.value() - m_lastCursorPosition.value()
|
||||
: ScreenVector(0, 0);
|
||||
|
||||
const auto cursorDelta = CursorDelta(m_currentCursorPosition, m_lastCursorPosition);
|
||||
if (m_currentCursorPosition.has_value())
|
||||
{
|
||||
m_lastCursorPosition = m_currentCursorPosition;
|
||||
@@ -51,36 +191,41 @@ namespace AzFramework
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
void Cameras::AddCamera(AZStd::shared_ptr<CameraInput> camera_input)
|
||||
void Cameras::AddCamera(AZStd::shared_ptr<CameraInput> cameraInput)
|
||||
{
|
||||
m_idleCameraInputs.push_back(AZStd::move(camera_input));
|
||||
m_idleCameraInputs.push_back(AZStd::move(cameraInput));
|
||||
}
|
||||
|
||||
void Cameras::HandleEvents(const InputEvent& event)
|
||||
bool Cameras::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta)
|
||||
{
|
||||
for (auto& camera_input : m_activeCameraInputs)
|
||||
bool handling = false;
|
||||
for (auto& cameraInput : m_activeCameraInputs)
|
||||
{
|
||||
camera_input->HandleEvents(event);
|
||||
cameraInput->HandleEvents(event, cursorDelta, scrollDelta);
|
||||
handling = !cameraInput->Idle() || handling;
|
||||
}
|
||||
|
||||
for (auto& camera_input : m_idleCameraInputs)
|
||||
for (auto& cameraInput : m_idleCameraInputs)
|
||||
{
|
||||
camera_input->HandleEvents(event);
|
||||
cameraInput->HandleEvents(event, cursorDelta, scrollDelta);
|
||||
}
|
||||
|
||||
return handling;
|
||||
}
|
||||
|
||||
Camera Cameras::StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, const float deltaTime)
|
||||
Camera Cameras::StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, const float scrollDelta, const float deltaTime)
|
||||
{
|
||||
for (int i = 0; i < m_idleCameraInputs.size();)
|
||||
{
|
||||
auto& camera_input = m_idleCameraInputs[i];
|
||||
const bool can_begin = camera_input->Beginning() &&
|
||||
std::all_of(m_activeCameraInputs.cbegin(), m_activeCameraInputs.cend(),
|
||||
[](const auto& input) { return !input->Exclusive(); }) &&
|
||||
(!camera_input->Exclusive() || (camera_input->Exclusive() && m_activeCameraInputs.empty()));
|
||||
if (can_begin)
|
||||
auto& cameraInput = m_idleCameraInputs[i];
|
||||
const bool canBegin = cameraInput->Beginning() &&
|
||||
AZStd::all_of(m_activeCameraInputs.cbegin(), m_activeCameraInputs.cend(),
|
||||
[](const auto& input) { return !input->Exclusive(); }) &&
|
||||
(!cameraInput->Exclusive() || (cameraInput->Exclusive() && m_activeCameraInputs.empty()));
|
||||
|
||||
if (canBegin)
|
||||
{
|
||||
m_activeCameraInputs.push_back(camera_input);
|
||||
m_activeCameraInputs.push_back(cameraInput);
|
||||
using AZStd::swap;
|
||||
swap(m_idleCameraInputs[i], m_idleCameraInputs[m_idleCameraInputs.size() - 1]);
|
||||
m_idleCameraInputs.pop_back();
|
||||
@@ -93,25 +238,25 @@ namespace AzFramework
|
||||
|
||||
// accumulate
|
||||
Camera nextCamera = targetCamera;
|
||||
for (auto& camera_input : m_activeCameraInputs)
|
||||
for (auto& cameraInput : m_activeCameraInputs)
|
||||
{
|
||||
nextCamera = camera_input->StepCamera(nextCamera, cursorDelta, scrollDelta, deltaTime);
|
||||
nextCamera = cameraInput->StepCamera(nextCamera, cursorDelta, scrollDelta, deltaTime);
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_activeCameraInputs.size();)
|
||||
{
|
||||
auto& camera_input = m_activeCameraInputs[i];
|
||||
if (camera_input->Ending())
|
||||
auto& cameraInput = m_activeCameraInputs[i];
|
||||
if (cameraInput->Ending())
|
||||
{
|
||||
camera_input->ClearActivation();
|
||||
m_idleCameraInputs.push_back(camera_input);
|
||||
cameraInput->ClearActivation();
|
||||
m_idleCameraInputs.push_back(cameraInput);
|
||||
using AZStd::swap;
|
||||
swap(m_activeCameraInputs[i], m_activeCameraInputs[m_activeCameraInputs.size() - 1]);
|
||||
m_activeCameraInputs.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
camera_input->ContinueActivation();
|
||||
cameraInput->ContinueActivation();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@@ -130,22 +275,35 @@ namespace AzFramework
|
||||
}
|
||||
}
|
||||
|
||||
void RotateCameraInput::HandleEvents(const InputEvent& event)
|
||||
void RotateCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
|
||||
{
|
||||
if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
{
|
||||
if (input->m_channelId == m_channelId)
|
||||
if (input->m_channelId == m_rotateChannelId)
|
||||
{
|
||||
if (input->m_state == InputChannel::State::Began)
|
||||
{
|
||||
BeginActivation();
|
||||
m_tryingToBegin = true;
|
||||
m_moveAccumulator = 0.0f;
|
||||
}
|
||||
else if (input->m_state == InputChannel::State::Ended)
|
||||
{
|
||||
m_tryingToBegin = false;
|
||||
EndActivation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_tryingToBegin)
|
||||
{
|
||||
// only allow the action to begin if the mouse has been moved a small amount
|
||||
m_moveAccumulator += ScreenVectorLength(cursorDelta);
|
||||
if (m_moveAccumulator > ed_cameraSystemLookDeadzone)
|
||||
{
|
||||
BeginActivation();
|
||||
m_tryingToBegin = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Camera RotateCameraInput::StepCamera(
|
||||
@@ -154,23 +312,24 @@ namespace AzFramework
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
|
||||
nextCamera.m_pitch += float(cursorDelta.m_y) * m_props.m_rotateSpeed;
|
||||
nextCamera.m_yaw += float(cursorDelta.m_x) * m_props.m_rotateSpeed;
|
||||
nextCamera.m_pitch -= float(cursorDelta.m_y) * ed_cameraSystemRotateSpeed;
|
||||
nextCamera.m_yaw -= float(cursorDelta.m_x) * ed_cameraSystemRotateSpeed;
|
||||
|
||||
auto clamp_rotation = [](const float angle) { return std::fmod(angle + AZ::Constants::TwoOverPi, AZ::Constants::TwoOverPi); };
|
||||
const auto clampRotation = [](const float angle) { return AZStd::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi); };
|
||||
|
||||
nextCamera.m_yaw = clamp_rotation(nextCamera.m_yaw);
|
||||
nextCamera.m_yaw = clampRotation(nextCamera.m_yaw);
|
||||
// clamp pitch to be +-90 degrees
|
||||
nextCamera.m_pitch = AZ::GetClamp(nextCamera.m_pitch, -AZ::Constants::Pi * 0.5f, AZ::Constants::Pi * 0.5f);
|
||||
nextCamera.m_pitch = AZ::GetClamp(nextCamera.m_pitch, -AZ::Constants::HalfPi, AZ::Constants::HalfPi);
|
||||
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
void PanCameraInput::HandleEvents(const InputEvent& event)
|
||||
void PanCameraInput::HandleEvents(
|
||||
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
|
||||
{
|
||||
if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
{
|
||||
if (input->m_channelId == InputDeviceMouse::Button::Middle)
|
||||
if (input->m_channelId == m_panChannelId)
|
||||
{
|
||||
if (input->m_state == InputChannel::State::Began)
|
||||
{
|
||||
@@ -190,51 +349,50 @@ namespace AzFramework
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
|
||||
const auto pan_axes = m_panAxesFn(nextCamera);
|
||||
const auto panAxes = m_panAxesFn(nextCamera);
|
||||
|
||||
const auto delta_pan_x = float(cursorDelta.m_x) * pan_axes.m_horizontalAxis * m_props.m_panSpeed;
|
||||
const auto delta_pan_y = float(cursorDelta.m_y) * pan_axes.m_verticalAxis * m_props.m_panSpeed;
|
||||
const auto deltaPanX = float(cursorDelta.m_x) * panAxes.m_horizontalAxis * ed_cameraSystemPanSpeed;
|
||||
const auto deltaPanY = float(cursorDelta.m_y) * panAxes.m_verticalAxis * ed_cameraSystemPanSpeed;
|
||||
|
||||
const auto inv = [](const bool invert) {
|
||||
constexpr float Dir[] = {1.0f, -1.0f};
|
||||
return Dir[static_cast<int>(invert)];
|
||||
};
|
||||
|
||||
nextCamera.m_lookAt += delta_pan_x * inv(m_props.m_panInvertX);
|
||||
nextCamera.m_lookAt += delta_pan_y * -inv(m_props.m_panInvertY);
|
||||
nextCamera.m_lookAt += deltaPanX * inv(ed_cameraSystemPanInvertX);
|
||||
nextCamera.m_lookAt += deltaPanY * -inv(ed_cameraSystemPanInvertY);
|
||||
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
TranslateCameraInput::TranslationType TranslateCameraInput::translationFromKey(InputChannelId channelId)
|
||||
{
|
||||
// note: remove hard-coded InputDevice keys
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericW)
|
||||
if (channelId == CameraTranslateForwardId)
|
||||
{
|
||||
return TranslationType::Forward;
|
||||
}
|
||||
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericS)
|
||||
if (channelId == CameraTranslateBackwardId)
|
||||
{
|
||||
return TranslationType::Backward;
|
||||
}
|
||||
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericA)
|
||||
if (channelId == CameraTranslateLeftId)
|
||||
{
|
||||
return TranslationType::Left;
|
||||
}
|
||||
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericD)
|
||||
if (channelId == CameraTranslateRightId)
|
||||
{
|
||||
return TranslationType::Right;
|
||||
}
|
||||
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericQ)
|
||||
if (channelId == CameraTranslateDownId)
|
||||
{
|
||||
return TranslationType::Down;
|
||||
}
|
||||
|
||||
if (channelId == InputDeviceKeyboard::Key::AlphanumericE)
|
||||
if (channelId == CameraTranslateUpId)
|
||||
{
|
||||
return TranslationType::Up;
|
||||
}
|
||||
@@ -242,7 +400,8 @@ namespace AzFramework
|
||||
return TranslationType::Nil;
|
||||
}
|
||||
|
||||
void TranslateCameraInput::HandleEvents(const InputEvent& event)
|
||||
void TranslateCameraInput::HandleEvents(
|
||||
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
|
||||
{
|
||||
if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
{
|
||||
@@ -259,19 +418,19 @@ namespace AzFramework
|
||||
BeginActivation();
|
||||
}
|
||||
|
||||
if (input->m_channelId == InputDeviceKeyboard::Key::ModifierShiftL)
|
||||
if (input->m_channelId == CameraTranslateBoostId)
|
||||
{
|
||||
m_boost = true;
|
||||
}
|
||||
}
|
||||
else if (input->m_state == InputChannel::State::Ended)
|
||||
{
|
||||
m_translation ^= translationFromKey(input->m_channelId);
|
||||
m_translation &= ~(translationFromKey(input->m_channelId));
|
||||
if (m_translation == TranslationType::Nil)
|
||||
{
|
||||
EndActivation();
|
||||
}
|
||||
if (input->m_channelId == InputDeviceKeyboard::Key::ModifierShiftL)
|
||||
if (input->m_channelId == CameraTranslateBoostId)
|
||||
{
|
||||
m_boost = false;
|
||||
}
|
||||
@@ -285,13 +444,13 @@ namespace AzFramework
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
|
||||
const auto translation_basis = m_translationAxesFn(nextCamera);
|
||||
const auto axisX = translation_basis.GetBasisX();
|
||||
const auto axisY = translation_basis.GetBasisY();
|
||||
const auto axisZ = translation_basis.GetBasisZ();
|
||||
const auto translationBasis = m_translationAxesFn(nextCamera);
|
||||
const auto axisX = translationBasis.GetBasisX();
|
||||
const auto axisY = translationBasis.GetBasisY();
|
||||
const auto axisZ = translationBasis.GetBasisZ();
|
||||
|
||||
const float speed = [boost = m_boost, props = m_props]() {
|
||||
return props.m_translateSpeed * (boost ? props.m_boostMultiplier : 1.0f);
|
||||
const float speed = [boost = m_boost]() {
|
||||
return ed_cameraSystemTranslateSpeed * (boost ? ed_cameraSystemBoostMultiplier : 1.0f);
|
||||
}();
|
||||
|
||||
if ((m_translation & TranslationType::Forward) == TranslationType::Forward)
|
||||
@@ -338,16 +497,12 @@ namespace AzFramework
|
||||
m_boost = false;
|
||||
}
|
||||
|
||||
void OrbitCameraInput::HandleEvents(const InputEvent& event)
|
||||
void OrbitCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta)
|
||||
{
|
||||
if (const auto* input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
{
|
||||
if (input->m_channelId == InputDeviceKeyboard::Key::ModifierAltL)
|
||||
if (input->m_channelId == CameraOrbitId)
|
||||
{
|
||||
if (input->m_state == InputChannel::State::Updated)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
if (input->m_state == InputChannel::State::Began)
|
||||
{
|
||||
BeginActivation();
|
||||
@@ -358,37 +513,39 @@ namespace AzFramework
|
||||
}
|
||||
}
|
||||
}
|
||||
end:
|
||||
|
||||
if (Active())
|
||||
{
|
||||
m_orbitCameras.HandleEvents(event);
|
||||
m_orbitCameras.HandleEvents(event, cursorDelta, scrollDelta);
|
||||
}
|
||||
}
|
||||
|
||||
Camera OrbitCameraInput::StepCamera(
|
||||
const Camera& targetCamera, const ScreenVector& cursorDelta, const float scrollDelta, float deltaTime)
|
||||
const Camera& targetCamera, const ScreenVector& cursorDelta, const float scrollDelta, const float deltaTime)
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
|
||||
if (Beginning())
|
||||
{
|
||||
float hit_distance = 0.0f;
|
||||
if (AZ::Plane::CreateFromNormalAndPoint(AZ::Vector3::CreateAxisZ(), AZ::Vector3::CreateZero())
|
||||
.CastRay(targetCamera.Translation(), targetCamera.Rotation().GetBasisY() * m_props.m_maxOrbitDistance, hit_distance))
|
||||
AZ::Plane::CreateFromNormalAndPoint(AZ::Vector3::CreateAxisZ(), AZ::Vector3::CreateAxisZ(ed_cameraSystemDefaultPlaneHeight))
|
||||
.CastRay(targetCamera.Translation(), targetCamera.Rotation().GetBasisY(), hit_distance);
|
||||
|
||||
if (hit_distance > 0.0f)
|
||||
{
|
||||
hit_distance = AZStd::min<float>(hit_distance, ed_cameraSystemMaxOrbitDistance);
|
||||
nextCamera.m_lookDist = -hit_distance;
|
||||
nextCamera.m_lookAt = targetCamera.Translation() + targetCamera.Rotation().GetBasisY() * hit_distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextCamera.m_lookDist = -m_props.m_defaultOrbitDistance;
|
||||
nextCamera.m_lookAt = targetCamera.Translation() + targetCamera.Rotation().GetBasisY() * m_props.m_defaultOrbitDistance;
|
||||
nextCamera.m_lookDist = -ed_cameraSystemMaxOrbitDistance;
|
||||
nextCamera.m_lookAt = targetCamera.Translation() + targetCamera.Rotation().GetBasisY() * ed_cameraSystemMaxOrbitDistance;
|
||||
}
|
||||
}
|
||||
|
||||
if (Active())
|
||||
{
|
||||
// todo: need to return nested cameras to idle state when ending
|
||||
nextCamera = m_orbitCameras.StepCamera(nextCamera, cursorDelta, scrollDelta, deltaTime);
|
||||
}
|
||||
|
||||
@@ -403,7 +560,8 @@ namespace AzFramework
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
void OrbitDollyScrollCameraInput::HandleEvents(const InputEvent& event)
|
||||
void OrbitDollyScrollCameraInput::HandleEvents(
|
||||
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
|
||||
{
|
||||
if (const auto* scroll = AZStd::get_if<ScrollEvent>(&event))
|
||||
{
|
||||
@@ -413,19 +571,20 @@ namespace AzFramework
|
||||
|
||||
Camera OrbitDollyScrollCameraInput::StepCamera(
|
||||
const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, const float scrollDelta,
|
||||
[[maybe_unused]] float deltaTime)
|
||||
[[maybe_unused]] const float deltaTime)
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
nextCamera.m_lookDist = AZ::GetMin(nextCamera.m_lookDist + scrollDelta * m_props.m_dollySpeed, 0.0f);
|
||||
nextCamera.m_lookDist = AZ::GetMin(nextCamera.m_lookDist + scrollDelta * ed_cameraSystemOrbitDollyScrollSpeed, 0.0f);
|
||||
EndActivation();
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
void OrbitDollyCursorMoveCameraInput::HandleEvents(const InputEvent& event)
|
||||
void OrbitDollyCursorMoveCameraInput::HandleEvents(
|
||||
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
|
||||
{
|
||||
if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
|
||||
{
|
||||
if (input->m_channelId == InputDeviceMouse::Button::Right)
|
||||
if (input->m_channelId == m_dollyChannelId)
|
||||
{
|
||||
if (input->m_state == InputChannel::State::Began)
|
||||
{
|
||||
@@ -444,11 +603,12 @@ namespace AzFramework
|
||||
[[maybe_unused]] const float deltaTime)
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
nextCamera.m_lookDist = AZ::GetMin(nextCamera.m_lookDist + float(cursorDelta.m_y) * m_props.m_dollySpeed, 0.0f);
|
||||
nextCamera.m_lookDist = AZ::GetMin(nextCamera.m_lookDist + float(cursorDelta.m_y) * ed_cameraSystemOrbitDollyCursorSpeed, 0.0f);
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
void ScrollTranslationCameraInput::HandleEvents(const InputEvent& event)
|
||||
void ScrollTranslationCameraInput::HandleEvents(
|
||||
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
|
||||
{
|
||||
if (const auto* scroll = AZStd::get_if<ScrollEvent>(&event))
|
||||
{
|
||||
@@ -457,7 +617,7 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
Camera ScrollTranslationCameraInput::StepCamera(
|
||||
const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, float scrollDelta,
|
||||
const Camera& targetCamera, [[maybe_unused]] const ScreenVector& cursorDelta, const float scrollDelta,
|
||||
[[maybe_unused]] const float deltaTime)
|
||||
{
|
||||
Camera nextCamera = targetCamera;
|
||||
@@ -465,39 +625,40 @@ namespace AzFramework
|
||||
const auto translation_basis = LookTranslation(nextCamera);
|
||||
const auto axisY = translation_basis.GetBasisY();
|
||||
|
||||
nextCamera.m_lookAt += axisY * scrollDelta * m_props.m_translateSpeed;
|
||||
nextCamera.m_lookAt += axisY * scrollDelta * ed_cameraSystemScrollTranslateSpeed;
|
||||
|
||||
EndActivation();
|
||||
|
||||
return nextCamera;
|
||||
}
|
||||
|
||||
Camera SmoothCamera(const Camera& currentCamera, const Camera& targetCamera, const SmoothProps& props, const float deltaTime)
|
||||
Camera SmoothCamera(const Camera& currentCamera, const Camera& targetCamera, const float deltaTime)
|
||||
{
|
||||
const auto clamp_rotation = [](const float angle) { return std::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi); };
|
||||
const auto clamp_rotation = [](const float angle) { return AZStd::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi); };
|
||||
|
||||
// keep yaw in 0 - 360 range
|
||||
float target_yaw = clamp_rotation(targetCamera.m_yaw);
|
||||
const float current_yaw = clamp_rotation(currentCamera.m_yaw);
|
||||
float targetYaw = clamp_rotation(targetCamera.m_yaw);
|
||||
const float currentYaw = clamp_rotation(currentCamera.m_yaw);
|
||||
|
||||
auto sign = [](const float value) { return static_cast<float>((0.0f < value) - (value < 0.0f)); };
|
||||
// return the sign of the float input (-1, 0, 1)
|
||||
const auto sign = [](const float value) { return aznumeric_cast<float>((0.0f < value) - (value < 0.0f)); };
|
||||
|
||||
// ensure smooth transition when moving across 0 - 360 boundary
|
||||
const float yaw_delta = target_yaw - current_yaw;
|
||||
if (std::abs(yaw_delta) >= AZ::Constants::Pi)
|
||||
const float yawDelta = targetYaw - currentYaw;
|
||||
if (AZStd::abs(yawDelta) >= AZ::Constants::Pi)
|
||||
{
|
||||
target_yaw -= AZ::Constants::TwoPi * sign(yaw_delta);
|
||||
targetYaw -= AZ::Constants::TwoPi * sign(yawDelta);
|
||||
}
|
||||
|
||||
Camera camera;
|
||||
// note: the math for the lerp smoothing implementation for camera rotation and translation was inspired by this excellent
|
||||
// note: the math for the lerp smoothing implementation for camera rotation and translation was inspired by this excellent
|
||||
// article by Scott Lembcke: https://www.gamasutra.com/blogs/ScottLembcke/20180404/316046/Improved_Lerp_Smoothing.php
|
||||
const float lookRate = std::exp2(props.m_lookSmoothness);
|
||||
const float lookT = std::exp2(-lookRate * deltaTime);
|
||||
const float lookRate = AZStd::exp2(ed_cameraSystemLookSmoothness);
|
||||
const float lookT = AZStd::exp2(-lookRate * deltaTime);
|
||||
camera.m_pitch = AZ::Lerp(targetCamera.m_pitch, currentCamera.m_pitch, lookT);
|
||||
camera.m_yaw = AZ::Lerp(target_yaw, current_yaw, lookT);
|
||||
const float moveRate = std::exp2(props.m_moveSmoothness);
|
||||
const float moveT = std::exp2(-moveRate * deltaTime);
|
||||
camera.m_yaw = AZ::Lerp(targetYaw, currentYaw, lookT);
|
||||
const float moveRate = AZStd::exp2(ed_cameraSystemTranslateSmoothness);
|
||||
const float moveT = AZStd::exp2(-moveRate * deltaTime);
|
||||
camera.m_lookDist = AZ::Lerp(targetCamera.m_lookDist, currentCamera.m_lookDist, moveT);
|
||||
camera.m_lookAt = targetCamera.m_lookAt.Lerp(currentCamera.m_lookAt, moveT);
|
||||
return camera;
|
||||
@@ -508,20 +669,24 @@ namespace AzFramework
|
||||
const auto& inputChannelId = inputChannel.GetInputChannelId();
|
||||
const auto& inputDeviceId = inputChannel.GetInputDevice().GetInputDeviceId();
|
||||
|
||||
if (inputChannelId == InputDeviceMouse::SystemCursorPosition)
|
||||
{
|
||||
AZ::Vector2 systemCursorPositionNormalized = AZ::Vector2::CreateZero();
|
||||
InputSystemCursorRequestBus::EventResult(
|
||||
systemCursorPositionNormalized, inputDeviceId, &InputSystemCursorRequestBus::Events::GetSystemCursorPositionNormalized);
|
||||
const bool wasMouseButton =
|
||||
AZStd::any_of(InputDeviceMouse::Button::All.begin(), InputDeviceMouse::Button::All.end(), [inputChannelId](const auto& button) {
|
||||
return button == inputChannelId;
|
||||
});
|
||||
|
||||
return CursorMotionEvent{ScreenPoint(
|
||||
systemCursorPositionNormalized.GetX() * windowSize.m_width, systemCursorPositionNormalized.GetY() * windowSize.m_height)};
|
||||
if (inputChannelId == InputDeviceMouse::Movement::X || inputChannelId == InputDeviceMouse::Movement::Y)
|
||||
{
|
||||
const auto* position = inputChannel.GetCustomData<AzFramework::InputChannel::PositionData2D>();
|
||||
AZ_Assert(position, "Expected PositionData2D but found nullptr");
|
||||
|
||||
return CursorEvent{ScreenPoint(
|
||||
position->m_normalizedPosition.GetX() * windowSize.m_width, position->m_normalizedPosition.GetY() * windowSize.m_height)};
|
||||
}
|
||||
else if (inputChannelId == InputDeviceMouse::Movement::Z)
|
||||
{
|
||||
return ScrollEvent{inputChannel.GetValue()};
|
||||
}
|
||||
else if (InputDeviceMouse::IsMouseDevice(inputDeviceId) || InputDeviceKeyboard::IsKeyboardDevice(inputDeviceId))
|
||||
else if (wasMouseButton || InputDeviceKeyboard::IsKeyboardDevice(inputDeviceId))
|
||||
{
|
||||
return DiscreteInputEvent{inputChannelId, inputChannel.GetState()};
|
||||
}
|
||||
|
||||
@@ -17,13 +17,16 @@
|
||||
#include <AzCore/std/containers/variant.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzFramework/Input/Channels/InputChannel.h>
|
||||
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
|
||||
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
|
||||
#include <AzFramework/Viewport/ScreenGeometry.h>
|
||||
#include <AzFramework/Viewport/ViewportId.h>
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
struct WindowSize;
|
||||
//! Update camera key bindings that can be overridden with AZ console vars (invoke from console to update)
|
||||
void ReloadCameraKeyBindings();
|
||||
|
||||
//! Return Euler angles (pitch, roll, yaw) for the incoming orientation.
|
||||
AZ::Vector3 EulerAngles(const AZ::Matrix3x3& orientation);
|
||||
|
||||
struct Camera
|
||||
{
|
||||
@@ -51,8 +54,8 @@ namespace AzFramework
|
||||
|
||||
inline AZ::Transform Camera::Transform() const
|
||||
{
|
||||
return AZ::Transform::CreateTranslation(m_lookAt) * AZ::Transform::CreateRotationX(m_pitch) *
|
||||
AZ::Transform::CreateRotationZ(m_yaw) * AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisZ(m_lookDist));
|
||||
return AZ::Transform::CreateTranslation(m_lookAt) * AZ::Transform::CreateRotationZ(m_yaw) *
|
||||
AZ::Transform::CreateRotationX(m_pitch) * AZ::Transform::CreateTranslation(AZ::Vector3::CreateAxisY(m_lookDist));
|
||||
}
|
||||
|
||||
inline AZ::Matrix3x3 Camera::Rotation() const
|
||||
@@ -65,7 +68,9 @@ namespace AzFramework
|
||||
return Transform().GetTranslation();
|
||||
}
|
||||
|
||||
struct CursorMotionEvent
|
||||
void UpdateCameraFromTransform(Camera& camera, const AZ::Transform& transform);
|
||||
|
||||
struct CursorEvent
|
||||
{
|
||||
ScreenPoint m_position;
|
||||
};
|
||||
@@ -81,7 +86,7 @@ namespace AzFramework
|
||||
InputChannel::State m_state; //!< Channel state. (e.g. Begin/update/end event).
|
||||
};
|
||||
|
||||
using InputEvent = AZStd::variant<AZStd::monostate, CursorMotionEvent, ScrollEvent, DiscreteInputEvent>;
|
||||
using InputEvent = AZStd::variant<AZStd::monostate, CursorEvent, ScrollEvent, DiscreteInputEvent>;
|
||||
|
||||
class CameraInput
|
||||
{
|
||||
@@ -142,7 +147,7 @@ namespace AzFramework
|
||||
ResetImpl();
|
||||
}
|
||||
|
||||
virtual void HandleEvents(const InputEvent& event) = 0;
|
||||
virtual void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) = 0;
|
||||
virtual Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) = 0;
|
||||
|
||||
virtual bool Exclusive() const
|
||||
@@ -159,19 +164,13 @@ namespace AzFramework
|
||||
Activation m_activation = Activation::Idle;
|
||||
};
|
||||
|
||||
struct SmoothProps
|
||||
{
|
||||
float m_lookSmoothness = 5.0f;
|
||||
float m_moveSmoothness = 5.0f;
|
||||
};
|
||||
|
||||
Camera SmoothCamera(const Camera& currentCamera, const Camera& targetCamera, const SmoothProps& props, float deltaTime);
|
||||
Camera SmoothCamera(const Camera& currentCamera, const Camera& targetCamera, float deltaTime);
|
||||
|
||||
class Cameras
|
||||
{
|
||||
public:
|
||||
void AddCamera(AZStd::shared_ptr<CameraInput> cameraInput);
|
||||
void HandleEvents(const InputEvent& event);
|
||||
bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta);
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime);
|
||||
void Reset();
|
||||
|
||||
@@ -183,7 +182,7 @@ namespace AzFramework
|
||||
class CameraSystem
|
||||
{
|
||||
public:
|
||||
void HandleEvents(const InputEvent& event);
|
||||
bool HandleEvents(const InputEvent& event);
|
||||
Camera StepCamera(const Camera& targetCamera, float deltaTime);
|
||||
|
||||
Cameras m_cameras;
|
||||
@@ -197,19 +196,18 @@ namespace AzFramework
|
||||
class RotateCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
explicit RotateCameraInput(const InputChannelId channelId)
|
||||
: m_channelId(channelId)
|
||||
explicit RotateCameraInput(const InputChannelId rotateChannelId)
|
||||
: m_rotateChannelId(rotateChannelId)
|
||||
{
|
||||
}
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
InputChannelId m_channelId;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_rotateSpeed = 0.005f;
|
||||
} m_props;
|
||||
private:
|
||||
InputChannelId m_rotateChannelId;
|
||||
float m_moveAccumulator = 0.0f;
|
||||
bool m_tryingToBegin = false;
|
||||
};
|
||||
|
||||
struct PanAxes
|
||||
@@ -242,22 +240,17 @@ namespace AzFramework
|
||||
class PanCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
explicit PanCameraInput(PanAxesFn panAxesFn)
|
||||
PanCameraInput(const InputChannelId panChannelId, PanAxesFn panAxesFn)
|
||||
: m_panAxesFn(AZStd::move(panAxesFn))
|
||||
, m_panChannelId(panChannelId)
|
||||
{
|
||||
}
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_panSpeed = 0.01f;
|
||||
bool m_panInvertX = true;
|
||||
bool m_panInvertY = true;
|
||||
} m_props;
|
||||
|
||||
private:
|
||||
PanAxesFn m_panAxesFn;
|
||||
InputChannelId m_panChannelId;
|
||||
};
|
||||
|
||||
using TranslationAxesFn = AZStd::function<AZ::Matrix3x3(const Camera& camera)>;
|
||||
@@ -294,21 +287,15 @@ namespace AzFramework
|
||||
: m_translationAxesFn(AZStd::move(translationAxesFn))
|
||||
{
|
||||
}
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
void ResetImpl() override;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_translateSpeed = 10.0f;
|
||||
float m_boostMultiplier = 3.0f;
|
||||
} m_props;
|
||||
|
||||
private:
|
||||
enum class TranslationType
|
||||
{
|
||||
// clang-format off
|
||||
Nil = 0,
|
||||
Nil = 0,
|
||||
Forward = 1 << 0,
|
||||
Backward = 1 << 1,
|
||||
Left = 1 << 2,
|
||||
@@ -354,6 +341,11 @@ namespace AzFramework
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend TranslationType operator~(const TranslationType lhs)
|
||||
{
|
||||
return static_cast<TranslationType>(~static_cast<std::underlying_type_t<TranslationType>>(lhs));
|
||||
}
|
||||
|
||||
static TranslationType translationFromKey(InputChannelId channelId);
|
||||
|
||||
TranslationType m_translation = TranslationType::Nil;
|
||||
@@ -364,43 +356,34 @@ namespace AzFramework
|
||||
class OrbitDollyScrollCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_dollySpeed = 0.2f;
|
||||
} m_props;
|
||||
};
|
||||
|
||||
class OrbitDollyCursorMoveCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
explicit OrbitDollyCursorMoveCameraInput(const InputChannelId dollyChannelId)
|
||||
: m_dollyChannelId(dollyChannelId) {}
|
||||
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_dollySpeed = 0.1f;
|
||||
} m_props;
|
||||
private:
|
||||
InputChannelId m_dollyChannelId;
|
||||
};
|
||||
|
||||
class ScrollTranslationCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_translateSpeed = 0.2f;
|
||||
} m_props;
|
||||
};
|
||||
|
||||
class OrbitCameraInput : public CameraInput
|
||||
{
|
||||
public:
|
||||
void HandleEvents(const InputEvent& event) override;
|
||||
void HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
|
||||
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
|
||||
bool Exclusive() const override
|
||||
{
|
||||
@@ -408,13 +391,10 @@ namespace AzFramework
|
||||
}
|
||||
|
||||
Cameras m_orbitCameras;
|
||||
|
||||
struct Props
|
||||
{
|
||||
float m_defaultOrbitDistance = 15.0f;
|
||||
float m_maxOrbitDistance = 100.0f;
|
||||
} m_props;
|
||||
};
|
||||
|
||||
struct WindowSize;
|
||||
|
||||
//! Map from a generic InputChannel event to a camera specific InputEvent.
|
||||
InputEvent BuildInputEvent(const InputChannel& inputChannel, const WindowSize& windowSize);
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -48,15 +48,21 @@ namespace AzFramework
|
||||
};
|
||||
|
||||
//! The interface used by MultiViewportController to manage individual instances.
|
||||
template <class TController>
|
||||
class MultiViewportControllerInstanceInterface
|
||||
{
|
||||
public:
|
||||
explicit MultiViewportControllerInstanceInterface(ViewportId viewport)
|
||||
using ControllerType = TController;
|
||||
|
||||
MultiViewportControllerInstanceInterface(ViewportId viewport, ControllerType* controller)
|
||||
: m_viewportId(viewport)
|
||||
, m_controller(controller)
|
||||
{
|
||||
}
|
||||
|
||||
ViewportId GetViewportId() const { return m_viewportId; }
|
||||
ControllerType* GetController() { return m_controller; }
|
||||
const ControllerType* GetController() const { return m_controller; }
|
||||
|
||||
virtual bool HandleInputChannelEvent([[maybe_unused]]const ViewportControllerInputEvent& event) { return false; }
|
||||
virtual void ResetInputChannels() {}
|
||||
@@ -64,6 +70,7 @@ namespace AzFramework
|
||||
|
||||
private:
|
||||
ViewportId m_viewportId;
|
||||
ControllerType* m_controller;
|
||||
};
|
||||
} //namespace AzFramework
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace AzFramework
|
||||
MultiViewportController<TViewportControllerInstance, Priority>::~MultiViewportController()
|
||||
{
|
||||
static_assert(
|
||||
AZStd::is_constructible<TViewportControllerInstance, ViewportId>::value,
|
||||
"TViewportControllerInstance must implement a TViewportControllerInstance(ViewportId) constructor"
|
||||
AZStd::is_same<TViewportControllerInstance, decltype(TViewportControllerInstance(0, nullptr))>::value,
|
||||
"TViewportControllerInstance must implement a TViewportControllerInstance(ViewportId, ViewportController) constructor"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace AzFramework
|
||||
template <class TViewportControllerInstance, ViewportControllerPriority Priority>
|
||||
void MultiViewportController<TViewportControllerInstance, Priority>::RegisterViewportContext(ViewportId viewport)
|
||||
{
|
||||
m_instances[viewport] = AZStd::make_unique<TViewportControllerInstance>(viewport);
|
||||
m_instances[viewport] = AZStd::make_unique<TViewportControllerInstance>(viewport, static_cast<typename TViewportControllerInstance::ControllerType*>(this));
|
||||
}
|
||||
|
||||
template <class TViewportControllerInstance, ViewportControllerPriority Priority>
|
||||
|
||||
@@ -134,11 +134,16 @@ namespace AzFramework
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
|
||||
inline float ScreenVectorLength(const ScreenVector& screenVector)
|
||||
{
|
||||
return aznumeric_cast<float>(AZStd::sqrt(screenVector.m_x * screenVector.m_x + screenVector.m_y * screenVector.m_y));
|
||||
}
|
||||
|
||||
inline ScreenPoint ScreenPointFromNDC(const AZ::Vector3& screenNDC, const AZ::Vector2& viewportSize)
|
||||
{
|
||||
return ScreenPoint(
|
||||
aznumeric_caster(std::round(screenNDC.GetX() * viewportSize.GetX())),
|
||||
aznumeric_caster(std::round((1.0f - screenNDC.GetY()) * viewportSize.GetY())));
|
||||
aznumeric_caster(AZStd::round(screenNDC.GetX() * viewportSize.GetX())),
|
||||
aznumeric_caster(AZStd::round((1.0f - screenNDC.GetY()) * viewportSize.GetY())));
|
||||
}
|
||||
|
||||
inline AZ::Vector2 NDCFromScreenPoint(const ScreenPoint& screenPoint, const AZ::Vector2& viewportSize)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Component/ComponentBus.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzFramework/Render/GeometryIntersectionStructures.h>
|
||||
@@ -27,7 +28,8 @@ namespace AZ
|
||||
namespace AzFramework
|
||||
{
|
||||
//! Implemented by components that provide bounds for use with various systems.
|
||||
class BoundsRequests : public AZ::ComponentBus
|
||||
class BoundsRequests
|
||||
: public AZ::ComponentBus
|
||||
{
|
||||
public:
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
@@ -37,6 +39,7 @@ namespace AzFramework
|
||||
//! more than one component may be providing a bound. It isn't guaranteed which bound
|
||||
//! will be returned by a single call to GetWorldBounds.
|
||||
virtual AZ::Aabb GetWorldBounds() = 0;
|
||||
|
||||
//! Returns an axis aligned bounding box in local space.
|
||||
//! @note It is preferred to use CalculateEntityLocalBoundsUnion in the general case as
|
||||
//! more than one component may be providing a bound. It isn't guaranteed which bound
|
||||
@@ -46,17 +49,15 @@ namespace AzFramework
|
||||
protected:
|
||||
~BoundsRequests() = default;
|
||||
};
|
||||
|
||||
using BoundsRequestBus = AZ::EBus<BoundsRequests>;
|
||||
|
||||
//! Returns a union of all local Aabbs provided by components implementing the BoundsRequestBus.
|
||||
//! @note It is preferred to call this function as opposed to GetLocalBounds directly as more than one
|
||||
//! component may be implementing this bus on an Entity and so only the first result (Aabb) will be returned.
|
||||
inline AZ::Aabb CalculateEntityLocalBoundsUnion(const AZ::EntityId entityId)
|
||||
inline AZ::Aabb CalculateEntityLocalBoundsUnion(const AZ::Entity* entity)
|
||||
{
|
||||
AZ::EBusReduceResult<AZ::Aabb, AabbUnionAggregator> aabbResult(AZ::Aabb::CreateNull());
|
||||
BoundsRequestBus::EventResult(
|
||||
aabbResult, entityId, &BoundsRequestBus::Events::GetLocalBounds);
|
||||
BoundsRequestBus::EventResult(aabbResult, entity->GetId(), &BoundsRequestBus::Events::GetLocalBounds);
|
||||
|
||||
if (aabbResult.value.IsValid())
|
||||
{
|
||||
@@ -69,18 +70,18 @@ namespace AzFramework
|
||||
//! Returns a union of all world Aabbs provided by components implementing the BoundsRequestBus.
|
||||
//! @note It is preferred to call this function as opposed to GetWorldBounds directly as more than one
|
||||
//! component may be implementing this bus on an Entity and so only the first result (Aabb) will be returned.
|
||||
inline AZ::Aabb CalculateEntityWorldBoundsUnion(const AZ::EntityId entityId)
|
||||
inline AZ::Aabb CalculateEntityWorldBoundsUnion(const AZ::Entity* entity)
|
||||
{
|
||||
AZ::EBusReduceResult<AZ::Aabb, AabbUnionAggregator> aabbResult(AZ::Aabb::CreateNull());
|
||||
BoundsRequestBus::EventResult(aabbResult, entityId, &BoundsRequestBus::Events::GetWorldBounds);
|
||||
BoundsRequestBus::EventResult(aabbResult, entity->GetId(), &BoundsRequestBus::Events::GetWorldBounds);
|
||||
|
||||
if (aabbResult.value.IsValid())
|
||||
{
|
||||
return aabbResult.value;
|
||||
}
|
||||
|
||||
AZ::Vector3 worldTranslation = AZ::Vector3::CreateZero();
|
||||
AZ::TransformBus::EventResult(worldTranslation, entityId, &AZ::TransformBus::Events::GetWorldTranslation);
|
||||
AZ::TransformInterface* transformInterface = entity->GetTransform();
|
||||
const AZ::Vector3 worldTranslation = transformInterface->GetWorldTranslation();
|
||||
return AZ::Aabb::CreateCenterHalfExtents(worldTranslation, AZ::Vector3(0.5f));
|
||||
}
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -23,9 +23,11 @@ namespace AzFramework
|
||||
{
|
||||
//! Provides an interface to retrieve and update the union of all Aabbs on a single Entity.
|
||||
//! @note This will be the combination/union of all individual Component Aabbs.
|
||||
class EntityBoundsUnionRequests : public AZ::EBusTraits
|
||||
class IEntityBoundsUnion
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(IEntityBoundsUnion, "{106968DD-43C0-478E-8045-523E0BF5D0F5}");
|
||||
|
||||
//! Requests the cached union of component Aabbs to be recalculated as one may have changed.
|
||||
//! @note This is used to drive event driven updates to the visibility system.
|
||||
virtual void RefreshEntityLocalBoundsUnion(AZ::EntityId entityId) = 0;
|
||||
@@ -38,9 +40,21 @@ namespace AzFramework
|
||||
//! also be called explicitly (e.g. For testing purposes).
|
||||
virtual void ProcessEntityBoundsUnionRequests() = 0;
|
||||
|
||||
//! Notifies the EntityBoundsUnion system that an entities transform has been modified.
|
||||
//! @param entity the entity whose transform has been modified.
|
||||
virtual void OnTransformUpdated(AZ::Entity* entity) = 0;
|
||||
|
||||
protected:
|
||||
~EntityBoundsUnionRequests() = default;
|
||||
~IEntityBoundsUnion() = default;
|
||||
};
|
||||
|
||||
using EntityBoundsUnionRequestBus = AZ::EBus<EntityBoundsUnionRequests>;
|
||||
// EBus wrapper for ScriptCanvas
|
||||
class IEntityBoundsUnionTraits
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
};
|
||||
using IEntityBoundsUnionRequestBus = AZ::EBus<IEntityBoundsUnion, IEntityBoundsUnionTraits>;
|
||||
} // namespace AzFramework
|
||||
|
||||
+57
-64
@@ -17,69 +17,70 @@
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
EntityVisibilityBoundsUnionSystem::EntityVisibilityBoundsUnionSystem()
|
||||
: m_entityActivatedEventHandler([this](AZ::Entity* entity) { OnEntityActivated(entity); })
|
||||
, m_entityDeactivatedEventHandler([this](AZ::Entity* entity) { OnEntityDeactivated(entity); })
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void EntityVisibilityBoundsUnionSystem::Connect()
|
||||
{
|
||||
EntityBoundsUnionRequestBus::Handler::BusConnect();
|
||||
AZ::TransformNotificationBus::Router::BusRouterConnect();
|
||||
AZ::EntitySystemBus::Handler::BusConnect();
|
||||
AZ::Interface<IEntityBoundsUnion>::Register(this);
|
||||
IEntityBoundsUnionRequestBus::Handler::BusConnect();
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
|
||||
AZ::Interface<AZ::ComponentApplicationRequests>::Get()->RegisterEntityActivatedEventHandler(m_entityActivatedEventHandler);
|
||||
AZ::Interface<AZ::ComponentApplicationRequests>::Get()->RegisterEntityDeactivatedEventHandler(m_entityDeactivatedEventHandler);
|
||||
}
|
||||
|
||||
void EntityVisibilityBoundsUnionSystem::Disconnect()
|
||||
{
|
||||
m_entityActivatedEventHandler.Disconnect();
|
||||
m_entityDeactivatedEventHandler.Disconnect();
|
||||
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
AZ::EntitySystemBus::Handler::BusDisconnect();
|
||||
AZ::TransformNotificationBus::Router::BusRouterDisconnect();
|
||||
EntityBoundsUnionRequestBus::Handler::BusDisconnect();
|
||||
IEntityBoundsUnionRequestBus::Handler::BusDisconnect();
|
||||
AZ::Interface<IEntityBoundsUnion>::Unregister(this);
|
||||
}
|
||||
|
||||
static void SetUserDataEntityId(VisibilityEntry& visibilityEntry, const AZ::EntityId entityId)
|
||||
{
|
||||
static_assert(
|
||||
sizeof(AZ::EntityId) <= sizeof(visibilityEntry.m_userData), "Ensure EntityId fits into m_userData");
|
||||
|
||||
visibilityEntry.m_typeFlags = VisibilityEntry::TYPE_Entity;
|
||||
|
||||
std::memcpy(&visibilityEntry.m_userData, &entityId, sizeof(AZ::EntityId));
|
||||
}
|
||||
|
||||
void EntityVisibilityBoundsUnionSystem::OnEntityActivated(const AZ::EntityId& entityId)
|
||||
void EntityVisibilityBoundsUnionSystem::OnEntityActivated(AZ::Entity* entity)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework);
|
||||
|
||||
// ignore any entity that might activate which does not have a TransformComponent
|
||||
if (!AZ::TransformBus::HasHandlers(entityId))
|
||||
if (entity->GetTransform() == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId);
|
||||
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
|
||||
instance_it == m_entityVisibilityBoundsUnionInstanceMapping.end())
|
||||
{
|
||||
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM);
|
||||
AZ::TransformInterface* transformInterface = entity->GetTransform();
|
||||
const AZ::Vector3 entityPosition = transformInterface->GetWorldTranslation();
|
||||
|
||||
EntityVisibilityBoundsUnionInstance instance;
|
||||
instance.m_worldTransform = worldFromLocal;
|
||||
instance.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entityId);
|
||||
SetUserDataEntityId(instance.m_visibilityEntry, entityId);
|
||||
instance.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entity);
|
||||
instance.m_visibilityEntry.m_typeFlags = VisibilityEntry::TYPE_Entity;
|
||||
instance.m_visibilityEntry.m_userData = static_cast<void*>(entity);
|
||||
|
||||
auto next_it = m_entityVisibilityBoundsUnionInstanceMapping.insert({entityId, instance});
|
||||
UpdateVisibilitySystem(next_it.first->second);
|
||||
auto next_it = m_entityVisibilityBoundsUnionInstanceMapping.insert({ entity, instance });
|
||||
UpdateVisibilitySystem(entity, next_it.first->second);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityVisibilityBoundsUnionSystem::OnEntityDeactivated(const AZ::EntityId& entityId)
|
||||
void EntityVisibilityBoundsUnionSystem::OnEntityDeactivated(AZ::Entity* entity)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework);
|
||||
|
||||
// ignore any entity that might deactivate which does not have a TransformComponent
|
||||
if (!AZ::TransformBus::HasHandlers(entityId))
|
||||
if (entity->GetTransform() == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId);
|
||||
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
|
||||
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
|
||||
{
|
||||
if (IVisibilitySystem* visibilitySystem = AZ::Interface<IVisibilitySystem>::Get())
|
||||
@@ -90,7 +91,7 @@ namespace AzFramework
|
||||
}
|
||||
}
|
||||
|
||||
void EntityVisibilityBoundsUnionSystem::UpdateVisibilitySystem(EntityVisibilityBoundsUnionInstance& instance)
|
||||
void EntityVisibilityBoundsUnionSystem::UpdateVisibilitySystem(AZ::Entity* entity, EntityVisibilityBoundsUnionInstance& instance)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework);
|
||||
|
||||
@@ -98,8 +99,8 @@ namespace AzFramework
|
||||
{
|
||||
// note: worldEntityBounds will not be a 'tight-fit' Aabb but that of a transformed local aabb
|
||||
// there will be some wasted space but it should be sufficient for the visibility system
|
||||
const AZ::Aabb worldEntityBoundsUnion =
|
||||
localEntityBoundsUnions.GetTransformedAabb(instance.m_worldTransform);
|
||||
AZ::TransformInterface* transformInterface = entity->GetTransform();
|
||||
const AZ::Aabb worldEntityBoundsUnion = localEntityBoundsUnions.GetTransformedAabb(transformInterface->GetWorldTM());
|
||||
IVisibilitySystem* visibilitySystem = AZ::Interface<IVisibilitySystem>::Get();
|
||||
if (visibilitySystem && !worldEntityBoundsUnion.IsClose(instance.m_visibilityEntry.m_boundingVolume))
|
||||
{
|
||||
@@ -111,19 +112,27 @@ namespace AzFramework
|
||||
|
||||
void EntityVisibilityBoundsUnionSystem::RefreshEntityLocalBoundsUnion(const AZ::EntityId entityId)
|
||||
{
|
||||
// track entities that need their bounds union to be recalculated
|
||||
m_entityIdsBoundsDirty.insert(entityId);
|
||||
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId);
|
||||
if (entity != nullptr)
|
||||
{
|
||||
// track entities that need their bounds union to be recalculated
|
||||
m_entityBoundsDirty.insert(entity);
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Aabb EntityVisibilityBoundsUnionSystem::GetEntityLocalBoundsUnion(const AZ::EntityId entityId) const
|
||||
{
|
||||
// if the EntityId is not found in the mapping then return a null Aabb, this is to mimic
|
||||
// as closely as possible the behavior of an individual GetLocalBounds call to an Entity that
|
||||
// had been deleted (there would be no response, leaving the default value assigned)
|
||||
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId);
|
||||
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
|
||||
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId);
|
||||
if (entity != nullptr)
|
||||
{
|
||||
return instance_it->second.m_localEntityBoundsUnion;
|
||||
// if the entity is not found in the mapping then return a null Aabb, this is to mimic
|
||||
// as closely as possible the behavior of an individual GetLocalBounds call to an Entity that
|
||||
// had been deleted (there would be no response, leaving the default value assigned)
|
||||
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
|
||||
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
|
||||
{
|
||||
return instance_it->second.m_localEntityBoundsUnion;
|
||||
}
|
||||
}
|
||||
|
||||
return AZ::Aabb::CreateNull();
|
||||
@@ -134,45 +143,29 @@ namespace AzFramework
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework);
|
||||
|
||||
// iterate over all entities whose bounds changed and recalculate them
|
||||
for (const auto& entityId : m_entityIdsBoundsDirty)
|
||||
for (const auto& entity : m_entityBoundsDirty)
|
||||
{
|
||||
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId);
|
||||
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
|
||||
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
|
||||
{
|
||||
instance_it->second.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entityId);
|
||||
}
|
||||
}
|
||||
|
||||
auto allDirtyEntityIds = m_entityIdsTransformDirty;
|
||||
allDirtyEntityIds.insert(m_entityIdsBoundsDirty.begin(), m_entityIdsBoundsDirty.end());
|
||||
|
||||
for (const auto& dirtyEntityId : allDirtyEntityIds)
|
||||
{
|
||||
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(dirtyEntityId);
|
||||
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
|
||||
{
|
||||
UpdateVisibilitySystem(instance_it->second);
|
||||
instance_it->second.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entity);
|
||||
UpdateVisibilitySystem(entity, instance_it->second);
|
||||
}
|
||||
}
|
||||
|
||||
// clear dirty entities once the visibility system has been updated
|
||||
m_entityIdsBoundsDirty.clear();
|
||||
m_entityIdsTransformDirty.clear();
|
||||
m_entityBoundsDirty.clear();
|
||||
}
|
||||
|
||||
void EntityVisibilityBoundsUnionSystem::OnTransformChanged(
|
||||
[[maybe_unused]] const AZ::Transform& local, const AZ::Transform& world)
|
||||
void EntityVisibilityBoundsUnionSystem::OnTransformUpdated(AZ::Entity* entity)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework);
|
||||
|
||||
const AZ::EntityId entityId = *AZ::TransformNotificationBus::GetCurrentBusId();
|
||||
m_entityIdsTransformDirty.insert(entityId);
|
||||
|
||||
// update the world transform of the visibility bounds union
|
||||
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entityId);
|
||||
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
|
||||
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
|
||||
{
|
||||
instance_it->second.m_worldTransform = world;
|
||||
UpdateVisibilitySystem(entity, instance_it->second);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-18
@@ -23,12 +23,12 @@ namespace AzFramework
|
||||
{
|
||||
//! Provide a unified hook between entities and the visibility system.
|
||||
class EntityVisibilityBoundsUnionSystem
|
||||
: public EntityBoundsUnionRequestBus::Handler
|
||||
, private AZ::EntitySystemBus::Handler
|
||||
, private AZ::TransformNotificationBus::Router
|
||||
: public IEntityBoundsUnionRequestBus::Handler
|
||||
, private AZ::TickBus::Handler
|
||||
{
|
||||
public:
|
||||
EntityVisibilityBoundsUnionSystem();
|
||||
|
||||
void Connect();
|
||||
void Disconnect();
|
||||
|
||||
@@ -36,34 +36,31 @@ namespace AzFramework
|
||||
void RefreshEntityLocalBoundsUnion(AZ::EntityId entityId) override;
|
||||
AZ::Aabb GetEntityLocalBoundsUnion(AZ::EntityId entityId) const override;
|
||||
void ProcessEntityBoundsUnionRequests() override;
|
||||
void OnTransformUpdated(AZ::Entity* entity) override;
|
||||
|
||||
private:
|
||||
struct EntityVisibilityBoundsUnionInstance
|
||||
{
|
||||
AZ::Transform m_worldTransform = AZ::Transform::CreateIdentity(); //!< The world transform of the Entity.
|
||||
AZ::Aabb m_localEntityBoundsUnion =
|
||||
AZ::Aabb::CreateNull(); //!< Entity union bounding volume in local space.
|
||||
AZ::Aabb m_localEntityBoundsUnion = AZ::Aabb::CreateNull(); //!< Entity union bounding volume in local space.
|
||||
VisibilityEntry m_visibilityEntry; //!< Hook into the IVisibilitySystem interface.
|
||||
};
|
||||
|
||||
using UniqueEntityIds = AZStd::unordered_set<AZ::EntityId>;
|
||||
using UniqueEntities = AZStd::set<AZ::Entity*>;
|
||||
using EntityVisibilityBoundsUnionInstanceMapping =
|
||||
AZStd::unordered_map<AZ::EntityId, EntityVisibilityBoundsUnionInstance>;
|
||||
AZStd::unordered_map<AZ::Entity*, EntityVisibilityBoundsUnionInstance>;
|
||||
|
||||
void OnEntityActivated(AZ::Entity* entity);
|
||||
void OnEntityDeactivated(AZ::Entity* entity);
|
||||
|
||||
// TickBus overrides ...
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
|
||||
// EntitySystemBus overrides ...
|
||||
void OnEntityActivated(const AZ::EntityId& entityId) override;
|
||||
void OnEntityDeactivated(const AZ::EntityId& entityId) override;
|
||||
|
||||
// TransformNotificationBus overrides ...
|
||||
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
|
||||
|
||||
void UpdateVisibilitySystem(EntityVisibilityBoundsUnionInstance& instance);
|
||||
void UpdateVisibilitySystem(AZ::Entity* entity, EntityVisibilityBoundsUnionInstance& instance);
|
||||
|
||||
EntityVisibilityBoundsUnionInstanceMapping m_entityVisibilityBoundsUnionInstanceMapping;
|
||||
UniqueEntityIds m_entityIdsBoundsDirty;
|
||||
UniqueEntityIds m_entityIdsTransformDirty;
|
||||
UniqueEntities m_entityBoundsDirty;
|
||||
|
||||
AZ::EntityActivatedEvent::Handler m_entityActivatedEventHandler;
|
||||
AZ::EntityDeactivatedEvent::Handler m_entityDeactivatedEventHandler;
|
||||
};
|
||||
} // namespace AzFramework
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <AzCore/Console/Console.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Math/ShapeIntersection.h>
|
||||
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
|
||||
#include <AzFramework/Visibility/IVisibilitySystem.h>
|
||||
@@ -66,6 +67,7 @@ namespace AzFramework
|
||||
octreeDebug.m_nodeBounds.push_back(nodeData.m_bounds);
|
||||
}
|
||||
|
||||
visibleEntityIdsOut.reserve(visibleEntityIdsOut.size() + nodeData.m_entries.size());
|
||||
for (const auto* visibilityEntry : nodeData.m_entries)
|
||||
{
|
||||
if (ed_visibility_showDebug)
|
||||
@@ -88,8 +90,7 @@ namespace AzFramework
|
||||
octreeDebug.m_entryAabbsInFrustum.push_back(visibilityEntry->m_boundingVolume);
|
||||
}
|
||||
|
||||
AZ::EntityId entityId;
|
||||
std::memcpy(&entityId, &visibilityEntry->m_userData, sizeof(AZ::EntityId));
|
||||
AZ::EntityId entityId = static_cast<AZ::Entity*>(visibilityEntry->m_userData)->GetId();
|
||||
visibleEntityIdsOut.push_back(entityId);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -14,7 +14,6 @@ set(FILES
|
||||
AzFrameworkModule.h
|
||||
AzFrameworkModule.cpp
|
||||
API/ApplicationAPI.h
|
||||
API/AtomActiveInterface.h
|
||||
Application/Application.cpp
|
||||
Application/Application.h
|
||||
Archive/Archive.cpp
|
||||
@@ -214,6 +213,12 @@ set(FILES
|
||||
StreamingInstall/StreamingInstall.cpp
|
||||
StreamingInstall/StreamingInstallRequests.h
|
||||
StreamingInstall/StreamingInstallNotifications.h
|
||||
Physics/Collision/CollisionEvents.h
|
||||
Physics/Collision/CollisionEvents.cpp
|
||||
Physics/Collision/CollisionLayers.h
|
||||
Physics/Collision/CollisionLayers.cpp
|
||||
Physics/Collision/CollisionGroups.h
|
||||
Physics/Collision/CollisionGroups.cpp
|
||||
Physics/Common/PhysicsSceneQueries.h
|
||||
Physics/Common/PhysicsSceneQueries.cpp
|
||||
Physics/Common/PhysicsEvents.h
|
||||
@@ -224,12 +229,7 @@ set(FILES
|
||||
Physics/Common/PhysicsSimulatedBodyEvents.h
|
||||
Physics/Common/PhysicsSimulatedBodyEvents.cpp
|
||||
Physics/Common/PhysicsTypes.h
|
||||
Physics/Collision/CollisionEvents.h
|
||||
Physics/Collision/CollisionEvents.cpp
|
||||
Physics/Collision/CollisionLayers.h
|
||||
Physics/Collision/CollisionLayers.cpp
|
||||
Physics/Collision/CollisionGroups.h
|
||||
Physics/Collision/CollisionGroups.cpp
|
||||
Physics/Components/SimulatedBodyComponentBus.h
|
||||
Physics/Configuration/CollisionConfiguration.h
|
||||
Physics/Configuration/CollisionConfiguration.cpp
|
||||
Physics/Configuration/RigidBodyConfiguration.h
|
||||
@@ -266,7 +266,6 @@ set(FILES
|
||||
Physics/ShapeConfiguration.h
|
||||
Physics/ShapeConfiguration.cpp
|
||||
Physics/SystemBus.h
|
||||
Physics/WorldBodyBus.h
|
||||
Physics/ColliderComponentBus.h
|
||||
Physics/RagdollPhysicsBus.h
|
||||
Physics/CharacterPhysicsDataBus.h
|
||||
|
||||
@@ -13,4 +13,3 @@
|
||||
#pragma once
|
||||
|
||||
#define STREAM_CACHE_DEFAULT 0
|
||||
#define FRONTEND_SHADER_CACHE_DEFAULT 0
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Utilities for iOS and Mac OS X. Needs to be separated
|
||||
// due to conflict with the system headers.
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_CRYSYSTEM_SYSTEMUTILSAPPLE_H
|
||||
#define CRYINCLUDE_CRYSYSTEM_SYSTEMUTILSAPPLE_H
|
||||
#pragma once
|
||||
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
namespace SystemUtilsApple
|
||||
{
|
||||
// Get the path to the application's bundle.
|
||||
// - Returns length of the string or 0 on failure.
|
||||
size_t GetPathToApplicationBundle(char* buffer, size_t bufferLen);
|
||||
|
||||
// Get the path to the application's executable.
|
||||
// - Returns length of the string or 0 on failure.
|
||||
size_t GetPathToApplicationExecutable(char* buffer, size_t bufferLen);
|
||||
|
||||
// Get the path to the application's resources.
|
||||
// - Returns length of the string or 0 on failure.
|
||||
size_t GetPathToApplicationResources(char* buffer, size_t bufferLen);
|
||||
|
||||
// Get the path to the user domain's application support directory.
|
||||
// - Returns length of the string or 0 on failure.
|
||||
// - Used to store application generated content.
|
||||
// - iOS: Not available through file sharing.
|
||||
// - Persistent, backed up by iTunes.
|
||||
size_t GetPathToUserApplicationSupportDirectory(char* buffer, size_t bufferLen);
|
||||
|
||||
// Get the path to the user domain's caches directory.
|
||||
// - Returns length of the string or 0 on failure.
|
||||
// - Used to store application generated content.
|
||||
// - iOS: Not available through file sharing.
|
||||
// - Temporary, not backed up by iTunes.
|
||||
size_t GetPathToUserCachesDirectory(char* buffer, size_t bufferLen);
|
||||
|
||||
// Get the path to the user domain's document directory.
|
||||
// - Returns length of the string or 0 on failure.
|
||||
// - Used to store user generated content.
|
||||
// - iOS: Available through file sharing.
|
||||
// - Persistent, backed up by iTunes.
|
||||
size_t GetPathToUserDocumentDirectory(char* buffer, size_t bufferLen);
|
||||
|
||||
// Get the path to the user domain's library directory.
|
||||
// - Returns length of the string or 0 on failure.
|
||||
// - Parent directory of app support and caches.
|
||||
// - iOS: Not available through file sharing.
|
||||
// - Persistent, backed up by iTunes.
|
||||
size_t GetPathToUserLibraryDirectory(char* buffer, size_t bufferLen);
|
||||
|
||||
// Get the user's name.
|
||||
// - Returns length of the string or 0 on failure.
|
||||
size_t GetUserName(char* buffer, size_t bufferLen);
|
||||
|
||||
// Get the device's machine name
|
||||
// - Returns string representing device identifier or empty string on failure
|
||||
// - Unique for each model
|
||||
AZStd::string GetMachineName();
|
||||
}
|
||||
|
||||
#endif // CRYINCLUDE_CRYSYSTEM_SYSTEMUTILSAPPLE_H
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "SystemUtilsApple.h"
|
||||
#include <AzCore/base.h>
|
||||
#include <AzCore/Debug/Trace.h>
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
namespace SystemUtilsApplePrivate
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Performs a 'safe' string copy from 'NString* source' to 'char* buffer' of 'size_t bufferLen'.
|
||||
// Returns the length of the string, or 0 if the buffer is not large enough to hold the source.
|
||||
// Copying an empty or null string will return 0, and null-terminate the buffer if possible.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
size_t CopyNSStringToBuffer(NSString* source, char* buffer, const size_t bufferLen)
|
||||
{
|
||||
if (!buffer || !bufferLen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (source)
|
||||
{
|
||||
const char* src = [source UTF8String];
|
||||
const size_t srcLen = strlen(src);
|
||||
if (srcLen < bufferLen - 1)
|
||||
{
|
||||
azstrncpy(buffer, bufferLen, src, srcLen);
|
||||
buffer[srcLen] = '\0';
|
||||
return srcLen;
|
||||
}
|
||||
}
|
||||
|
||||
// Could not copy the source to the destination buffer.
|
||||
buffer[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Get the path to the specified user domain directory.
|
||||
// Returns length of the string or 0 on failure.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
size_t GetPathToUserDirectory(NSSearchPathDirectory dir, char* buffer, const size_t bufferLen)
|
||||
{
|
||||
NSArray* userDomainDirectoryPaths = NSSearchPathForDirectoriesInDomains(dir, NSUserDomainMask, YES);
|
||||
if ([userDomainDirectoryPaths count] != 0)
|
||||
{
|
||||
NSString* userDomainDirectoryPath = static_cast<NSString*>([userDomainDirectoryPaths objectAtIndex:0]);
|
||||
return CopyNSStringToBuffer(userDomainDirectoryPath, buffer, bufferLen);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
size_t SystemUtilsApple::GetPathToApplicationBundle(char* buffer, const size_t bufferLen)
|
||||
{
|
||||
NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
|
||||
return SystemUtilsApplePrivate::CopyNSStringToBuffer(bundlePath, buffer, bufferLen);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
size_t SystemUtilsApple::GetPathToApplicationExecutable(char* buffer, const size_t bufferLen)
|
||||
{
|
||||
NSString* executablePath = [[NSBundle mainBundle] executablePath];
|
||||
return SystemUtilsApplePrivate::CopyNSStringToBuffer(executablePath, buffer, bufferLen);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
size_t SystemUtilsApple::GetPathToApplicationResources(char* buffer, const size_t bufferLen)
|
||||
{
|
||||
NSString* resourcesPath = [[NSBundle mainBundle] resourcePath];
|
||||
return SystemUtilsApplePrivate::CopyNSStringToBuffer(resourcesPath, buffer, bufferLen);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
size_t SystemUtilsApple::GetPathToUserApplicationSupportDirectory(char* buffer, const size_t bufferLen)
|
||||
{
|
||||
return SystemUtilsApplePrivate::GetPathToUserDirectory(NSApplicationSupportDirectory, buffer, bufferLen);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
size_t SystemUtilsApple::GetPathToUserCachesDirectory(char* buffer, const size_t bufferLen)
|
||||
{
|
||||
return SystemUtilsApplePrivate::GetPathToUserDirectory(NSCachesDirectory, buffer, bufferLen);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
size_t SystemUtilsApple::GetPathToUserDocumentDirectory(char* buffer, const size_t bufferLen)
|
||||
{
|
||||
return SystemUtilsApplePrivate::GetPathToUserDirectory(NSDocumentDirectory, buffer, bufferLen);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
size_t SystemUtilsApple::GetPathToUserLibraryDirectory(char* buffer, const size_t bufferLen)
|
||||
{
|
||||
return SystemUtilsApplePrivate::GetPathToUserDirectory(NSLibraryDirectory, buffer, bufferLen);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
size_t SystemUtilsApple::GetUserName(char* buffer, const size_t bufferLen)
|
||||
{
|
||||
return SystemUtilsApplePrivate::CopyNSStringToBuffer(NSUserName(), buffer, bufferLen);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
AZStd::string SystemUtilsApple::GetMachineName()
|
||||
{
|
||||
utsname systemInfo;
|
||||
if (uname(&systemInfo) == -1)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return systemInfo.machine;
|
||||
}
|
||||
@@ -13,4 +13,3 @@
|
||||
#pragma once
|
||||
|
||||
#define STREAM_CACHE_DEFAULT 0
|
||||
#define FRONTEND_SHADER_CACHE_DEFAULT 0
|
||||
|
||||
@@ -13,4 +13,3 @@
|
||||
#pragma once
|
||||
|
||||
#define STREAM_CACHE_DEFAULT 0
|
||||
#define FRONTEND_SHADER_CACHE_DEFAULT 0
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../../Common/Apple/AzFramework/Utils/SystemUtilsApple.h"
|
||||
@@ -36,4 +36,6 @@ set(FILES
|
||||
../Common/Unimplemented/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard_Unimplemented.cpp
|
||||
AzFramework/Archive/ArchiveVars_Platform.h
|
||||
AzFramework/Archive/ArchiveVars_Mac.h
|
||||
../Common/Apple/AzFramework/Utils/SystemUtilsApple.h
|
||||
../Common/Apple/AzFramework/Utils/SystemUtilsApple.mm
|
||||
)
|
||||
|
||||
@@ -13,4 +13,3 @@
|
||||
#pragma once
|
||||
|
||||
#define STREAM_CACHE_DEFAULT 0
|
||||
#define FRONTEND_SHADER_CACHE_DEFAULT 0
|
||||
|
||||
@@ -13,4 +13,3 @@
|
||||
#pragma once
|
||||
|
||||
#define STREAM_CACHE_DEFAULT 0
|
||||
#define FRONTEND_SHADER_CACHE_DEFAULT 0
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* 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 "../../../Common/Apple/AzFramework/Utils/SystemUtilsApple.h"
|
||||
@@ -36,5 +36,7 @@ set(FILES
|
||||
AzFramework/Process/ProcessCommon.h
|
||||
AzFramework/Process/ProcessWatcher_iOS.cpp
|
||||
AzFramework/Process/ProcessCommunicator_iOS.cpp
|
||||
../Common/Apple/AzFramework/Utils/SystemUtilsApple.h
|
||||
../Common/Apple/AzFramework/Utils/SystemUtilsApple.mm
|
||||
)
|
||||
|
||||
|
||||
+4
-3
@@ -38,8 +38,9 @@ namespace AzManipulatorTestFramework
|
||||
void SetGridSize(float size) override;
|
||||
void SetAngularStep(float step) override;
|
||||
int GetViewportId() const override;
|
||||
AZStd::optional<AZ::Vector3> ViewportScreenToWorld(const QPoint& screenPosition, float depth) override;
|
||||
AZStd::optional<AzToolsFramework::ViewportInteraction::ProjectedViewportRay> ViewportScreenToWorldRay(const QPoint& screenPosition) override;
|
||||
AZStd::optional<AZ::Vector3> ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition, float depth) override;
|
||||
AZStd::optional<AzToolsFramework::ViewportInteraction::ProjectedViewportRay> ViewportScreenToWorldRay(
|
||||
const AzFramework::ScreenPoint& screenPosition) override;
|
||||
private:
|
||||
// ViewportInteractionRequestBus ...
|
||||
bool GridSnappingEnabled();
|
||||
@@ -47,7 +48,7 @@ namespace AzManipulatorTestFramework
|
||||
bool ShowGrid();
|
||||
bool AngleSnappingEnabled();
|
||||
float AngleStep();
|
||||
QPoint ViewportWorldToScreen(const AZ::Vector3& worldPosition);
|
||||
AzFramework::ScreenPoint ViewportWorldToScreen(const AZ::Vector3& worldPosition);
|
||||
private:
|
||||
AZStd::unique_ptr<NullDebugDisplayRequests> m_nullDebugDisplayRequests;
|
||||
const int m_viewportId = 1234; // Arbitrary viewport id for manipulator tests
|
||||
|
||||
@@ -66,10 +66,9 @@ namespace AzManipulatorTestFramework
|
||||
return m_angularStep;
|
||||
}
|
||||
|
||||
QPoint ViewportInteraction::ViewportWorldToScreen(const AZ::Vector3& worldPosition)
|
||||
AzFramework::ScreenPoint ViewportInteraction::ViewportWorldToScreen(const AZ::Vector3& worldPosition)
|
||||
{
|
||||
auto pos = AzFramework::WorldToScreen(worldPosition, m_cameraState);
|
||||
return QPoint(pos.m_x, pos.m_y);
|
||||
return AzFramework::WorldToScreen(worldPosition, m_cameraState);
|
||||
}
|
||||
|
||||
void ViewportInteraction::SetCameraState(const AzFramework::CameraState& cameraState)
|
||||
@@ -117,12 +116,14 @@ namespace AzManipulatorTestFramework
|
||||
return m_viewportId;
|
||||
}
|
||||
|
||||
AZStd::optional<AZ::Vector3> ViewportInteraction::ViewportScreenToWorld([[maybe_unused]]const QPoint& screenPosition, [[maybe_unused]]float depth)
|
||||
AZStd::optional<AZ::Vector3> ViewportInteraction::ViewportScreenToWorld(
|
||||
[[maybe_unused]] const AzFramework::ScreenPoint& screenPosition, [[maybe_unused]] float depth)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
AZStd::optional<AzToolsFramework::ViewportInteraction::ProjectedViewportRay> ViewportInteraction::ViewportScreenToWorldRay([[maybe_unused]]const QPoint& screenPosition)
|
||||
AZStd::optional<AzToolsFramework::ViewportInteraction::ProjectedViewportRay> ViewportInteraction::ViewportScreenToWorldRay(
|
||||
[[maybe_unused]] const AzFramework::ScreenPoint& screenPosition)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -19,9 +19,10 @@ namespace AzNetworking
|
||||
static const int32_t FloatHashMinValue = (INT_MIN >> 7);
|
||||
static const int32_t FloatHashMaxValue = (INT_MAX >> 7);
|
||||
|
||||
AZ::HashValue64 HashSerializer::GetHash() const
|
||||
AZ::HashValue32 HashSerializer::GetHash() const
|
||||
{
|
||||
return m_hash;
|
||||
// Just truncate the upper bits
|
||||
return static_cast<AZ::HashValue32>(m_hash);
|
||||
}
|
||||
|
||||
SerializerMode HashSerializer::GetSerializerMode() const
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user