merge from main

This commit is contained in:
greerdv
2021-05-19 12:14:25 +01:00
11816 changed files with 189923 additions and 1002401 deletions
-1
View File
@@ -1 +0,0 @@
*.xml
@@ -26,4 +26,4 @@ namespace AZ
template <typename T>
using Instance = AZStd::intrusive_ptr<T>;
}
}
}
@@ -60,4 +60,4 @@ namespace AZ
return m_guid != rhs.m_guid || m_subId != rhs.m_subId;
}
}
}
}
@@ -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);
@@ -35,4 +35,4 @@ namespace AZStd
base_type::assign(list.begin(), list.end());
}
};
}
}
@@ -158,4 +158,4 @@ namespace AZStd
/// Old elements will be evicted if the capacity is exceeded.
size_t m_capacity = 0;
};
} // namespace AZStd
} // namespace AZStd
@@ -76,4 +76,4 @@ namespace AZStd
base_type::m_container.set_allocator(allocator);
}
};
}
}
@@ -231,4 +231,4 @@ namespace AZStd
protected:
RandomAccessContainer m_container;
};
}
}
@@ -20,10 +20,12 @@
namespace AZStd
{
//! Simple class for verifying that no concurrent access is occuring.
//! Simple class for verifying that no concurrent access is occurring.
//! This is *not* a synchronization primitive, and is intended simply for checking that no concurrency issues exist.
//! It will be compiled out in release builds.
//! Use concurrency_checker like a mutex (i.e. call soft_lock() and soft_unlock() around all instances of your data access).
//! Use soft_lock_shared and soft_unlock_shared around places where multiple threads are allowed to have read access
//! at the same time as long as nothing else already has a soft lock
//! It will assert if there are multiple threads accessing the locked code/data at the same time.
//! Expected use case is for defensive programming: when you do not expect any concurrent access within a system,
//! but want to verify that it stays that way in the future, without incurring the overhead of a mutex.
@@ -34,7 +36,7 @@ namespace AZStd
{
#ifdef AZ_CONCURRENCY_CHECKER_ENABLED
uint32_t count = ++m_concurrencyCounter;
AZ_Assert(count == 1, "Concurrency check failed. Multiple threads are trying to access data at the same time, or there is a lock/unlock mismatch.");
AZ_Assert(count == 1 && m_sharedConcurrencyCounter == 0, "Concurrency check failed. Multiple threads are trying to access data at the same time, or there is a lock/unlock mismatch.");
#endif
}
@@ -46,9 +48,27 @@ namespace AZStd
#endif
}
AZ_FORCE_INLINE void soft_lock_shared()
{
#ifdef AZ_CONCURRENCY_CHECKER_ENABLED
AZ_Assert(m_concurrencyCounter == 0, "Concurrency check failed. A soft_lock_shared was attempted when there was already a soft_lock.");
++m_sharedConcurrencyCounter;
#endif
}
AZ_FORCE_INLINE void soft_unlock_shared()
{
#ifdef AZ_CONCURRENCY_CHECKER_ENABLED
AZ_Assert(m_sharedConcurrencyCounter != 0, "Concurrency check failed. There is a shared_lock/shared_unlock mismatch.");
--m_sharedConcurrencyCounter;
#endif
}
private:
#ifdef AZ_CONCURRENCY_CHECKER_ENABLED
AZStd::atomic_uint32_t m_concurrencyCounter = 0;
AZStd::atomic_uint32_t m_sharedConcurrencyCounter = 0;
#endif
};
+2 -5
View File
@@ -293,15 +293,12 @@ namespace UnitTest
{
array_view<int> view({ 1,2,3,4 });
UnitTest::TestRunner::Instance().StartAssertTests();
AZ_TEST_START_TRACE_SUPPRESSION;
EXPECT_EQ(0, UnitTest::TestRunner::Instance().m_numAssertsFailed);
view[4];
EXPECT_EQ(1, UnitTest::TestRunner::Instance().m_numAssertsFailed);
view[5];
EXPECT_EQ(2, UnitTest::TestRunner::Instance().m_numAssertsFailed);
UnitTest::TestRunner::Instance().StopAssertTests();
AZ_TEST_STOP_TRACE_SUPPRESSION(2);
}
}
@@ -0,0 +1,100 @@
/*
* 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 <AtomCore/std/parallel/concurrency_checker.h>
#include <AzCore/UnitTest/TestTypes.h>
using namespace AZStd;
namespace UnitTest
{
class ConcurrencyCheckerTestFixture
: public AllocatorsTestFixture
{
void SetUp() override
{
AllocatorsFixture::SetUp();
}
};
TEST_F(AllocatorsTestFixture, SoftLock_NoContention_NoAsserts)
{
concurrency_checker concurrencyChecker;
concurrencyChecker.soft_lock();
concurrencyChecker.soft_unlock();
concurrencyChecker.soft_lock();
concurrencyChecker.soft_unlock();
}
TEST_F(AllocatorsTestFixture, SoftLock_AlreadyLocked_Assert)
{
concurrency_checker concurrencyChecker;
concurrencyChecker.soft_lock();
AZ_TEST_START_TRACE_SUPPRESSION;
concurrencyChecker.soft_lock();
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
}
TEST_F(AllocatorsTestFixture, SoftUnlock_NotAlreadyLocked_Assert)
{
concurrency_checker concurrencyChecker;
concurrencyChecker.soft_lock();
concurrencyChecker.soft_unlock();
AZ_TEST_START_TRACE_SUPPRESSION;
concurrencyChecker.soft_unlock();
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
}
TEST_F(AllocatorsTestFixture, SoftLockShared_NoContention_NoAsserts)
{
concurrency_checker concurrencyChecker;
// Multiple shared locks can be made at once,
// as long as they are all unlocked before the next soft_lock
concurrencyChecker.soft_lock_shared();
concurrencyChecker.soft_lock_shared();
concurrencyChecker.soft_unlock_shared();
concurrencyChecker.soft_unlock_shared();
concurrencyChecker.soft_lock();
concurrencyChecker.soft_unlock();
concurrencyChecker.soft_lock_shared();
concurrencyChecker.soft_lock_shared();
concurrencyChecker.soft_unlock_shared();
concurrencyChecker.soft_unlock_shared();
concurrencyChecker.soft_lock();
concurrencyChecker.soft_unlock();
}
TEST_F(AllocatorsTestFixture, SoftLockShared_SharedLockAfterSoftLock_Assert)
{
concurrency_checker concurrencyChecker;
concurrencyChecker.soft_lock();
AZ_TEST_START_TRACE_SUPPRESSION;
concurrencyChecker.soft_lock_shared();
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
}
TEST_F(AllocatorsTestFixture, SoftUnlockShared_NotAlreadyLocked_Assert)
{
concurrency_checker concurrencyChecker;
concurrencyChecker.soft_lock_shared();
concurrencyChecker.soft_unlock_shared();
AZ_TEST_START_TRACE_SUPPRESSION;
concurrencyChecker.soft_unlock_shared();
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
}
}
@@ -11,9 +11,10 @@
set(FILES
ArrayView.cpp
ConcurrencyCheckerTests.cpp
InstanceDatabase.cpp
JsonSerializationUtilsTests.cpp
lru_cache.cpp
Main.cpp
vector_set.cpp
)
)
+1 -1
View File
@@ -169,4 +169,4 @@ namespace UnitTest
intintptr_cache.clear();
EXPECT_EQ(p->use_count(), 1);
}
}
}
+1 -1
View File
@@ -282,4 +282,4 @@ namespace UnitTest
VectorSetTester<AZStd::fixed_vector_set<int32_t, 64>> tester;
tester.TestIteratorsConst();
}
}
}
@@ -193,4 +193,4 @@ public class KeyboardHandler
private Activity m_activity;
private InputMethodManager m_inputManager;
private DummyTextView m_textView;
}
}
@@ -88,4 +88,4 @@ public class APKHandler
private static AssetManager s_assetManager = null;
private static boolean s_debug = false;
}
}
@@ -320,4 +320,4 @@ public class ObbDownloaderActivity extends Activity implements IDownloaderClient
private int m_buttonPauseTextId;
private int m_kbPerSecondTextId;
private int m_timeRemainingTextId;
}
}
@@ -37,4 +37,4 @@ public class ObbDownloaderAlarmReceiver extends BroadcastReceiver
e.printStackTrace();
}
}
}
}
@@ -75,4 +75,4 @@ public class ObbDownloaderService extends DownloaderService
private byte[] m_salt = new byte[] { 23, 12, 4, -12, -34, 23,
-120, 122, -23, -104, -2, -4, 12, 3, -21, 123, -11, 4, -11, 32
};
}
}
@@ -84,4 +84,4 @@ public class SimpleObject
// ----
private static final String TAG = "SimpleObject";
}
}
@@ -11,4 +11,4 @@
set(FILES
AzAutoGen.py
)
)
-1
View File
@@ -1 +0,0 @@
*.xml
@@ -417,4 +417,4 @@ namespace AZ
return true;
}
}
}
}
@@ -219,4 +219,4 @@ namespace AZ
bool m_isRunning; //!< Internal flag indicating if the application is running, mainly used to determine if we shoudl be blocking on the event pump while paused
};
} // namespace Android
} // namespace AZ
} // namespace AZ
@@ -485,4 +485,4 @@ namespace AZ { namespace Android
} // namespace AZ
#include <AzCore/Android/JNI/Internal/Object_impl.h>
#include <AzCore/Android/JNI/Internal/Object_impl.h>
@@ -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
{
@@ -308,6 +307,8 @@ namespace AZ
Asset(AssetLoadBehavior loadBehavior = AssetLoadBehavior::Default);
/// Create an asset from a valid asset data (created asset), might not be loaded or currently loading.
Asset(AssetData* assetData, AssetLoadBehavior loadBehavior);
/// Create an asset from a valid asset data (created asset) and set the asset id for both, might not be loaded or currently loading.
Asset(const AZ::Data::AssetId& id, AssetData* assetData, AssetLoadBehavior loadBehavior);
/// Initialize asset pointer with id, type, and hint. No data construction will occur until QueueLoad is called.
Asset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type, const AZStd::string& hint = AZStd::string());
@@ -788,6 +789,18 @@ namespace AZ
SetData(assetData);
}
//=========================================================================
template<class T>
Asset<T>::Asset(const AssetId& id, AssetData* assetData, AssetLoadBehavior loadBehavior)
: m_assetId(id)
, m_assetType(azrtti_typeid<T>())
, m_loadBehavior(loadBehavior)
{
AZ_Assert(!assetData->m_assetId.IsValid(), "Asset data already has an ID set.");
assetData->m_assetId = id;
SetData(assetData);
}
//=========================================================================
template<class T>
Asset<T>::Asset(const AssetId& id, const AZ::Data::AssetType& type, const AZStd::string& hint)
@@ -1104,8 +1117,11 @@ namespace AZ
// If we either already had valid asset data, or just created it via FindOrCreateAsset, try to queue the load.
if (m_assetData && m_assetData->GetId().IsValid())
{
// Only try to queue if the asset isn't already loading or loaded.
if (m_assetData->GetStatus() == AZ::Data::AssetData::AssetStatus::NotLoaded)
// Try to queue if the asset isn't already loading or loaded.
// Also try to queue if the asset *is* already loading or loaded, but we're the only one with a strong reference
// (i.e. use count == 1), because that means it was in the process of being garbage-collected.
if ((m_assetData->GetStatus() == AZ::Data::AssetData::AssetStatus::NotLoaded) ||
(m_assetData->GetUseCount() == 1))
{
*this = AssetInternal::GetAsset(m_assetData->GetId(), m_assetData->GetType(), loadBehavior, loadParams);
}
@@ -1219,6 +1235,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
@@ -255,7 +260,7 @@ namespace AZ
bool AssetContainer::IsValid() const
{
return (m_containerAssetId.IsValid() && m_initComplete);
return (m_containerAssetId.IsValid() && m_initComplete && m_rootAsset);
}
void AssetContainer::CheckReady()
@@ -264,13 +269,13 @@ namespace AZ
{
for (auto& [assetId, dependentAsset] : m_dependencies)
{
if (dependentAsset->IsReady())
if (dependentAsset->IsReady() || dependentAsset->IsError())
{
HandleReadyAsset(dependentAsset);
}
}
}
if (auto asset = m_rootAsset.GetStrongReference(); asset.IsReady())
if (auto asset = m_rootAsset.GetStrongReference(); asset.IsReady() || asset.IsError())
{
HandleReadyAsset(asset);
}
@@ -341,6 +346,7 @@ namespace AZ
void AssetContainer::OnAssetError(Asset<AssetData> asset)
{
AZ_Warning("AssetContainer", false, "Error loading asset %s", asset->GetId().ToString<AZStd::string>().c_str());
HandleReadyAsset(asset);
}
@@ -366,7 +372,10 @@ namespace AZ
auto remainingPreloadIter = m_preloadList.find(waiterId);
if (remainingPreloadIter == m_preloadList.end())
{
AZ_Warning("AssetContainer", !m_initComplete, "Couldn't find waiting list for %s", waiterId.ToString<AZStd::string>().c_str());
// If we got here without an entry on the preload list, it probably means this asset was triggered to load multiple
// times, some with dependencies and some without. To ensure that we don't disturb the loads that expect the
// dependencies, just silently return and don't treat the asset as finished loading. We'll rely on the other load
// to send an OnAssetReady() whenever its expected dependencies are met.
return;
}
if (!remainingPreloadIter->second.erase(preloadID))
@@ -487,10 +496,10 @@ namespace AZ
m_waitingCount -= 1;
disconnectEbus = true;
if (m_waitingAssets.empty())
{
allReady = true;
}
}
if (m_waitingAssets.empty())
{
allReady = true;
}
}
@@ -501,8 +510,15 @@ namespace AZ
}
}
if (allReady && m_initComplete)
// If there are no assets left to be loaded, trigger the final AssetContainer notification (ready or canceled).
// We guard against prematurely sending it (m_initComplete) because it's possible for assets to get removed from our waiting
// list *while* we're still building up the list, so the list would appear to be empty too soon.
// We also guard against sending it multiple times (m_finalNotificationSent), because in some error conditions, it may be
// possible to try to remove the same asset multiple times, which if it's the last asset, it could trigger multiple
// notifications.
if (allReady && m_initComplete && !m_finalNotificationSent)
{
m_finalNotificationSent = true;
if (m_rootAsset)
{
AssetManagerBus::Broadcast(&AssetManagerBus::Events::OnAssetContainerReady, this);
@@ -610,7 +626,12 @@ namespace AZ
}
for(auto& thisList : preloadList)
{
m_preloadList[thisList.first].insert(thisList.second.begin(), thisList.second.end());
// Only save the entry to the final preload list if it has at least one dependent asset still remaining after
// the checks above.
if (!thisList.second.empty())
{
m_preloadList[thisList.first].insert(thisList.second.begin(), thisList.second.end());
}
}
}
}
@@ -137,6 +137,7 @@ namespace AZ
AZStd::atomic_int m_invalidDependencies{ 0 };
AZStd::unordered_set<AZ::Data::AssetId> m_unloadedDependencies;
AZStd::atomic_bool m_initComplete{ false };
AZStd::atomic_bool m_finalNotificationSent{false};
mutable AZStd::recursive_mutex m_preloadMutex;
// AssetId -> List of assets it is still waiting on
@@ -208,6 +208,7 @@ namespace AZ::Data
void AssetDataStream::Close()
{
AZ_Assert(m_isOpen, "Attempting to close a stream that hasn't been opened.");
AZ_Assert(m_curReadRequest == nullptr, "Attempting to close a stream with a read request in flight.");
// Destroy the asset buffer and unlock the allocator, so the allocator itself knows that it is no longer needed.
if (m_buffer != m_preloadedData.data())
@@ -222,6 +223,16 @@ namespace AZ::Data
AZ_PROFILE_INTERVAL_END(AZ::Debug::ProfileCategory::AzCore, this);
}
void AssetDataStream::RequestCancel()
{
AZStd::scoped_lock<AZStd::mutex> lock(m_readRequestMutex);
if (m_curReadRequest)
{
auto streamer = Interface<IO::IStreamer>::Get();
m_curReadRequest = streamer->Cancel(m_curReadRequest);
}
}
void AssetDataStream::Seek(AZ::IO::OffsetType bytes, AZ::IO::GenericStream::SeekMode mode)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzCore);
@@ -82,6 +82,10 @@ namespace AZ::Data
//! Gets the size of data loaded (so far).
size_t GetLoadedSize() const { return m_loadedSize; }
//! Request a cancellation of any current IO streamer requests.
//! Note: This is asynchronous and not guaranteed to cancel if the request is already in-process.
void RequestCancel();
private:
//! Perform any operations needed by all variants of Open()
void OpenInternal(size_t assetSize, const char* streamName);
@@ -28,6 +28,8 @@ namespace AZ::Data::AssetInternal
class WeakAsset
{
public:
static constexpr bool EnableAssetCancellation = false;
WeakAsset() = default;
WeakAsset(AssetData* assetData, AssetLoadBehavior assetReferenceLoadBehavior);
@@ -111,7 +113,14 @@ namespace AZ::Data::AssetInternal
// - If the left and right sides are the same, clearing the right side's reference means one less reference will exist
if (m_assetData)
{
m_assetData->ReleaseWeak();
if constexpr (EnableAssetCancellation)
{
m_assetData->ReleaseWeak();
}
else
{
m_assetData->Release();
}
}
m_assetData = AZStd::move(rhs.m_assetData);
rhs.m_assetData = nullptr;
@@ -141,13 +150,27 @@ namespace AZ::Data::AssetInternal
if (assetData)
{
assetData->AcquireWeak();
if constexpr (EnableAssetCancellation)
{
assetData->AcquireWeak();
}
else
{
assetData->Acquire();
}
m_assetId = assetData->GetId();
}
if (m_assetData)
{
m_assetData->ReleaseWeak();
if constexpr (EnableAssetCancellation)
{
m_assetData->ReleaseWeak();
}
else
{
m_assetData->Release();
}
}
m_assetData = assetData;
@@ -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);
}
}
@@ -2144,7 +2160,7 @@ namespace AZ
if (curIter != m_assetContainers.end())
{
auto newRef = curIter->second.lock();
if (newRef)
if (newRef && newRef->IsValid())
{
return newRef;
}
@@ -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>()
@@ -19,7 +19,6 @@
#include <AzCore/Jobs/JobManagerComponent.h>
#include <AzCore/Serialization/Json/JsonSystemComponent.h>
#include <AzCore/Memory/MemoryComponent.h>
#include <AzCore/NativeUI/NativeUISystemComponent.h>
#include <AzCore/Script/ScriptSystemComponent.h>
#include <AzCore/Slice/SliceComponent.h>
#include <AzCore/Slice/SliceSystemComponent.h>
@@ -43,7 +42,6 @@ namespace AZ
AssetManagerComponent::CreateDescriptor(),
UserSettingsComponent::CreateDescriptor(),
Debug::FrameProfilerComponent::CreateDescriptor(),
NativeUI::NativeUISystemComponent::CreateDescriptor(),
SliceComponent::CreateDescriptor(),
SliceSystemComponent::CreateDescriptor(),
SliceMetadataInfoComponent::CreateDescriptor(),
@@ -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
@@ -28,6 +28,8 @@
#include <AzCore/Memory/AllocatorManager.h>
#include <AzCore/Memory/MallocSchema.h>
#include <AzCore/NativeUI/NativeUIRequests.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/ObjectStream.h>
#include <AzCore/Serialization/Utils.h>
@@ -424,7 +426,7 @@ namespace AZ
// Now that the Allocators are initialized, the Command Line parameters can be parsed
m_commandLine.Parse(m_argC, m_argV);
ParseCommandLine(m_commandLine);
SettingsRegistryMergeUtils::ParseCommandLine(m_commandLine);
// Create the settings registry and register it with the AZ interface system
// This is done after the AppRoot has been calculated so that the Bootstrap.cfg
@@ -475,7 +477,7 @@ namespace AZ
m_console = AZ::Interface<AZ::IConsole>::Get();
if (m_console == nullptr)
{
m_console = aznew AZ::Console();
m_console = aznew AZ::Console(*m_settingsRegistry);
AZ::Interface<AZ::IConsole>::Register(m_console);
m_ownsConsole = true;
m_console->LinkDeferredFunctors(AZ::ConsoleFunctorBase::GetDeferredHead());
@@ -524,13 +526,50 @@ namespace AZ
// are destroyed
m_commandLine = {};
m_entityAddedEvent.DisconnectAllHandlers();
m_entityRemovedEvent.DisconnectAllHandlers();
m_entityActivatedEvent.DisconnectAllHandlers();
m_entityDeactivatedEvent.DisconnectAllHandlers();
DestroyAllocator();
}
void ReportBadEngineRoot()
{
AZStd::string errorMessage = {"Unable to determine a valid path to the engine.\n"
"Check parameters such as --project-path and --engine-path and make sure they are valid.\n"};
if (auto registry = AZ::SettingsRegistry::Get(); registry != nullptr)
{
AZ::SettingsRegistryInterface::FixedValueString filePathErrorStr;
if (registry->Get(filePathErrorStr, AZ::SettingsRegistryMergeUtils::FilePathKey_ErrorText); !filePathErrorStr.empty())
{
errorMessage += "Additional Info:\n";
errorMessage += filePathErrorStr.c_str();
}
}
if (auto nativeUI = AZ::Interface<AZ::NativeUI::NativeUIRequests>::Get(); nativeUI != nullptr)
{
nativeUI->DisplayOkDialog("O3DE Fatal Error", errorMessage.c_str(), false);
}
else
{
AZ_Error("ComponentApplication", false, "O3DE Fatal Error: %s\n", errorMessage.c_str());
}
}
Entity* ComponentApplication::Create(const Descriptor& descriptor, const StartupParameters& startupParameters)
{
AZ_Assert(!m_isStarted, "Component application already started!");
if (m_engineRoot.empty())
{
ReportBadEngineRoot();
return nullptr;
}
m_startupParameters = startupParameters;
m_descriptor = descriptor;
@@ -871,73 +910,55 @@ namespace AZ
}
}
void ComponentApplication::ParseCommandLine(const AZ::CommandLine& commandLine)
{
struct OptionKeyToRegsetKey
{
AZStd::string_view m_optionKey;
AZStd::string m_regsetKey;
};
// Provide overrides for the engine root, the project root and the project cache root
AZStd::array commandOptions = {
OptionKeyToRegsetKey{ "engine-path", AZStd::string::format("%s/engine_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) },
OptionKeyToRegsetKey{ "project-path", AZStd::string::format("%s/project_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) },
OptionKeyToRegsetKey{ "project-cache-path", AZStd::string::format("%s/project_cache_path", AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) }
};
AZStd::fixed_vector<AZStd::string, commandOptions.size()> overrideArgs;
for (auto&& [optionKey, regsetKey] : commandOptions)
{
if (size_t optionCount = commandLine.GetNumSwitchValues(optionKey); optionCount > 0)
{
// Use the last supplied command option value to override previous values
auto overrideArg = AZStd::string::format(R"(--regset="%s=%s")", regsetKey.c_str(),
commandLine.GetSwitchValue(optionKey, optionCount - 1).c_str());
overrideArgs.emplace_back(AZStd::move(overrideArg));
}
}
if (!overrideArgs.empty())
{
// Dump the input command line, add the additional option overrides
// and Parse the new command line into the Component Application command line
AZ::CommandLine::ParamContainer commandLineArgs;
commandLine.Dump(commandLineArgs);
commandLineArgs.insert(commandLineArgs.end(), AZStd::make_move_iterator(overrideArgs.begin()),
AZStd::make_move_iterator(overrideArgs.end()));
m_commandLine.Parse(commandLineArgs);
}
}
void ComponentApplication::MergeSettingsToRegistry(SettingsRegistryInterface& registry)
{
SettingsRegistryInterface::Specializations specializations;
SetSettingsRegistrySpecializations(specializations);
AZStd::vector<char> scratchBuffer;
// Retrieves the list gem module build targets that the active project depends on
SettingsRegistryMergeUtils::MergeSettingsToRegistry_TargetBuildDependencyRegistry(registry,
AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
#if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD)
// In development builds apply the o3de registry and the command line to allow early overrides. This will
// allow developers to override things like default paths or Asset Processor connection settings. Any additional
// values will be replaced by later loads, so this step will happen again at the end of loading.
SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false);
// Project User Registry is merged after the command line here to allow make sure the any command line override of the project path
// is used for merging the project's user registry
SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false);
SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry);
#endif
//! Retrieves the list gem targets that the project has load dependencies on
//! This populates the /Amazon/Gems/<GemName>/SourcePaths array entries which is required
//! by the MergeSettingsToRegistry_GemRegistry() function below to locate the gem's root folder
//! and merge in the gem's registry files.
//! But when running from a pre-built app from the O3DE SDK(Editor/AssetProcessor), the projects binary
//! directory is needed in order to located the load dependency registry files
//! That project binary folder is generated with the <ProjectRoot>/user/Registry when CMake is configured
//! for the project
//! Therefore the order of merging must be as follows
//! 1. MergeSettingsToRegistry_ProjectUserRegistry - Populates the /Amazon/Project/Settings/Build/project_build_path
//! which contains the path to the project binary directory
//! 2. MergeSettingsToRegistry_TargetBuildDependencyRegistry - Loads the cmake_dependencies.<project_name>.<application_name>.setreg
//! file from the locations in order of
//! 1. <executable_directory>/Registry
//! 2. <cache_root>/Registry
//! 3. <project_build_path>/bin/$<CONFIG>/Registry
//! 3. MergeSettingsToRegistry_GemRegistries - Merges the settings registry files from each gem's <GemRoot>/Registry directory
SettingsRegistryMergeUtils::MergeSettingsToRegistry_TargetBuildDependencyRegistry(registry,
AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
SettingsRegistryMergeUtils::MergeSettingsToRegistry_EngineRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
SettingsRegistryMergeUtils::MergeSettingsToRegistry_GemRegistries(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
#if defined(AZ_DEBUG_BUILD) || defined(AZ_PROFILE_BUILD)
SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, false);
SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer);
SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true);
#endif
// Update the Runtime file paths in case the "{BootstrapSettingsRootKey}/assets" key was overriden by a setting registry
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry);
SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry);
}
void ComponentApplication::SetSettingsRegistrySpecializations(SettingsRegistryInterface::Specializations& specializations)
@@ -986,6 +1007,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]
@@ -1285,7 +1326,7 @@ namespace AZ
// Add all auto loadable non-asset gems to the list of gem modules to load
if (!moduleLoadData.m_autoLoad)
{
break;
continue;
}
for (AZ::OSString& dynamicLibraryPath : moduleLoadData.m_dynamicLibraryPaths)
{
@@ -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;
@@ -328,9 +332,6 @@ namespace AZ
/// Create the drillers
void CreateDrillers();
/// Parse ComponentApplication specific command line arguments
void ParseCommandLine(const AZ::CommandLine& commandLine);
virtual void MergeSettingsToRegistry(SettingsRegistryInterface& registry);
//! Sets the specializations that will be used when loading the Settings Registry. Extend this in derived
@@ -385,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);
@@ -87,4 +87,4 @@ namespace AZ
size_t m_nextBlockSize;
unsigned int m_compressedBufferIndex;
};
};
};
+176 -38
View File
@@ -13,7 +13,9 @@
#include <AzCore/Console/Console.h>
#include <AzCore/Console/ILogger.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Serialization/Json/JsonSerializationSettings.h>
#include <AzCore/Settings/CommandLine.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <AzCore/Utils/Utils.h>
#include <AzCore/IO/FileIO.h>
@@ -43,6 +45,12 @@ namespace AZ
{
}
Console::Console(AZ::SettingsRegistryInterface& settingsRegistryInterface)
: Console()
{
RegisterCommandInvokerWithSettingsRegistry(settingsRegistryInterface);
}
Console::~Console()
{
// on console destruction relink the console functors back to the deferred head
@@ -111,51 +119,51 @@ namespace AZ
void Console::ExecuteConfigFile(AZStd::string_view configFileName)
{
IO::FixedMaxPath filePathFixed = configFileName;
if (AZ::IO::FileIOBase* fileIOBase = AZ::IO::FileIOBase::GetInstance())
auto settingsRegistry = AZ::SettingsRegistry::Get();
// If the config file is a settings registry file use the SettingsRegistryInterface MergeSettingsFile function
// otherwise use the SettingsRegistryMergeUtils MergeSettingsToRegistry_ConfigFile function to merge an INI-style
// file to the settings registry
AZ::IO::PathView configFile(configFileName);
if (configFile.Extension() == ".setreg")
{
fileIOBase->ResolvePath(filePathFixed, configFileName);
settingsRegistry->MergeSettingsFile(configFile.Native(), AZ::SettingsRegistryInterface::Format::JsonMergePatch);
}
IO::SystemFile file;
if (!file.Open(filePathFixed.c_str(), AZ::IO::SystemFile::SF_OPEN_READ_ONLY))
else if (configFile.Extension() == ".setregpatch")
{
AZLOG_ERROR("Failed to load '%s'. File could not be opened.", filePathFixed.c_str());
return;
settingsRegistry->MergeSettingsFile(configFile.Native(), AZ::SettingsRegistryInterface::Format::JsonPatch);
}
const IO::SizeType length = file.Length();
if (length == 0)
else
{
AZLOG_ERROR("Failed to load '%s'. File is empty.", filePathFixed.c_str());
return;
}
file.Seek(0, IO::SystemFile::SF_SEEK_BEGIN);
AZStd::string fileBuffer;
fileBuffer.resize(length);
IO::SizeType bytesRead = file.Read(length, fileBuffer.data());
file.Close();
// Resize again just in case bytesRead is less than length for some reason
fileBuffer.resize(bytesRead);
AZLOG_INFO("Loading config file %s", filePathFixed.c_str());
AZStd::vector<AZStd::string_view> separatedCommands;
auto BreakCommandsByLine = [&separatedCommands](AZStd::string_view token)
{
separatedCommands.emplace_back(token);
};
StringFunc::TokenizeVisitor(fileBuffer, BreakCommandsByLine, "\n\r");
for (const auto& commandView : separatedCommands)
{
ConsoleCommandContainer commandArgsView;
auto ConvertCommandStringToArray = [&commandArgsView](AZStd::string_view token)
AZ::SettingsRegistryMergeUtils::ConfigParserSettings configParserSettings;
configParserSettings.m_registryRootPointerPath = "/Amazon/AzCore/Runtime/ConsoleCommands";
configParserSettings.m_commandLineSettings.m_delimiterFunc = [](AZStd::string_view line)
{
commandArgsView.emplace_back(token);
SettingsRegistryInterface::CommandLineArgumentSettings::JsonPathValue pathValue;
AZStd::string_view parsedLine = line;
// Splits the line based on the <equal> or <colon>
if (auto path = AZ::StringFunc::TokenizeNext(parsedLine, "=:"); path.has_value())
{
pathValue.m_path = AZ::StringFunc::StripEnds(*path);
pathValue.m_value = AZ::StringFunc::StripEnds(parsedLine);
}
// If the value is empty, then the line either contained an equal sign followed only by whitespace or the line was empty
// 1. line="testInit=", pathValue.m_path="testInit", pathValue.m_value=""
// 2. line="testInit 1", pathValue.m_path="testInit 1", pathValue.m_value=""
// Therefore the path is split the path on whitespace in order to retrieve a value
if (pathValue.m_value.empty())
{
parsedLine = pathValue.m_path;
if (auto path = AZ::StringFunc::TokenizeNext(parsedLine, " \t"); path.has_value())
{
pathValue.m_path = AZ::StringFunc::StripEnds(*path);
pathValue.m_value = AZ::StringFunc::StripEnds(parsedLine);
}
}
return pathValue;
};
constexpr AZStd::string_view commandSeparators = " =";
StringFunc::TokenizeVisitor(commandView, ConvertCommandStringToArray, commandSeparators);
PerformCommand(commandArgsView, ConsoleSilentMode::NotSilent, ConsoleInvokedFrom::AzConsole, ConsoleFunctorFlags::Null, ConsoleFunctorFlags::Null);
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ConfigFile(*settingsRegistry, configFile.Native(), configParserSettings);
}
}
@@ -447,4 +455,134 @@ namespace AZ
return result;
}
struct ConsoleCommandKeyNotificationHandler
{
ConsoleCommandKeyNotificationHandler(AZ::SettingsRegistryInterface& registry, Console& console)
: m_settingsRegistry(registry)
, m_console(console)
{
}
// Responsible for using the Json Serialization Issue Callback system
// to determine when a JSON Patch or JSON Merge Patch modifies a value
// at a path underneath the IConsole::ConsoleRootCommandKey JSON pointer
JsonSerializationResult::ResultCode operator()(AZStd::string_view message,
JsonSerializationResult::ResultCode result, AZStd::string_view path)
{
AZ::IO::PathView consoleRootCommandKey{ IConsole::ConsoleRootCommandKey, AZ::IO::PosixPathSeparator };
AZ::IO::PathView inputKey{ path, AZ::IO::PosixPathSeparator };
if (result.GetTask() == JsonSerializationResult::Tasks::Merge
&& result.GetProcessing() == JsonSerializationResult::Processing::Completed
&& inputKey.IsRelativeTo(consoleRootCommandKey))
{
if (auto type = m_settingsRegistry.GetType(path); type != SettingsRegistryInterface::Type::NoType)
{
operator()(path, type);
}
}
// This is the default issue reporting, that logs using the warning category
if (result.GetProcessing() != JsonSerializationResult::Processing::Completed)
{
scratchBuffer.append(message.begin(), message.end());
scratchBuffer.append("\n Reason: ");
result.AppendToString(scratchBuffer, path);
scratchBuffer.append(".");
AZ_Warning("JSON Serialization", false, "%s", scratchBuffer.c_str());
scratchBuffer.clear();
}
return result;
}
void operator()(AZStd::string_view path, SettingsRegistryInterface::Type type)
{
using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString;
AZ::IO::PathView consoleRootCommandKey{ IConsole::ConsoleRootCommandKey, AZ::IO::PosixPathSeparator };
AZ::IO::PathView inputKey{ path, AZ::IO::PosixPathSeparator };
if (inputKey.IsRelativeTo(consoleRootCommandKey))
{
FixedValueString command = inputKey.LexicallyRelative(consoleRootCommandKey).Native();
ConsoleCommandContainer commandArgs;
// Argument string which stores the value from the Settings Registry long enough
// to pass into the PerformCommand. The ConsoleCommandContainer stores string_views
// and therefore doesn't own the memory.
FixedValueString commandArgString;
if (type == SettingsRegistryInterface::Type::String)
{
if (m_settingsRegistry.Get(commandArgString, path))
{
auto ConvertCommandArgumentToArray = [&commandArgs](AZStd::string_view token)
{
commandArgs.emplace_back(token);
};
constexpr AZStd::string_view commandSeparators = " \t\n\r";
StringFunc::TokenizeVisitor(commandArgString, ConvertCommandArgumentToArray, commandSeparators);
}
}
else if (type == SettingsRegistryInterface::Type::Boolean)
{
bool commandArgBool{};
if (m_settingsRegistry.Get(commandArgBool, path))
{
commandArgString = commandArgBool ? "true" : "false";
commandArgs.emplace_back(commandArgString);
}
}
else if (type == SettingsRegistryInterface::Type::Integer)
{
// Try converting to a signed 64-bit number first and then an unsigned 64-bit number
AZ::s64 commandArgInt{};
AZ::u64 commandArgUInt{};
if (m_settingsRegistry.Get(commandArgInt, path))
{
AZStd::to_string(commandArgString, commandArgInt);
commandArgs.emplace_back(commandArgString);
}
else if (m_settingsRegistry.Get(commandArgUInt, path))
{
AZStd::to_string(commandArgString, commandArgUInt);
commandArgs.emplace_back(commandArgString);
}
}
else if (type == SettingsRegistryInterface::Type::FloatingPoint)
{
double commandArgFloat{};
if (m_settingsRegistry.Get(commandArgFloat, path))
{
AZStd::to_string(commandArgString, commandArgFloat);
commandArgs.emplace_back(commandArgString);
}
}
CVarFixedString commandTrace(command);
for (AZStd::string_view commandArg : commandArgs)
{
commandTrace.push_back(' ');
commandTrace += commandArg;
}
m_console.PerformCommand(command, commandArgs, ConsoleSilentMode::NotSilent, ConsoleInvokedFrom::AzConsole, ConsoleFunctorFlags::Null, ConsoleFunctorFlags::Null);
}
}
AZ::Console& m_console;
AZ::SettingsRegistryInterface& m_settingsRegistry;
AZStd::string scratchBuffer;
};
void Console::RegisterCommandInvokerWithSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry)
{
// Make sure the there is a JSON object at the path of AZ::IConsole::ConsoleRootCommandKey
// So that JSON Patch is able to add values underneath that object (JSON Patch doesn't create intermediate objects)
settingsRegistry.MergeSettings(R"({ "Amazon": { "AzCore": { "Runtime": { "ConsoleCommands": {} } }}})",
SettingsRegistryInterface::Format::JsonMergePatch);
m_consoleCommandKeyHandler = settingsRegistry.RegisterNotifier(ConsoleCommandKeyNotificationHandler{ settingsRegistry, *this });
JsonApplyPatchSettings applyPatchSettings;
applyPatchSettings.m_reporting = ConsoleCommandKeyNotificationHandler{ settingsRegistry, *this };
settingsRegistry.SetApplyPatchSettings(applyPatchSettings);
}
}
@@ -14,6 +14,7 @@
#include <AzCore/Console/IConsole.h>
#include <AzCore/Memory/OSAllocator.h>
#include <AzCore/Settings/SettingsRegistry.h>
#include <AzCore/std/functional.h>
#include <AzCore/std/containers/unordered_map.h>
@@ -29,6 +30,9 @@ namespace AZ
AZ_CLASS_ALLOCATOR(Console, AZ::OSAllocator, 0);
Console();
//! Constructor overload which registers a notifier with the Settings Registry that will execute
//! a console command whenever a key is set under the AZ::IConsole::ConsoleCommandRootKey JSON object
explicit Console(AZ::SettingsRegistryInterface& settingsRegistry);
~Console() override;
//! IConsole interface
@@ -67,6 +71,7 @@ namespace AZ
void RegisterFunctor(ConsoleFunctorBase* functor) override;
void UnregisterFunctor(ConsoleFunctorBase* functor) override;
void LinkDeferredFunctors(ConsoleFunctorBase*& deferredHead) override;
void RegisterCommandInvokerWithSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry) override;
//! @}
private:
@@ -96,6 +101,7 @@ namespace AZ
ConsoleFunctorBase* m_head;
using CommandMap = AZStd::unordered_map<CVarFixedString, AZStd::vector<ConsoleFunctorBase*>>;
CommandMap m_commands;
AZ::SettingsRegistryInterface::NotifyEventHandler m_consoleCommandKeyHandler;
friend class ConsoleFunctorBase;
};
@@ -148,7 +148,15 @@ namespace AZ
{
AZ::CVarFixedString convertCandidate{ arguments.front() };
char* endPtr = nullptr;
MAX_TYPE value = static_cast<MAX_TYPE>(strtoll(convertCandidate.c_str(), &endPtr, 0));
MAX_TYPE value;
if constexpr (AZStd::is_unsigned_v<MAX_TYPE>)
{
value = aznumeric_cast<MAX_TYPE>(strtoull(convertCandidate.c_str(), &endPtr, 0));
}
else
{
value = aznumeric_cast<MAX_TYPE>(strtoll(convertCandidate.c_str(), &endPtr, 0));
}
if (endPtr == convertCandidate.c_str())
{
@@ -22,8 +22,10 @@
namespace AZ
{
class SettingsRegistryInterface;
class CommandLine;
//! @class IConsole
//! A simple console class for providing text based variable and process interaction.
class IConsole
@@ -33,6 +35,8 @@ namespace AZ
using FunctorVisitor = AZStd::function<void(ConsoleFunctorBase*)>;
inline static constexpr AZStd::string_view ConsoleRootCommandKey = "/Amazon/AzCore/Runtime/ConsoleCommands";
IConsole() = default;
virtual ~IConsole() = default;
@@ -145,6 +149,12 @@ namespace AZ
//! Returns the AZ::Event<> invoked whenever a console command could not be found.
DispatchCommandNotFoundEvent& GetDispatchCommandNotFoundEvent();
//! Register a notification event handler with the Settings Registry
//! That is responsible for updating console commands whenever
//! a key is found underneath the "/Amazon/AzCore/Runtime/ConsoleCommands" JSON entry
//! @param Settings Registry reference to register notifier with
virtual void RegisterCommandInvokerWithSettingsRegistry(AZ::SettingsRegistryInterface& settingsRegistry) = 0;
AZ_DISABLE_COPY_MOVE(IConsole);
protected:
@@ -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)
@@ -82,4 +82,4 @@ namespace AZ
#define AZ_TRACE_INSTANT_THREAD_CATEGORY(name, category) \
EBUS_QUEUE_EVENT(AZ::Debug::EventTraceDrillerBus, RecordInstantThread, name, category, AZStd::this_thread::get_id(), AZStd::GetTimeNowMicroSecond())
#define AZ_TRACE_INSTANT_THREAD(name) AZ_TRACE_INSTANT_THREAD_CATEGORY(name, "")
#define AZ_TRACE_INSTANT_THREAD(name) AZ_TRACE_INSTANT_THREAD_CATEGORY(name, "")
@@ -64,4 +64,4 @@ namespace AZ
} // namespace AZ
#endif // AZCORE_FRAME_PROFILER_H
#pragma once
#pragma once
@@ -39,4 +39,4 @@ namespace AZ
} // namespace AZ
#endif // AZCORE_FRAME_PROFILER_BUS_H
#pragma once
#pragma once
@@ -46,4 +46,4 @@ namespace AZ
}
#endif // AZCORE_PROFILER_DRILLER_BUS_H
#pragma once
#pragma once
@@ -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);
}
@@ -194,4 +194,4 @@ namespace AZ
}
};
}
}
}
@@ -112,4 +112,4 @@ namespace AZ
return m_offsetEnd;
}
} // namespace IO
} // namesapce AZ
} // namesapce AZ
@@ -71,4 +71,4 @@ namespace AZ
u64 m_offsetEnd : 63;
};
} // namespace IO
} // namesapce AZ
} // namesapce AZ
+1 -1
View File
@@ -24,4 +24,4 @@
#if AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING && defined(AZ_COMPILER_CLANG)
#pragma clang diagnostic pop
#endif
#endif
@@ -46,4 +46,4 @@ namespace AZ
}
#endif
#pragma once
#pragma once
@@ -68,4 +68,4 @@ namespace AZ
}
#endif
#pragma once
#pragma once
@@ -70,4 +70,4 @@ namespace AZ
}
#endif
#pragma once
#pragma once
+1 -1
View File
@@ -36,4 +36,4 @@ namespace AZ
}
#endif
#pragma once
#pragma once
@@ -96,4 +96,4 @@ namespace AZ
}
#endif
#pragma once
#pragma once
@@ -135,4 +135,4 @@ namespace AZ
}
#endif
#pragma once
#pragma once
@@ -296,4 +296,4 @@ namespace AZ
m_updateCallback(index);
}
}
}
}
@@ -164,4 +164,4 @@ namespace AZ
return GetTargetValue();
}
};
}
}
@@ -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>();
+10 -9
View File
@@ -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.
+38 -13
View File
@@ -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>
+84 -57
View File
@@ -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
+40 -3
View File
@@ -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
+39 -5
View File
@@ -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>
+92 -15
View File
@@ -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
@@ -67,4 +67,4 @@ namespace AZ
//! Transforms a position by a matrix. This function can be used with any generic cases which include projection matrices.
Vector3 MatrixTransformPosition(const Matrix4x4& matrix, const Vector3& inPosition);
} // namespace AZ
} // namespace AZ
@@ -110,4 +110,4 @@ namespace AZ
} // namespace AZ
#include <AzCore/Math/Internal/VertexContainer.inl>
#include <AzCore/Math/Internal/VertexContainer.inl>
@@ -172,4 +172,4 @@ namespace AZ
template<>
inline AZ::Vector3 AdaptVertexOut<AZ::Vector2>(const AZ::Vector2& vector) { return Vector2ToVector3(vector); }
} // namespace AZ
} // namespace AZ
@@ -103,7 +103,7 @@ namespace AZ
}
}
/// Returns a pointer to the beginning of master vector of SmallAllocationGroups.
/// Returns a pointer to the beginning of vector of SmallAllocationGroups.
SmallAllocationGroup* ArrayHead()
{
return this - m_index;
@@ -169,7 +169,7 @@ namespace AZ
return m_marker == MARKER;
}
/// Returns the master index of the SmallAllocationGroup containing this allocation
/// Returns the index of the SmallAllocationGroup containing this allocation
uint32_t GetSmallAllocationIndex() const
{
return (uint32_t)(m_data & 0xFFFFFFFF);
@@ -31,4 +31,4 @@ namespace AZ
return modulePath;
}
} // namespace Internal
} // namespace AZ
} // namespace AZ
@@ -15,45 +15,49 @@
#include <AzCore/EBus/EBus.h>
#include <AzCore/std/string/string.h>
namespace AZ
namespace AZ::NativeUI
{
namespace NativeUI
enum AssertAction
{
enum AssertAction
{
IGNORE_ASSERT = 0,
IGNORE_ALL_ASSERTS,
BREAK,
NONE,
};
IGNORE_ASSERT = 0,
IGNORE_ALL_ASSERTS,
BREAK,
NONE,
};
class NativeUIRequests
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
using MutexType = AZStd::recursive_mutex;
class NativeUIRequests
{
public:
AZ_RTTI(NativeUIRequests, "{48361EE6-C1E7-4965-A13A-7425B2691817}");
virtual ~NativeUIRequests() = default;
// Waits for user to select an option before execution continues
// Returns the option string selected by the user
virtual AZStd::string DisplayBlockingDialog(const AZStd::string& /*title*/, const AZStd::string& /*message*/, const AZStd::vector<AZStd::string>& /*options*/) const { return ""; };
// Waits for user to select an option before execution continues
// Returns the option string selected by the user
virtual AZStd::string DisplayBlockingDialog(const AZStd::string& /*title*/, const AZStd::string& /*message*/, const AZStd::vector<AZStd::string>& /*options*/) const { return ""; };
// Waits for user to select an option ('Ok' or optionally 'Cancel') before execution continues
// Returns the option string selected by the user
virtual AZStd::string DisplayOkDialog(const AZStd::string& /*title*/, const AZStd::string& /*message*/, bool /*showCancel*/) const { return ""; };
// Waits for user to select an option ('Ok' or optionally 'Cancel') before execution continues
// Returns the option string selected by the user
virtual AZStd::string DisplayOkDialog(const AZStd::string& /*title*/, const AZStd::string& /*message*/, bool /*showCancel*/) const { return ""; };
// Waits for user to select an option ('Yes', 'No' or optionally 'Cancel') before execution continues
// Returns the option string selected by the user
virtual AZStd::string DisplayYesNoDialog(const AZStd::string& /*title*/, const AZStd::string& /*message*/, bool /*showCancel*/) const { return ""; };
// Waits for user to select an option ('Yes', 'No' or optionally 'Cancel') before execution continues
// Returns the option string selected by the user
virtual AZStd::string DisplayYesNoDialog(const AZStd::string& /*title*/, const AZStd::string& /*message*/, bool /*showCancel*/) const { return ""; };
// Displays an assert dialog box
// Returns the action selected by the user
virtual AssertAction DisplayAssertDialog(const AZStd::string& /*message*/) const { return AssertAction::NONE; };
};
// Displays an assert dialog box
// Returns the action selected by the user
virtual AssertAction DisplayAssertDialog(const AZStd::string& /*message*/) const { return AssertAction::NONE; };
};
using NativeUIRequestBus = AZ::EBus<NativeUIRequests>;
}
}
class NativeUIEBusTraits
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
using MutexType = AZStd::recursive_mutex;
};
using NativeUIRequestBus = AZ::EBus<NativeUIRequests, NativeUIEBusTraits>;
} // namespace AZ::NativeUI
@@ -15,50 +15,19 @@
#include <AzCore/NativeUI/NativeUISystemComponent.h>
namespace AZ
namespace AZ::NativeUI
{
using namespace AZ::NativeUI;
void NativeUISystemComponent::Reflect(AZ::ReflectContext* context)
NativeUISystem::NativeUISystem()
{
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->Class<NativeUISystemComponent, AZ::Component>()
->Version(0)
;
if (AZ::EditContext* ec = serialize->GetEditContext())
{
ec->Class<NativeUISystemComponent>("NativeUI", "Adds basic support for native (platform specific) UI dialog boxes")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
;
}
}
NativeUIRequestBus::Handler::BusConnect();
}
void NativeUISystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
NativeUISystem::~NativeUISystem()
{
provided.push_back(AZ_CRC("NativeUIService", 0x8ec25f87));
NativeUIRequestBus::Handler::BusDisconnect();
}
void NativeUISystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("NativeUIService", 0x8ec25f87));
}
void NativeUISystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
(void)required;
}
void NativeUISystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
(void)dependent;
}
AssertAction NativeUISystemComponent::DisplayAssertDialog(const AZStd::string& message) const
AssertAction NativeUISystem::DisplayAssertDialog(const AZStd::string& message) const
{
static const char* buttonNames[3] = { "Ignore", "Ignore All", "Break" };
AZStd::vector<AZStd::string> options;
@@ -80,7 +49,7 @@ namespace AZ
return AssertAction::NONE;
}
AZStd::string NativeUISystemComponent::DisplayOkDialog(const AZStd::string& title, const AZStd::string& message, bool showCancel) const
AZStd::string NativeUISystem::DisplayOkDialog(const AZStd::string& title, const AZStd::string& message, bool showCancel) const
{
AZStd::vector<AZStd::string> options;
@@ -93,7 +62,7 @@ namespace AZ
return DisplayBlockingDialog(title, message, options);
}
AZStd::string NativeUISystemComponent::DisplayYesNoDialog(const AZStd::string& title, const AZStd::string& message, bool showCancel) const
AZStd::string NativeUISystem::DisplayYesNoDialog(const AZStd::string& title, const AZStd::string& message, bool showCancel) const
{
AZStd::vector<AZStd::string> options;
@@ -106,18 +75,4 @@ namespace AZ
return DisplayBlockingDialog(title, message, options);
}
void NativeUISystemComponent::Init()
{
}
void NativeUISystemComponent::Activate()
{
NativeUIRequestBus::Handler::BusConnect();
}
void NativeUISystemComponent::Deactivate()
{
NativeUIRequestBus::Handler::BusDisconnect();
}
}
} // namespace AZ::NativeUI
@@ -15,40 +15,24 @@
#include <AzCore/Component/Component.h>
#include <AzCore/NativeUI/NativeUIRequests.h>
namespace AZ
namespace AZ::NativeUI
{
namespace NativeUI
class NativeUISystem
: public NativeUIRequestBus::Handler
{
class NativeUISystemComponent
: public AZ::Component
, public NativeUIRequestBus::Handler
{
public:
AZ_COMPONENT(NativeUISystemComponent, "{E996C058-4AFE-4C8C-816F-98D864D8576D}");
public:
AZ_RTTI(NativeUISystem, "{FF534B2C-11BE-4DEA-A5B7-A4FA96FE1EDE}", NativeUIRequests);
AZ_CLASS_ALLOCATOR(NativeUISystem, AZ::OSAllocator, 0);
static void Reflect(AZ::ReflectContext* context);
NativeUISystem();
~NativeUISystem() override;
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
////////////////////////////////////////////////////////////////////////
// NativeUIRequestBus interface implementation
AZStd::string DisplayBlockingDialog(const AZStd::string& title, const AZStd::string& message, const AZStd::vector<AZStd::string>& options) const override;
AZStd::string DisplayOkDialog(const AZStd::string& title, const AZStd::string& message, bool showCancel) const override;
AZStd::string DisplayYesNoDialog(const AZStd::string& title, const AZStd::string& message, bool showCancel) const override;
AssertAction DisplayAssertDialog(const AZStd::string& message) const override;
////////////////////////////////////////////////////////////////////////
protected:
////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Init() override;
void Activate() override;
void Deactivate() override;
////////////////////////////////////////////////////////////////////////
};
}
}
////////////////////////////////////////////////////////////////////////
// NativeUIRequestBus interface implementation
AZStd::string DisplayBlockingDialog(const AZStd::string& title, const AZStd::string& message, const AZStd::vector<AZStd::string>& options) const override;
AZStd::string DisplayOkDialog(const AZStd::string& title, const AZStd::string& message, bool showCancel) const override;
AZStd::string DisplayYesNoDialog(const AZStd::string& title, const AZStd::string& message, bool showCancel) const override;
AssertAction DisplayAssertDialog(const AZStd::string& message) const override;
////////////////////////////////////////////////////////////////////////
};
} // namespace AZ::NativeUI
@@ -113,4 +113,4 @@
#define AZCG_Unpack_98(x, ...) AZCG_Unpack_1(x) AZCG_Unpack_97(__VA_ARGS__)
#define AZCG_Unpack_99(x, ...) AZCG_Unpack_1(x) AZCG_Unpack_98(__VA_ARGS__)
#define AZCG_Unpack(...) AZ_MACRO_SPECIALIZE(AZCG_Unpack_, AZ_VA_NUM_ARGS(__VA_ARGS__), (__VA_ARGS__))
#define AZCG_Paste(x) x
#define AZCG_Paste(x) x
@@ -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)
@@ -26,4 +26,4 @@ namespace AZ
void Activate() override { }
void Deactivate() override { }
};
}
}
@@ -79,4 +79,4 @@ namespace AZ
AZ_TYPE_INFO_SPECIALIZE(Script::Attributes::OperatorType, "{26B98C03-7E07-4E3E-9E31-03DA2168E896}");
AZ_TYPE_INFO_SPECIALIZE(Script::Attributes::StorageType, "{57FED71F-B590-4002-9599-A48CB50B0F8E}");
}
}
@@ -32,4 +32,4 @@ namespace AZ
};
typedef AZ::EBus<BehaviorObjectSignalsInterface> BehaviorObjectSignals;
}
}
@@ -138,4 +138,4 @@ namespace AZ
m_currentlyProcessingTypeIds.pop_back();
}
}
}
}
@@ -208,4 +208,4 @@ namespace AZ
}
}
}
}
}
@@ -1411,4 +1411,4 @@ namespace AZ
m_value = entityProperty->m_value;
}
}
}
}
@@ -38,4 +38,4 @@ namespace AZ
};
typedef AZ::EBus<ScriptPropertyWatcherInterface> ScriptPropertyWatcherBus;
}
}
@@ -699,6 +699,10 @@ Data::AssetHandler::LoadResult ScriptSystemComponent::LoadAssetData(
script->m_scriptBuffer.resize(scriptDataLength);
stream->Read(scriptDataLength, script->m_scriptBuffer.data());
// Clear cached references in the event of a successful load. This function has to be queued on
// AssetBus where NotifyAssetReloaded is also queued, to ensure its execution before NotifyAssetReloaded
Data::AssetBus::QueueFunction(&ScriptSystemComponent::ClearAssetReferences, this, asset.GetId());
return Data::AssetHandler::LoadResult::LoadComplete;
}
@@ -853,7 +857,7 @@ const char* ScriptSystemComponent::GetGroup() const
const char* AZ::ScriptSystemComponent::GetBrowserIcon() const
{
return "Editor/Icons/Components/LuaScript.svg";
return "Icons/Components/LuaScript.svg";
}
AZ::Uuid AZ::ScriptSystemComponent::GetComponentTypeId() const
@@ -47,4 +47,4 @@ namespace AZ
}
}
#endif // #if !defined(AZCORE_EXCLUDE_LUA)
#endif // #if !defined(AZCORE_EXCLUDE_LUA)
@@ -24,9 +24,7 @@ namespace AZ
AZ_TYPE_INFO_SPECIALIZE(AZStd::chrono::system_clock::time_point, "{5C48FD59-7267-405D-9C06-1EA31379FE82}");
/**
* Wrapper that reflects a AZStd::chrono::system_clock::time_point to script.
*/
//! Wrapper that reflects a AZStd::chrono::system_clock::time_point to script.
class ScriptTimePoint
{
public:
@@ -38,33 +36,45 @@ namespace AZ
explicit ScriptTimePoint(AZStd::chrono::system_clock::time_point timePoint)
: m_timePoint(timePoint) {}
AZStd::string ToString() const
{
return AZStd::string::format("Time %llu", m_timePoint.time_since_epoch().count());
}
//! Formats the time point in a string formatted as: "Time <seconds since epoch>".
AZStd::string ToString() const;
const AZStd::chrono::system_clock::time_point& Get() { return m_timePoint; }
//! Returns the time point.
const AZStd::chrono::system_clock::time_point& Get() const;
// Returns the time point in seconds
double GetSeconds() const
{
typedef AZStd::chrono::duration<double> double_seconds;
return AZStd::chrono::duration_cast<double_seconds>(m_timePoint.time_since_epoch()).count();
}
//! Returns the time point in seconds
double GetSeconds() const;
// Returns the time point in milliseconds
double GetMilliseconds() const
{
typedef AZStd::chrono::duration<double, AZStd::milli> double_ms;
return AZStd::chrono::duration_cast<double_ms>(m_timePoint.time_since_epoch()).count();
}
//! Returns the time point in milliseconds
double GetMilliseconds() const;
static void Reflect(ReflectContext* reflection);
protected:
AZStd::chrono::system_clock::time_point m_timePoint;
};
inline AZStd::string ScriptTimePoint::ToString() const
{
return AZStd::string::format("Time %llu", m_timePoint.time_since_epoch().count());
}
inline const AZStd::chrono::system_clock::time_point& ScriptTimePoint::Get() const
{
return m_timePoint;
}
inline double ScriptTimePoint::GetSeconds() const
{
typedef AZStd::chrono::duration<double> double_seconds;
return AZStd::chrono::duration_cast<double_seconds>(m_timePoint.time_since_epoch()).count();
}
inline double ScriptTimePoint::GetMilliseconds() const
{
typedef AZStd::chrono::duration<double, AZStd::milli> double_ms;
return AZStd::chrono::duration_cast<double_ms>(m_timePoint.time_since_epoch()).count();
}
}
@@ -287,4 +287,4 @@ namespace AZ
return nullptr;
}
}
}
@@ -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.
@@ -118,6 +122,7 @@ namespace AZ
const static AZ::Crc32 StringLineEditingCompleteNotify = AZ_CRC("StringLineEditingCompleteNotify", 0x139e5fa9);
const static AZ::Crc32 NameLabelOverride = AZ_CRC("NameLabelOverride", 0x9ff79cab);
const static AZ::Crc32 AssetPickerTitle = AZ_CRC_CE("AssetPickerTitle");
const static AZ::Crc32 ChildNameLabelOverride = AZ_CRC("ChildNameLabelOverride", 0x73dd2909);
//! Container attribute that is used to override labels for its elements given the index of the element
const static AZ::Crc32 IndexedChildNameLabelOverride = AZ_CRC("IndexedChildNameLabelOverride", 0x5f313ac2);
@@ -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();

Some files were not shown because too many files have changed in this diff Show More