From 5ff65be3145c43215c4a9e635316016919bdcbfa Mon Sep 17 00:00:00 2001 From: nemerle <96597+nemerle@users.noreply.github.com> Date: Sun, 12 Dec 2021 23:48:47 +0100 Subject: [PATCH 001/136] This reduces non-unity build time by ~2% and build size by ~0.5%. This PR is a 'clean' version of #6199 updated to latest development Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> --- Code/Editor/GameEngine.cpp | 1 + .../AtomCore/Instance/InstanceDatabase.h | 5 + .../AzCore/AzCore/Asset/AssetCommon.h | 2 +- .../AzCore/AzCore/Asset/AssetDataStream.cpp | 98 +++- .../AzCore/AzCore/Asset/AssetDataStream.h | 35 +- .../AzCore/AzCore/Asset/AssetManager.cpp | 1 + .../AzCore/AzCore/Asset/AssetManager.h | 1 - Code/Framework/AzCore/AzCore/IO/IStreamer.h | 6 +- .../AzCore/AzCore/IO/Streamer/BlockCache.cpp | 14 +- .../AzCore/AzCore/IO/Streamer/BlockCache.h | 8 +- .../AzCore/IO/Streamer/DedicatedCache.cpp | 20 +- .../AzCore/IO/Streamer/DedicatedCache.h | 23 +- .../AzCore/AzCore/IO/Streamer/FileRequest.cpp | 143 ++++-- .../AzCore/AzCore/IO/Streamer/FileRequest.h | 485 ++++++++++-------- .../IO/Streamer/FullFileDecompressor.cpp | 46 +- .../AzCore/IO/Streamer/FullFileDecompressor.h | 7 +- .../AzCore/IO/Streamer/ReadSplitter.cpp | 10 +- .../AzCore/AzCore/IO/Streamer/Scheduler.cpp | 50 +- .../AzCore/AzCore/IO/Streamer/Scheduler.h | 19 +- .../AzCore/IO/Streamer/StorageDrive.cpp | 42 +- .../AzCore/AzCore/IO/Streamer/StorageDrive.h | 8 +- .../AzCore/AzCore/IO/Streamer/Streamer.cpp | 7 +- .../AzCore/AzCore/IO/Streamer/Streamer.h | 8 +- .../AzCore/IO/Streamer/StreamerComponent.cpp | 3 +- .../AzCore/IO/Streamer/StreamerContext.cpp | 6 +- .../AzCore/IO/Streamer/StreamerContext.h | 15 +- .../IO/Streamer/StorageDrive_Windows.cpp | 52 +- .../AzCore/IO/Streamer/StorageDrive_Windows.h | 11 +- .../Tests/Asset/AssetDataStreamTests.cpp | 1 + .../IO/Streamer/StorageDriveTests_Windows.cpp | 26 +- .../AzCore/Tests/Streamer/BlockCacheTests.cpp | 16 +- .../Tests/Streamer/FullDecompressorTests.cpp | 2 +- .../AzCore/Tests/Streamer/IStreamerMock.h | 1 + .../Tests/Streamer/ReadSplitterTests.cpp | 10 +- .../AzCore/Tests/Streamer/SchedulerTests.cpp | 7 +- .../StreamStackEntryConformityTests.h | 1 + Code/Framework/AzCore/Tests/StreamerTests.cpp | 1 + .../Asset/AssetSystemComponent.cpp | 1 + .../AzFramework/IO/RemoteStorageDrive.cpp | 42 +- .../AzFramework/IO/RemoteStorageDrive.h | 11 +- .../Physics/Common/PhysicsSimulatedBody.cpp | 1 + .../Common/PhysicsSimulatedBodyAutomation.cpp | 1 + .../Common/PhysicsSimulatedBodyEvents.cpp | 1 + .../AzFramework/Physics/PhysicsScene.cpp | 1 + .../AzFramework/Physics/PhysicsSystem.cpp | 1 + .../AzFramework/Script/ScriptComponent.cpp | 1 + .../ToolsAssetCatalogComponent.h | 1 + .../Model/AssetCompleterModel.h | 5 +- .../AssetBuilder/AssetBuilderComponent.cpp | 1 + .../Shader/ShaderVariantAsyncLoader.h | 6 +- .../Shader/PrecompiledShaderAssetSourceData.h | 1 + .../RPI/Code/Source/RPI.Public/Culling.cpp | 24 +- .../Shader/Metrics/ShaderMetricsSystem.cpp | 4 +- .../Tests/Common/AssetManagerTestFixture.cpp | 2 + .../Atom/Utils/AssetCollectionAsyncLoader.h | 1 + .../Code/Source/AtomActorInstance.cpp | 2 + .../Code/Rendering/SharedBuffer.cpp | 2 + .../Code/Source/Engine/ATLEntities.cpp | 18 + .../Code/Source/Engine/ATLEntities.h | 14 +- .../Code/Source/Engine/FileCacheManager.cpp | 1 + .../Code/Tests/AudioSystemTest.cpp | 1 + .../Code/Tests/Mocks/FileCacheManagerMock.h | 5 + .../Code/EMotionFX/Source/ActorInstance.cpp | 2 + .../Code/Tests/TestAssetCode/SimpleActors.cpp | 2 + .../Asset/AssetSystemDebugComponent.cpp | 2 + .../Audio/AudioAreaEnvironmentComponent.cpp | 1 + .../ClothComponentMesh/ActorClothColliders.h | 1 + Gems/NvCloth/Code/Source/Utils/AssetHelper.h | 1 + .../Joints/JointsSubComponentModeAngleCone.h | 1 + .../Joints/JointsSubComponentModeSnap.h | 1 + .../Code/Source/ForceRegionComponent.cpp | 2 + .../Code/Source/Joint/PhysXJointUtils.cpp | 14 +- .../PhysX/Code/Source/Joint/PhysXJointUtils.h | 7 + Gems/PhysX/Code/Source/JointComponent.cpp | 11 +- Gems/PhysX/Code/Source/Material.cpp | 3 +- .../PhysXCharacters/API/CharacterUtils.cpp | 11 +- .../PhysXCharacters/API/RagdollNode.cpp | 11 +- .../Pipeline/HeightFieldAssetHandler.cpp | 3 +- .../Code/Source/Pipeline/StreamWrapper.h | 1 + Gems/PhysX/Code/Source/Scene/PhysXScene.cpp | 18 +- Gems/PhysX/Code/Source/System/PhysXSystem.cpp | 18 +- Gems/PhysX/Code/Tests/PhysXTestUtil.cpp | 1 + .../Code/Source/SystemComponent.cpp | 23 +- .../Editor/Assets/ScriptCanvasMemoryAsset.cpp | 9 +- .../Windows/Tools/UpgradeTool/FileSaver.cpp | 2 + .../Code/Source/ScriptEventsSystemComponent.h | 1 + .../WhiteBoxVertexTranslationModifier.h | 1 + 87 files changed, 882 insertions(+), 604 deletions(-) diff --git a/Code/Editor/GameEngine.cpp b/Code/Editor/GameEngine.cpp index db4c587f54..3753b5fa37 100644 --- a/Code/Editor/GameEngine.cpp +++ b/Code/Editor/GameEngine.cpp @@ -18,6 +18,7 @@ // AzCore #include #include +#include #include #include diff --git a/Code/Framework/AtomCore/AtomCore/Instance/InstanceDatabase.h b/Code/Framework/AtomCore/AtomCore/Instance/InstanceDatabase.h index 4b4ad572c2..de98ce97b9 100644 --- a/Code/Framework/AtomCore/AtomCore/Instance/InstanceDatabase.h +++ b/Code/Framework/AtomCore/AtomCore/Instance/InstanceDatabase.h @@ -17,6 +17,11 @@ #include #include +namespace AZStd +{ + class any; +} + namespace AZ { namespace Data diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetCommon.h b/Code/Framework/AzCore/AzCore/Asset/AssetCommon.h index e4d2c7612e..697ca81a49 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetCommon.h +++ b/Code/Framework/AzCore/AzCore/Asset/AssetCommon.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include namespace AZ { diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetDataStream.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetDataStream.cpp index 4794b04626..7c9593fe3d 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetDataStream.cpp +++ b/Code/Framework/AzCore/AzCore/Asset/AssetDataStream.cpp @@ -7,11 +7,61 @@ */ #include +#include +#include +#include +#include +#include + +#include +#include namespace AZ::Data { + namespace Internal + { + struct AssetDataStreamPrivate + { + //! Optional data buffer that's been directly passed in through Open(), instead of reading data from a file. + AZStd::vector m_preloadedData; + //! The current active streamer read request - tracked in case we need to cancel it prematurely + AZ::IO::FileRequestPtr m_curReadRequest{ nullptr }; + + //! Synchronization for the read request, so that it's possible to block until completion. + AZStd::mutex m_readRequestMutex; + AZStd::condition_variable m_readRequestActive; + + void SetReadRequest(AZ::IO::FileRequestPtr&& req) + { + AZStd::scoped_lock lock(m_readRequestMutex); + // The read request finished, so stop tracking it. + m_curReadRequest = AZStd::move(req); + } + void BlockUntilReadComplete() + { + AZStd::unique_lock lock(m_readRequestMutex); + m_readRequestActive.wait( + lock, + [this] + { + return m_curReadRequest == nullptr; + }); + lock.unlock(); + } + void CancelRequest() + { + AZStd::scoped_lock lock(m_readRequestMutex); + if (m_curReadRequest) + { + auto streamer = Interface::Get(); + m_curReadRequest = streamer->Cancel(m_curReadRequest); + } + } + }; + } // namespace Internal AssetDataStream::AssetDataStream(AZ::IO::IStreamerTypes::RequestMemoryAllocator* bufferAllocator) : m_bufferAllocator(bufferAllocator ? bufferAllocator : &m_defaultAllocator) + , m_privateData(new Internal::AssetDataStreamPrivate) { ClearInternalStateData(); } @@ -22,6 +72,7 @@ namespace AZ::Data { Close(); } + delete m_privateData; } @@ -53,9 +104,9 @@ namespace AZ::Data OpenInternal(data.size(), "(mem buffer)"); // Directly take ownership of the provided buffer - m_preloadedData = AZStd::move(data); - m_buffer = m_preloadedData.data(); - m_loadedSize = m_preloadedData.size(); + m_privateData->m_preloadedData = AZStd::move(data); + m_buffer = m_privateData->m_preloadedData.data(); + m_loadedSize = m_privateData->m_preloadedData.size(); } void AssetDataStream::Open(const AZStd::string& filePath, size_t fileOffset, size_t assetSize, @@ -65,7 +116,7 @@ namespace AZ::Data AZ_PROFILE_FUNCTION(AzCore); AZ_Assert(!m_isOpen, "Attempting to open the stream when it is already open."); - AZ_Assert(!m_curReadRequest, "Queueing an asset stream load while one is still in progress."); + AZ_Assert(!m_privateData->m_curReadRequest, "Queueing an asset stream load while one is still in progress."); AZ_Assert(!filePath.empty(), "AssetDataStream::Open called without a valid file name."); // Initialize the state variables and start tracking the overall load timings @@ -97,11 +148,8 @@ namespace AZ::Data "Buffer for %s was expected to be %zu bytes, but is %zu bytes.", m_filePath.c_str(), m_requestedAssetSize, m_loadedSize); - { - AZStd::scoped_lock lock(m_readRequestMutex); - // The read request finished, so stop tracking it. - m_curReadRequest = nullptr; - } + // The read request finished, so stop tracking it. + m_privateData->SetReadRequest(nullptr); // Call the load callback to start processing the loaded data. if (loadCallback) @@ -115,21 +163,22 @@ namespace AZ::Data } // Notify that the load is complete, in case anyone is using BlockUntilLoadComplete to block. - m_readRequestActive.notify_one(); + m_privateData->m_readRequestActive.notify_one(); }; // Queue the raw file load with the file streamer. auto streamer = AZ::Interface::Get(); - m_curReadRequest = streamer->Read( + m_privateData->m_curReadRequest = + streamer->Read( m_filePath, *m_bufferAllocator, m_requestedAssetSize, deadline, priority, m_fileOffset); m_curDeadline = deadline; m_curPriority = priority; - streamer->SetRequestCompleteCallback(m_curReadRequest, streamerCallback); + streamer->SetRequestCompleteCallback(m_privateData->m_curReadRequest, streamerCallback); - streamer->QueueRequest(m_curReadRequest); + streamer->QueueRequest(m_privateData->m_curReadRequest); } else { @@ -139,19 +188,19 @@ namespace AZ::Data loadCallback(AZ::IO::IStreamerTypes::RequestStatus::Completed); } - m_readRequestActive.notify_one(); + m_privateData->m_readRequestActive.notify_one(); } } void AssetDataStream::Reschedule(AZStd::chrono::milliseconds newDeadline, AZ::IO::IStreamerTypes::Priority newPriority) { - if (m_curReadRequest && (newDeadline < m_curDeadline || newPriority > m_curPriority)) + if (m_privateData->m_curReadRequest && (newDeadline < m_curDeadline || newPriority > m_curPriority)) { auto deadline = AZStd::GetMin(m_curDeadline, newDeadline); auto priority = AZStd::GetMax(m_curPriority, newPriority); auto streamer = Interface::Get(); - m_curReadRequest = streamer->RescheduleRequest(m_curReadRequest, deadline, priority); + m_privateData->m_curReadRequest = streamer->RescheduleRequest(m_privateData->m_curReadRequest, deadline, priority); m_curDeadline = deadline; m_curPriority = priority; } @@ -159,15 +208,13 @@ namespace AZ::Data void AssetDataStream::BlockUntilLoadComplete() { - AZStd::unique_lock lock(m_readRequestMutex); - m_readRequestActive.wait(lock, [this] { return m_curReadRequest == nullptr; }); - lock.unlock(); + m_privateData->BlockUntilReadComplete(); } void AssetDataStream::ClearInternalStateData() { // Clear all our internal state data. - m_preloadedData.resize(0); + m_privateData->m_preloadedData.resize(0); m_buffer = nullptr; m_loadedSize = 0; m_requestedAssetSize = 0; @@ -204,10 +251,10 @@ 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."); + AZ_Assert(m_privateData->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()) + if (m_buffer != m_privateData->m_preloadedData.data()) { m_bufferAllocator->Release(m_buffer); } @@ -221,12 +268,7 @@ namespace AZ::Data void AssetDataStream::RequestCancel() { - AZStd::scoped_lock lock(m_readRequestMutex); - if (m_curReadRequest) - { - auto streamer = Interface::Get(); - m_curReadRequest = streamer->Cancel(m_curReadRequest); - } + m_privateData->CancelRequest(); } void AssetDataStream::Seek(AZ::IO::OffsetType bytes, AZ::IO::GenericStream::SeekMode mode) diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetDataStream.h b/Code/Framework/AzCore/AzCore/Asset/AssetDataStream.h index 79822c8db2..f095e31562 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetDataStream.h +++ b/Code/Framework/AzCore/AzCore/Asset/AssetDataStream.h @@ -9,17 +9,26 @@ #include #include -#include -#include -#include -#include -#include +#include + + +namespace AZStd +{ + template + class vector; +} namespace AZ::Data { + namespace Internal + { + struct AssetDataStreamPrivate; + } + class AssetDataStream : public AZ::IO::GenericStream { public: + using VectorDataSource = AZStd::vector; // The default Generic Stream APIs in this class will only allow for a single sequential pass // through the data, no seeking. Reads will block when pages aren't available yet, and // pages will be marked for recycling once reading has progressed beyond them. @@ -29,10 +38,10 @@ namespace AZ::Data ~AssetDataStream() override; // Open the AssetDataStream and make a copy of the provided memory buffer. - void Open(const AZStd::vector& data); + void Open(const VectorDataSource& data); // Open the AssetDataStream and directly take ownership of a pre-populated memory buffer. - void Open(AZStd::vector&& data); + void Open(VectorDataSource&& data); // Open the AssetDataStream and load it via file streaming using OnCompleteCallback = AZStd::function; @@ -91,6 +100,8 @@ namespace AZ::Data void ClearInternalStateData(); + Internal::AssetDataStreamPrivate* m_privateData; + //! The allocator to use for allocating / deallocating asset buffers AZ::IO::IStreamerTypes::RequestMemoryAllocator* m_bufferAllocator{ nullptr }; @@ -106,9 +117,6 @@ namespace AZ::Data //! The amount of data that's expected to be loaded. size_t m_requestedAssetSize{ 0 }; - //! Optional data buffer that's been directly passed in through Open(), instead of reading data from a file. - AZStd::vector m_preloadedData; - //! The buffer that will hold the raw data after it's loaded from the file. void* m_buffer{ nullptr }; @@ -119,19 +127,12 @@ namespace AZ::Data //! The current offset representing how far we've read into the buffer. size_t m_curOffset{ 0 }; - //! The current active streamer read request - tracked in case we need to cancel it prematurely - AZ::IO::FileRequestPtr m_curReadRequest{ nullptr }; - //! The current request deadline. Used to avoid requesting a reschedule to the same (current) deadline. AZStd::chrono::milliseconds m_curDeadline{ AZ::IO::IStreamerTypes::s_noDeadline }; //! The current request priority. Used to avoid requesting a reschedule to the same (current) priority. AZ::IO::IStreamerTypes::Priority m_curPriority{ AZ::IO::IStreamerTypes::s_priorityMedium }; - //! Synchronization for the read request, so that it's possible to block until completion. - AZStd::mutex m_readRequestMutex; - AZStd::condition_variable m_readRequestActive; - //! Track whether or not the stream is currently open bool m_isOpen{ false }; diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp index afe3330bd3..b4b1a0d81c 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp +++ b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManager.h b/Code/Framework/AzCore/AzCore/Asset/AssetManager.h index 9666d434c1..663de2c058 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetManager.h +++ b/Code/Framework/AzCore/AzCore/Asset/AssetManager.h @@ -12,7 +12,6 @@ #include #include #include -#include #include #include // used as allocator for most components #include diff --git a/Code/Framework/AzCore/AzCore/IO/IStreamer.h b/Code/Framework/AzCore/AzCore/IO/IStreamer.h index 438384e687..d59ee5007e 100644 --- a/Code/Framework/AzCore/AzCore/IO/IStreamer.h +++ b/Code/Framework/AzCore/AzCore/IO/IStreamer.h @@ -15,14 +15,18 @@ #include #include #include +#include // These Streamer includes need to be moved to Streamer internals/implementation, // and pull out only what we need for visibility at IStreamer.h interface declaration. #include -#include namespace AZ::IO { + class ExternalFileRequest; + class FileRequestHandle; + + using FileRequestPtr = AZStd::intrusive_ptr; /** * Data Streamer Interface */ diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/BlockCache.cpp b/Code/Framework/AzCore/AzCore/IO/Streamer/BlockCache.cpp index 6c873f3050..ca38414eaa 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/BlockCache.cpp +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/BlockCache.cpp @@ -137,18 +137,18 @@ namespace AZ::IO AZStd::visit([this, request](auto&& args) { using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { ReadFile(request, args); return; } else { - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { FlushCache(args.m_path); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { FlushEntireCache(); } @@ -166,7 +166,7 @@ namespace AZ::IO { Section& delayed = m_delayedSections.front(); AZ_Assert(delayed.m_parent, "Delayed section doesn't have a reference to the original request."); - auto data = AZStd::get_if(&delayed.m_parent->GetCommand()); + auto data = AZStd::get_if(&delayed.m_parent->GetCommand()); AZ_Assert(data, "A request in the delayed queue of the BlockCache didn't have a parent with read data."); // This call can add the same section to the back of the queue if there's not // enough space. Because of this the entry needs to be removed from the delayed @@ -233,7 +233,7 @@ namespace AZ::IO } } - void BlockCache::ReadFile(FileRequest* request, FileRequest::ReadData& data) + void BlockCache::ReadFile(FileRequest* request, Requests::ReadData& data) { if (!m_next) { @@ -250,7 +250,7 @@ namespace AZ::IO m_numMetaDataRetrievalInProgress--; if (fileSizeRequest.GetStatus() == IStreamerTypes::RequestStatus::Completed) { - auto& requestInfo = AZStd::get(fileSizeRequest.GetCommand()); + auto& requestInfo = AZStd::get(fileSizeRequest.GetCommand()); if (requestInfo.m_found) { ContinueReadFile(request, requestInfo.m_fileSize); @@ -272,7 +272,7 @@ namespace AZ::IO Section main; Section epilog; - auto& data = AZStd::get(request->GetCommand()); + auto& data = AZStd::get(request->GetCommand()); if (!SplitRequest(prolog, main, epilog, data.m_path, fileLength, data.m_offset, data.m_size, reinterpret_cast(data.m_output))) diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/BlockCache.h b/Code/Framework/AzCore/AzCore/IO/Streamer/BlockCache.h index 90fb7ea193..68aa2da689 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/BlockCache.h +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/BlockCache.h @@ -21,6 +21,12 @@ namespace AZ::IO { + class RequestPath; + namespace Requests + { + struct ReadData; + } + struct BlockCacheConfig final : public IStreamerStackConfig { @@ -109,7 +115,7 @@ namespace AZ::IO using TimePoint = AZStd::chrono::system_clock::time_point; - void ReadFile(FileRequest* request, FileRequest::ReadData& data); + void ReadFile(FileRequest* request, Requests::ReadData& data); void ContinueReadFile(FileRequest* request, u64 fileLength); CacheResult ReadFromCache(FileRequest* request, Section& section, const RequestPath& filePath); CacheResult ReadFromCache(FileRequest* request, Section& section, u32 cacheBlock); diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/DedicatedCache.cpp b/Code/Framework/AzCore/AzCore/IO/Streamer/DedicatedCache.cpp index b80a1ea724..f155d26eef 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/DedicatedCache.cpp +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/DedicatedCache.cpp @@ -101,12 +101,12 @@ namespace AZ::IO AZStd::visit([this, request](auto&& args) { using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { args.m_range = FileRange::CreateRangeForEntireFile(); m_context->PushPreparedRequest(request); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { args.m_range = FileRange::CreateRangeForEntireFile(); m_context->PushPreparedRequest(request); @@ -125,28 +125,28 @@ namespace AZ::IO AZStd::visit([this, request](auto&& args) { using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { ReadFile(request, args); return; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { CreateDedicatedCache(request, args); return; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { DestroyDedicatedCache(request, args); return; } else { - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { FlushCache(args.m_path); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { FlushEntireCache(); } @@ -200,7 +200,7 @@ namespace AZ::IO } } - void DedicatedCache::ReadFile(FileRequest* request, FileRequest::ReadData& data) + void DedicatedCache::ReadFile(FileRequest* request, Requests::ReadData& data) { size_t index = FindCache(data.m_path, data.m_offset); if (index == s_fileNotFound) @@ -255,7 +255,7 @@ namespace AZ::IO StreamStackEntry::CollectStatistics(statistics); } - void DedicatedCache::CreateDedicatedCache(FileRequest* request, FileRequest::CreateDedicatedCacheData& data) + void DedicatedCache::CreateDedicatedCache(FileRequest* request, Requests::CreateDedicatedCacheData& data) { size_t index = FindCache(data.m_path, data.m_range); if (index == s_fileNotFound) @@ -276,7 +276,7 @@ namespace AZ::IO m_context->MarkRequestAsCompleted(request); } - void DedicatedCache::DestroyDedicatedCache(FileRequest* request, FileRequest::DestroyDedicatedCacheData& data) + void DedicatedCache::DestroyDedicatedCache(FileRequest* request, Requests::DestroyDedicatedCacheData& data) { size_t index = FindCache(data.m_path, data.m_range); if (index != s_fileNotFound) diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/DedicatedCache.h b/Code/Framework/AzCore/AzCore/IO/Streamer/DedicatedCache.h index 0ef2d879d3..a69dcdbd7f 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/DedicatedCache.h +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/DedicatedCache.h @@ -11,15 +11,21 @@ #include #include #include -#include #include +#include #include -#include #include +#include #include namespace AZ::IO { + namespace Requests + { + struct CreateDedicatedCacheData; + struct DestroyDedicatedCacheData; + } // namespace Requests + struct DedicatedCacheConfig final : public IStreamerStackConfig { @@ -56,16 +62,19 @@ namespace AZ::IO void UpdateStatus(Status& status) const override; - void UpdateCompletionEstimates(AZStd::chrono::system_clock::time_point now, AZStd::vector& internalPending, - StreamerContext::PreparedQueue::iterator pendingBegin, StreamerContext::PreparedQueue::iterator pendingEnd) override; + void UpdateCompletionEstimates( + AZStd::chrono::system_clock::time_point now, + AZStd::vector& internalPending, + StreamerContext::PreparedQueue::iterator pendingBegin, + StreamerContext::PreparedQueue::iterator pendingEnd) override; void CollectStatistics(AZStd::vector& statistics) const override; private: - void CreateDedicatedCache(FileRequest* request, FileRequest::CreateDedicatedCacheData& data); - void DestroyDedicatedCache(FileRequest* request, FileRequest::DestroyDedicatedCacheData& data); + void CreateDedicatedCache(FileRequest* request, Requests::CreateDedicatedCacheData& data); + void DestroyDedicatedCache(FileRequest* request, Requests::DestroyDedicatedCacheData& data); - void ReadFile(FileRequest* request, FileRequest::ReadData& data); + void ReadFile(FileRequest* request, AZ::IO::Requests::ReadData& data); size_t FindCache(const RequestPath& filename, FileRange range); size_t FindCache(const RequestPath& filename, u64 offset); diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/FileRequest.cpp b/Code/Framework/AzCore/AzCore/IO/Streamer/FileRequest.cpp index fc05b77b36..2f96d224e6 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/FileRequest.cpp +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/FileRequest.cpp @@ -12,22 +12,30 @@ #include #include -namespace AZ::IO +// +// Command structures. +// + +namespace AZ::IO::Requests { - // - // Command structures. - // + ReadData::ReadData(void* output, u64 outputSize, const RequestPath& path, u64 offset, u64 size, bool sharedRead) + : m_path(path) + , m_output(output) + , m_outputSize(outputSize) + , m_offset(offset) + , m_size(size) + , m_sharedRead(sharedRead) + { + } - FileRequest::ExternalRequestData::ExternalRequestData(FileRequestPtr&& request) - : m_request(AZStd::move(request)) - {} - - FileRequest::RequestPathStoreData::RequestPathStoreData(RequestPath path) - : m_path(AZStd::move(path)) - {} - - FileRequest::ReadRequestData::ReadRequestData(RequestPath path, void* output, u64 outputSize, u64 offset, u64 size, - AZStd::chrono::system_clock::time_point deadline, IStreamerTypes::Priority priority) + ReadRequestData::ReadRequestData( + RequestPath path, + void* output, + u64 outputSize, + u64 offset, + u64 size, + AZStd::chrono::system_clock::time_point deadline, + IStreamerTypes::Priority priority) : m_path(AZStd::move(path)) , m_allocator(nullptr) , m_deadline(deadline) @@ -37,10 +45,16 @@ namespace AZ::IO , m_size(size) , m_priority(priority) , m_memoryType(IStreamerTypes::MemoryType::ReadWrite) // Only generic memory can be assigned externally. - {} + { + } - FileRequest::ReadRequestData::ReadRequestData(RequestPath path, IStreamerTypes::RequestMemoryAllocator* allocator, - u64 offset, u64 size, AZStd::chrono::system_clock::time_point deadline, IStreamerTypes::Priority priority) + ReadRequestData::ReadRequestData( + RequestPath path, + IStreamerTypes::RequestMemoryAllocator* allocator, + u64 offset, + u64 size, + AZStd::chrono::system_clock::time_point deadline, + IStreamerTypes::Priority priority) : m_path(AZStd::move(path)) , m_allocator(allocator) , m_deadline(deadline) @@ -50,9 +64,10 @@ namespace AZ::IO , m_size(size) , m_priority(priority) , m_memoryType(IStreamerTypes::MemoryType::ReadWrite) // Only generic memory can be assigned externally. - {} + { + } - FileRequest::ReadRequestData::~ReadRequestData() + ReadRequestData::~ReadRequestData() { if (m_allocator != nullptr) { @@ -64,65 +79,81 @@ namespace AZ::IO } } - FileRequest::ReadData::ReadData(void* output, u64 outputSize, const RequestPath& path, u64 offset, u64 size, bool sharedRead) - : m_output(output) - , m_outputSize(outputSize) - , m_path(path) - , m_offset(offset) - , m_size(size) - , m_sharedRead(sharedRead) - {} + CreateDedicatedCacheData::CreateDedicatedCacheData(RequestPath path, const FileRange& range) + : m_path(AZStd::move(path)) + , m_range(range) + { + } - FileRequest::CompressedReadData::CompressedReadData(CompressionInfo&& compressionInfo, void* output, u64 readOffset, u64 readSize) + DestroyDedicatedCacheData::DestroyDedicatedCacheData(RequestPath path, const FileRange& range) + : m_path(AZStd::move(path)) + , m_range(range) + { + } + + ExternalRequestData::ExternalRequestData(FileRequestPtr&& request) + : m_request(AZStd::move(request)) + { + } + + RequestPathStoreData::RequestPathStoreData(RequestPath path) + : m_path(AZStd::move(path)) + { + } + + CompressedReadData::CompressedReadData(CompressionInfo&& compressionInfo, void* output, u64 readOffset, u64 readSize) : m_compressionInfo(AZStd::move(compressionInfo)) , m_output(output) , m_readOffset(readOffset) , m_readSize(readSize) - {} + { + } - FileRequest::FileExistsCheckData::FileExistsCheckData(const RequestPath& path) + FileExistsCheckData::FileExistsCheckData(const RequestPath& path) : m_path(path) - {} + { + } - FileRequest::FileMetaDataRetrievalData::FileMetaDataRetrievalData(const RequestPath& path) + FileMetaDataRetrievalData::FileMetaDataRetrievalData(const RequestPath& path) : m_path(path) - {} + { + } - FileRequest::CancelData::CancelData(FileRequestPtr target) + CancelData::CancelData(FileRequestPtr target) : m_target(AZStd::move(target)) - {} + { + } - FileRequest::FlushData::FlushData(RequestPath path) + FlushData::FlushData(RequestPath path) : m_path(AZStd::move(path)) - {} + { + } - FileRequest::RescheduleData::RescheduleData(FileRequestPtr target, AZStd::chrono::system_clock::time_point newDeadline, + RescheduleData::RescheduleData( + FileRequestPtr target, + AZStd::chrono::system_clock::time_point newDeadline, IStreamerTypes::Priority newPriority) : m_target(AZStd::move(target)) , m_newDeadline(newDeadline) , m_newPriority(newPriority) - {} + { + } - FileRequest::CreateDedicatedCacheData::CreateDedicatedCacheData(RequestPath path, const FileRange& range) - : m_path(AZStd::move(path)) - , m_range(range) - {} - - FileRequest::DestroyDedicatedCacheData::DestroyDedicatedCacheData(RequestPath path, const FileRange& range) - : m_path(AZStd::move(path)) - , m_range(range) - {} - - FileRequest::ReportData::ReportData(ReportType reportType) + Requests::ReportData::ReportData(ReportType reportType) : m_reportType(reportType) - {} + { + } - FileRequest::CustomData::CustomData(AZStd::any data, bool failWhenUnhandled) + CustomData::CustomData(AZStd::any data, bool failWhenUnhandled) : m_data(AZStd::move(data)) , m_failWhenUnhandled(failWhenUnhandled) - {} - + { + } +} // namespace AZ::IO::Requests +namespace AZ::IO +{ + using namespace Requests; // // FileRequest // @@ -263,7 +294,7 @@ namespace AZ::IO SetOptionalParent(parent); } - void FileRequest::CreateReport(ReportData::ReportType reportType) + void FileRequest::CreateReport(Requests::ReportType reportType) { AZ_Assert(AZStd::holds_alternative(m_command), "Attempting to set FileRequest to 'Report', but another task was already assigned."); @@ -361,7 +392,7 @@ namespace AZ::IO "Request does not contain a valid command. It may have been reset already or was never assigned a command."); return true; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { return args.m_failWhenUnhandled; } diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/FileRequest.h b/Code/Framework/AzCore/AzCore/IO/Streamer/FileRequest.h index dd4dad2387..7f5874c95d 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/FileRequest.h +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/FileRequest.h @@ -27,7 +27,252 @@ namespace AZ::IO class ExternalFileRequest; using FileRequestPtr = AZStd::intrusive_ptr; +} // namespace AZ::IO +namespace AZ::IO::Requests +{ + //! Request to read data. This is a translated request and holds an absolute path and has been + //! resolved to the archive file if needed. + struct ReadData + { + inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium; + inline constexpr static bool s_failWhenUnhandled = true; + + ReadData(void* output, u64 outputSize, const RequestPath& path, u64 offset, u64 size, bool sharedRead); + + const RequestPath& m_path; //!< The path to the file that contains the requested data. + void* m_output; //!< Target output to write the read data to. + u64 m_outputSize; //!< Size of memory m_output points to. This needs to be at least as big as m_size, but can be bigger. + u64 m_offset; //!< The offset in bytes into the file. + u64 m_size; //!< The number of bytes to read from the file. + bool m_sharedRead; //!< True if other code will be reading from the file or the stack entry can exclusively lock. + }; + + //! Request to read data. This is an untranslated request and holds a relative path. The Scheduler + //! will translate this to the appropriate ReadData or CompressedReadData. + struct ReadRequestData + { + inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium; + inline constexpr static bool s_failWhenUnhandled = true; + + ReadRequestData( + RequestPath path, + void* output, + u64 outputSize, + u64 offset, + u64 size, + AZStd::chrono::system_clock::time_point deadline, + IStreamerTypes::Priority priority); + ReadRequestData( + RequestPath path, + IStreamerTypes::RequestMemoryAllocator* allocator, + u64 offset, + u64 size, + AZStd::chrono::system_clock::time_point deadline, + IStreamerTypes::Priority priority); + ~ReadRequestData(); + + RequestPath m_path; //!< Relative path to the target file. + IStreamerTypes::RequestMemoryAllocator* m_allocator; //!< Allocator used to manage the memory for this request. + AZStd::chrono::system_clock::time_point m_deadline; //!< Time by which this request should have been completed. + void* m_output; //!< The memory address assigned (during processing) to store the read data to. + u64 m_outputSize; //!< The memory size of the addressed used to store the read data. + u64 m_offset; //!< The offset in bytes into the file. + u64 m_size; //!< The number of bytes to read from the file. + IStreamerTypes::Priority m_priority; //!< Priority used for ordering requests. This is used when requests have the same deadline. + IStreamerTypes::MemoryType m_memoryType; //!< The type of memory provided by the allocator if used. + }; + + //! Creates a cache dedicated to a single file. This is best used for files where blocks are read from + //! periodically such as audio banks of video files. + struct CreateDedicatedCacheData + { + inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh; + inline constexpr static bool s_failWhenUnhandled = false; + + CreateDedicatedCacheData(RequestPath path, const FileRange& range); + + RequestPath m_path; + FileRange m_range; + }; + + //! Destroys a cache dedicated to a single file that was previously created by CreateDedicatedCache + struct DestroyDedicatedCacheData + { + inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh; + inline constexpr static bool s_failWhenUnhandled = false; + + DestroyDedicatedCacheData(RequestPath path, const FileRange& range); + + RequestPath m_path; + FileRange m_range; + }; + + enum class ReportType : int8_t + { + FileLocks + }; + + struct ReportData + { + inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityLow; + inline constexpr static bool s_failWhenUnhandled = false; + + explicit ReportData(ReportType reportType); + + ReportType m_reportType; + }; + + //! Stores a reference to the external request so it stays alive while the request is being processed. + //! This is needed because Streamer supports fire-and-forget requests since completion can be handled by + //! registering a callback. + struct ExternalRequestData + { + inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium; + inline constexpr static bool s_failWhenUnhandled = true; + + explicit ExternalRequestData(FileRequestPtr&& request); + + FileRequestPtr m_request; //!< The request that was send to Streamer. + }; + + //! Stores an instance of a RequestPath. To reduce copying instances of a RequestPath functions that + //! need a path take them by reference to the original request. In some cases a path originates from + //! within in the stack and temporary storage is needed. This struct allows for that temporary storage + //! so it can be safely referenced later. + struct RequestPathStoreData + { + inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium; + inline constexpr static bool s_failWhenUnhandled = true; + + explicit RequestPathStoreData(RequestPath path); + + RequestPath m_path; + }; + + //! Request to read and decompress data. + struct CompressedReadData + { + inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium; + inline constexpr static bool s_failWhenUnhandled = true; + + CompressedReadData(CompressionInfo&& compressionInfo, void* output, u64 readOffset, u64 readSize); + + CompressionInfo m_compressionInfo; + void* m_output; //!< Target output to write the read data to. + u64 m_readOffset; //!< The offset into the decompressed to start copying from. + u64 m_readSize; //!< Number of bytes to read from the decompressed file. + }; + + //! Holds the progress of an operation chain until this request is explicitly completed. + struct WaitData + { + inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium; + inline constexpr static bool s_failWhenUnhandled = true; + }; + + //! Checks to see if any node in the stack can find a file at the provided path. + struct FileExistsCheckData + { + inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh; + inline constexpr static bool s_failWhenUnhandled = false; + + explicit FileExistsCheckData(const RequestPath& path); + + const RequestPath& m_path; + bool m_found{ false }; + }; + + //! Searches for a file in the stack and retrieves the meta data. This may be slower than a file exists + //! check. + struct FileMetaDataRetrievalData + { + inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh; + inline constexpr static bool s_failWhenUnhandled = false; + + explicit FileMetaDataRetrievalData(const RequestPath& path); + + const RequestPath& m_path; + u64 m_fileSize{ 0 }; + bool m_found{ false }; + }; + + //! Cancels a request in the stream stack, if possible. + struct CancelData + { + inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHighest; + inline constexpr static bool s_failWhenUnhandled = false; + + explicit CancelData(FileRequestPtr target); + + FileRequestPtr m_target; //!< The request that will be canceled. + }; + + //! Updates the priority and deadline of a request that has not been queued yet. + struct RescheduleData + { + inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh; + inline constexpr static bool s_failWhenUnhandled = false; + + RescheduleData(FileRequestPtr target, AZStd::chrono::system_clock::time_point newDeadline, IStreamerTypes::Priority newPriority); + + FileRequestPtr m_target; //!< The request that will be rescheduled. + AZStd::chrono::system_clock::time_point m_newDeadline; //!< The new deadline for the request. + IStreamerTypes::Priority m_newPriority; //!< The new priority for the request. + }; + + //! Flushes all references to the provided file in the streaming stack. + struct FlushData + { + inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh; + inline constexpr static bool s_failWhenUnhandled = false; + + explicit FlushData(RequestPath path); + + RequestPath m_path; + }; + + //! Flushes all caches in the streaming stack. + struct FlushAllData + { + inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh; + inline constexpr static bool s_failWhenUnhandled = false; + }; + + //! Data for a custom command. This can be used by nodes added extensions that need data that can't be stored + //! in the already provided data. + struct CustomData + { + inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium; + + CustomData(AZStd::any data, bool failWhenUnhandled); + + AZStd::any m_data; //!< The data for the custom request. + bool m_failWhenUnhandled; //!< Whether or not the request is marked as failed or success when no node process it. + }; + using CommandVariant = AZStd::variant< + AZStd::monostate, + ExternalRequestData, + RequestPathStoreData, + ReadRequestData, + ReadData, + CompressedReadData, + WaitData, + FileExistsCheckData, + FileMetaDataRetrievalData, + CancelData, + RescheduleData, + FlushData, + FlushAllData, + CreateDedicatedCacheData, + DestroyDedicatedCacheData, + ReportData, + CustomData>; + +} // namespace AZ::IO::Requests + +namespace AZ::IO +{ class FileRequest final { public: @@ -36,218 +281,7 @@ namespace AZ::IO friend class StreamerContext; friend class ExternalFileRequest; - //! Stores a reference to the external request so it stays alive while the request is being processed. - //! This is needed because Streamer supports fire-and-forget requests since completion can be handled by - //! registering a callback. - struct ExternalRequestData - { - inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium; - inline constexpr static bool s_failWhenUnhandled = true; - - explicit ExternalRequestData(FileRequestPtr&& request); - - FileRequestPtr m_request; //!< The request that was send to Streamer. - }; - - //! Stores an instance of a RequestPath. To reduce copying instances of a RequestPath functions that - //! need a path take them by reference to the original request. In some cases a path originates from - //! within in the stack and temporary storage is needed. This struct allows for that temporary storage - //! so it can be safely referenced later. - struct RequestPathStoreData - { - inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium; - inline constexpr static bool s_failWhenUnhandled = true; - - explicit RequestPathStoreData(RequestPath path); - - RequestPath m_path; - }; - - //! Request to read data. This is an untranslated request and holds a relative path. The Scheduler - //! will translate this to the appropriate ReadData or CompressedReadData. - struct ReadRequestData - { - inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium; - inline constexpr static bool s_failWhenUnhandled = true; - - ReadRequestData(RequestPath path, void* output, u64 outputSize, u64 offset, u64 size, - AZStd::chrono::system_clock::time_point deadline, IStreamerTypes::Priority priority); - ReadRequestData(RequestPath path, IStreamerTypes::RequestMemoryAllocator* allocator, u64 offset, u64 size, - AZStd::chrono::system_clock::time_point deadline, IStreamerTypes::Priority priority); - ~ReadRequestData(); - - RequestPath m_path; //!< Relative path to the target file. - IStreamerTypes::RequestMemoryAllocator* m_allocator; //!< Allocator used to manage the memory for this request. - AZStd::chrono::system_clock::time_point m_deadline; //!< Time by which this request should have been completed. - void* m_output; //!< The memory address assigned (during processing) to store the read data to. - u64 m_outputSize; //!< The memory size of the addressed used to store the read data. - u64 m_offset; //!< The offset in bytes into the file. - u64 m_size; //!< The number of bytes to read from the file. - IStreamerTypes::Priority m_priority; //!< Priority used for ordering requests. This is used when requests have the same deadline. - IStreamerTypes::MemoryType m_memoryType; //!< The type of memory provided by the allocator if used. - }; - - //! Request to read data. This is a translated request and holds an absolute path and has been - //! resolved to the archive file if needed. - struct ReadData - { - inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium; - inline constexpr static bool s_failWhenUnhandled = true; - - ReadData(void* output, u64 outputSize, const RequestPath& path, u64 offset, u64 size, bool sharedRead); - - const RequestPath& m_path; //!< The path to the file that contains the requested data. - void* m_output; //!< Target output to write the read data to. - u64 m_outputSize; //!< Size of memory m_output points to. This needs to be at least as big as m_size, but can be bigger. - u64 m_offset; //!< The offset in bytes into the file. - u64 m_size; //!< The number of bytes to read from the file. - bool m_sharedRead; //!< True if other code will be reading from the file or the stack entry can exclusively lock. - }; - - //! Request to read and decompress data. - struct CompressedReadData - { - inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium; - inline constexpr static bool s_failWhenUnhandled = true; - - CompressedReadData(CompressionInfo&& compressionInfo, void* output, u64 readOffset, u64 readSize); - - CompressionInfo m_compressionInfo; - void* m_output; //!< Target output to write the read data to. - u64 m_readOffset; //!< The offset into the decompressed to start copying from. - u64 m_readSize; //!< Number of bytes to read from the decompressed file. - }; - - //! Holds the progress of an operation chain until this request is explicitly completed. - struct WaitData - { - inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium; - inline constexpr static bool s_failWhenUnhandled = true; - }; - - //! Checks to see if any node in the stack can find a file at the provided path. - struct FileExistsCheckData - { - inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh; - inline constexpr static bool s_failWhenUnhandled = false; - - explicit FileExistsCheckData(const RequestPath& path); - - const RequestPath& m_path; - bool m_found{ false }; - }; - - //! Searches for a file in the stack and retrieves the meta data. This may be slower than a file exists - //! check. - struct FileMetaDataRetrievalData - { - inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh; - inline constexpr static bool s_failWhenUnhandled = false; - - explicit FileMetaDataRetrievalData(const RequestPath& path); - - const RequestPath& m_path; - u64 m_fileSize{ 0 }; - bool m_found{ false }; - }; - - //! Cancels a request in the stream stack, if possible. - struct CancelData - { - inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHighest; - inline constexpr static bool s_failWhenUnhandled = false; - - explicit CancelData(FileRequestPtr target); - - FileRequestPtr m_target; //!< The request that will be canceled. - }; - - //! Updates the priority and deadline of a request that has not been queued yet. - struct RescheduleData - { - inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh; - inline constexpr static bool s_failWhenUnhandled = false; - - RescheduleData(FileRequestPtr target, AZStd::chrono::system_clock::time_point newDeadline, IStreamerTypes::Priority newPriority); - - FileRequestPtr m_target; //!< The request that will be rescheduled. - AZStd::chrono::system_clock::time_point m_newDeadline; //!< The new deadline for the request. - IStreamerTypes::Priority m_newPriority; //!< The new priority for the request. - }; - - //! Flushes all references to the provided file in the streaming stack. - struct FlushData - { - inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh; - inline constexpr static bool s_failWhenUnhandled = false; - - explicit FlushData(RequestPath path); - - RequestPath m_path; - }; - - //! Flushes all caches in the streaming stack. - struct FlushAllData - { - inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh; - inline constexpr static bool s_failWhenUnhandled = false; - }; - - //! Creates a cache dedicated to a single file. This is best used for files where blocks are read from - //! periodically such as audio banks of video files. - struct CreateDedicatedCacheData - { - inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh; - inline constexpr static bool s_failWhenUnhandled = false; - - CreateDedicatedCacheData(RequestPath path, const FileRange& range); - - RequestPath m_path; - FileRange m_range; - }; - - //! Destroys a cache dedicated to a single file that was previously created by CreateDedicatedCache - struct DestroyDedicatedCacheData - { - inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh; - inline constexpr static bool s_failWhenUnhandled = false; - - DestroyDedicatedCacheData(RequestPath path, const FileRange& range); - - RequestPath m_path; - FileRange m_range; - }; - - struct ReportData - { - inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityLow; - inline constexpr static bool s_failWhenUnhandled = false; - - enum class ReportType - { - FileLocks - }; - - explicit ReportData(ReportType reportType); - - ReportType m_reportType; - }; - - //! Data for a custom command. This can be used by nodes added extensions that need data that can't be stored - //! in the already provided data. - struct CustomData - { - inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium; - - CustomData(AZStd::any data, bool failWhenUnhandled); - - AZStd::any m_data; //!< The data for the custom request. - bool m_failWhenUnhandled; //!< Whether or not the request is marked as failed or success when no node process it. - }; - - using CommandVariant = AZStd::variant; + using CommandVariant = Requests::CommandVariant; using OnCompletionCallback = AZStd::function; AZ_CLASS_ALLOCATOR(FileRequest, SystemAllocator, 0); @@ -278,7 +312,7 @@ namespace AZ::IO void CreateFlushAll(); void CreateDedicatedCacheCreation(RequestPath path, const FileRange& range = {}, FileRequest* parent = nullptr); void CreateDedicatedCacheDestruction(RequestPath path, const FileRange& range = {}, FileRequest* parent = nullptr); - void CreateReport(ReportData::ReportType reportType); + void CreateReport(Requests::ReportType reportType); void CreateCustom(AZStd::any data, bool failWhenUnhandled = true, FileRequest* parent = nullptr); void SetCompletionCallback(OnCompletionCallback callback); @@ -325,8 +359,17 @@ namespace AZ::IO //! Command and parameters for the request. CommandVariant m_command; - //! Status of the request. - AZStd::atomic m_status{ IStreamerTypes::RequestStatus::Pending }; + //! Estimated time this request will complete. This is an estimation and depends on many + //! factors which can cause it to change drastically from moment to moment. + AZStd::chrono::system_clock::time_point m_estimatedCompletion; + + //! The file request that has a dependency on this one. This can be null if there are no + //! other request depending on this one to complete. + FileRequest* m_parent{ nullptr }; + + + //! Id assigned when the request is added to the pending queue. + size_t m_pendingId{ 0 }; //! Called once the request has completed. This will always be called from the Streamer thread //! and thread safety is the responsibility of called function. When assigning a lambda avoid @@ -336,16 +379,8 @@ namespace AZ::IO //! a longer running task is needed consider using a job to do the work. OnCompletionCallback m_onCompletion; - //! Estimated time this request will complete. This is an estimation and depends on many - //! factors which can cause it to change drastically from moment to moment. - AZStd::chrono::system_clock::time_point m_estimatedCompletion; - - //! The file request that has a dependency on this one. This can be null if there are no - //! other request depending on this one to complete. - FileRequest* m_parent{ nullptr }; - - //! Id assigned when the request is added to the pending queue. - size_t m_pendingId{ 0 }; + //! Status of the request. + AZStd::atomic m_status{ IStreamerTypes::RequestStatus::Pending }; //! The number of dependent file request that need to complete before this one is done. u16 m_dependencies{ 0 }; diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/FullFileDecompressor.cpp b/Code/Framework/AzCore/AzCore/IO/Streamer/FullFileDecompressor.cpp index 723a5d62c8..ac9344dd28 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/FullFileDecompressor.cpp +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/FullFileDecompressor.cpp @@ -91,12 +91,12 @@ namespace AZ::IO AZStd::visit([this, request](auto&& args) { using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { PrepareReadRequest(request, args); } - else if constexpr (AZStd::is_same_v || - AZStd::is_same_v) + else if constexpr (AZStd::is_same_v || + AZStd::is_same_v) { PrepareDedicatedCache(request, args.m_path); } @@ -114,11 +114,11 @@ namespace AZ::IO AZStd::visit([this, request](auto&& args) { using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { m_pendingReads.push_back(request); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { m_pendingFileExistChecks.push_back(request); } @@ -203,7 +203,7 @@ namespace AZ::IO { FileRequest* compressedRequest = m_processingJobs[i].m_waitRequest->GetParent(); AZ_Assert(compressedRequest, "A wait request attached to FullFileDecompressor was completed but didn't have a parent compressed request."); - auto data = AZStd::get_if(&compressedRequest->GetCommand()); + auto data = AZStd::get_if(&compressedRequest->GetCommand()); AZ_Assert(data, "Compressed request in the decompression queue in FullFileDecompressor didn't contain compression read data."); size_t bytesToDecompress = data->m_compressionInfo.m_compressedSize; @@ -255,7 +255,7 @@ namespace AZ::IO // Calculate the amount of time it will take to decompress the data. FileRequest* compressedRequest = m_readRequests[i]->GetParent(); - auto data = AZStd::get_if(&compressedRequest->GetCommand()); + auto data = AZStd::get_if(&compressedRequest->GetCommand()); size_t bytesToDecompress = data->m_compressionInfo.m_compressedSize; auto decompressionDuration = AZStd::chrono::microseconds( @@ -290,7 +290,7 @@ namespace AZ::IO void FullFileDecompressor::EstimateCompressedReadRequest(FileRequest* request, AZStd::chrono::microseconds& cumulativeDelay, AZStd::chrono::microseconds decompressionDelay, double totalDecompressionDurationUs, double totalBytesDecompressed) const { - auto data = AZStd::get_if(&request->GetCommand()); + auto data = AZStd::get_if(&request->GetCommand()); if (data) { AZStd::chrono::microseconds processingTime = decompressionDelay; @@ -343,7 +343,7 @@ namespace AZ::IO m_numRunningJobs == 0; } - void FullFileDecompressor::PrepareReadRequest(FileRequest* request, FileRequest::ReadRequestData& data) + void FullFileDecompressor::PrepareReadRequest(FileRequest* request, Requests::ReadRequestData &data) { CompressionInfo info; if (CompressionUtils::FindCompressionInfo(info, data.m_path.GetRelativePath())) @@ -359,7 +359,7 @@ namespace AZ::IO { FileRequest* pathStorageRequest = m_context->GetNewInternalRequest(); pathStorageRequest->CreateRequestPathStore(request, AZStd::move(info.m_archiveFilename)); - auto& pathStorage = AZStd::get(pathStorageRequest->GetCommand()); + auto& pathStorage = AZStd::get(pathStorageRequest->GetCommand()); nextRequest->CreateRead(pathStorageRequest, data.m_output, data.m_outputSize, pathStorage.m_path, info.m_offset + data.m_offset, data.m_size, info.m_isSharedPak); @@ -370,13 +370,13 @@ namespace AZ::IO auto callback = [this, nextRequest](const FileRequest& checkRequest) { AZ_PROFILE_FUNCTION(AzCore); - auto check = AZStd::get_if(&checkRequest.GetCommand()); + auto check = AZStd::get_if(&checkRequest.GetCommand()); AZ_Assert(check, "Callback in FullFileDecompressor::PrepareReadRequest expected FileExistsCheck but got another command."); if (check->m_found) { FileRequest* originalRequest = m_context->RejectRequest(nextRequest); - if (AZStd::holds_alternative(originalRequest->GetCommand())) + if (AZStd::holds_alternative(originalRequest->GetCommand())) { originalRequest = m_context->RejectRequest(originalRequest); } @@ -412,12 +412,12 @@ namespace AZ::IO AZStd::visit([request, &info, nextRequest](auto&& args) { using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { nextRequest->CreateDedicatedCacheCreation(AZStd::move(info.m_archiveFilename), FileRange::CreateRange(info.m_offset, info.m_compressedSize), request); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { nextRequest->CreateDedicatedCacheDestruction(AZStd::move(info.m_archiveFilename), FileRange::CreateRange(info.m_offset, info.m_compressedSize), request); @@ -429,7 +429,7 @@ namespace AZ::IO auto callback = [this, nextRequest](const FileRequest& checkRequest) { AZ_PROFILE_FUNCTION(AzCore); - auto check = AZStd::get_if(&checkRequest.GetCommand()); + auto check = AZStd::get_if(&checkRequest.GetCommand()); AZ_Assert(check, "Callback in FullFileDecompressor::PrepareDedicatedCache expected FileExistsCheck but got another command."); if (check->m_found) @@ -461,7 +461,7 @@ namespace AZ::IO void FullFileDecompressor::FileExistsCheck(FileRequest* checkRequest) { - auto& fileCheckRequest = AZStd::get(checkRequest->GetCommand()); + auto& fileCheckRequest = AZStd::get(checkRequest->GetCommand()); CompressionInfo info; if (CompressionUtils::FindCompressionInfo(info, fileCheckRequest.m_path.GetRelativePath())) { @@ -487,7 +487,7 @@ namespace AZ::IO { if (m_readBufferStatus[i] == ReadBufferStatus::Unused) { - auto data = AZStd::get_if(&compressedReadRequest->GetCommand()); + auto data = AZStd::get_if(&compressedReadRequest->GetCommand()); AZ_Assert(data, "Compressed request that's starting a read in FullFileDecompressor didn't contain compression read data."); AZ_Assert(data->m_compressionInfo.m_decompressor, "FileRequest for FullFileDecompressor is missing a decompression callback."); @@ -549,7 +549,7 @@ namespace AZ::IO } else { - auto data = AZStd::get_if(&compressedRequest->GetCommand()); + auto data = AZStd::get_if(&compressedRequest->GetCommand()); AZ_Assert(data, "Compressed request in FullFileDecompressor that finished unsuccessfully didn't contain compression read data."); CompressionInfo& info = data->m_compressionInfo; size_t offsetAdjustment = info.m_offset - AZ_SIZE_ALIGN_DOWN(info.m_offset, aznumeric_cast(m_alignment)); @@ -591,7 +591,7 @@ namespace AZ::IO } FileRequest* waitRequest = m_readRequests[readSlot]; - AZ_Assert(AZStd::holds_alternative(waitRequest->GetCommand()), + AZ_Assert(AZStd::holds_alternative(waitRequest->GetCommand()), "File request waiting for decompression wasn't marked as being a wait operation."); FileRequest* compressedRequest = waitRequest->GetParent(); AZ_Assert(compressedRequest, "Read requests started by FullFileDecompressor is missing a parent request."); @@ -610,7 +610,7 @@ namespace AZ::IO m_readBuffers[readSlot] = nullptr; AZ::Job* decompressionJob; - auto data = AZStd::get_if(&compressedRequest->GetCommand()); + auto data = AZStd::get_if(&compressedRequest->GetCommand()); AZ_Assert(data, "Compressed request in FullFileDecompressor that's starting decompression didn't contain compression read data."); AZ_Assert(data->m_compressionInfo.m_decompressor, "FullFileDecompressor is queuing a decompression job but couldn't find a decompressor."); @@ -664,7 +664,7 @@ namespace AZ::IO FileRequest* compressedRequest = jobInfo.m_waitRequest->GetParent(); AZ_Assert(compressedRequest, "A wait request attached to FullFileDecompressor was completed but didn't have a parent compressed request."); - auto data = AZStd::get_if(&compressedRequest->GetCommand()); + auto data = AZStd::get_if(&compressedRequest->GetCommand()); AZ_Assert(data, "Compressed request in FullFileDecompressor that completed decompression didn't contain compression read data."); CompressionInfo& info = data->m_compressionInfo; size_t offsetAdjustment = info.m_offset - AZ_SIZE_ALIGN_DOWN(info.m_offset, aznumeric_cast(m_alignment)); @@ -694,7 +694,7 @@ namespace AZ::IO FileRequest* compressedRequest = info.m_waitRequest->GetParent(); AZ_Assert(compressedRequest, "A wait request attached to FullFileDecompressor was completed but didn't have a parent compressed request."); - auto request = AZStd::get_if(&compressedRequest->GetCommand()); + auto request = AZStd::get_if(&compressedRequest->GetCommand()); AZ_Assert(request, "Compressed request in FullFileDecompressor that's running full decompression didn't contain compression read data."); CompressionInfo& compressionInfo = request->m_compressionInfo; AZ_Assert(compressionInfo.m_decompressor, "Full decompressor job started, but there's no decompressor callback assigned."); @@ -719,7 +719,7 @@ namespace AZ::IO FileRequest* compressedRequest = info.m_waitRequest->GetParent(); AZ_Assert(compressedRequest, "A wait request attached to FullFileDecompressor was completed but didn't have a parent compressed request."); - auto request = AZStd::get_if(&compressedRequest->GetCommand()); + auto request = AZStd::get_if(&compressedRequest->GetCommand()); AZ_Assert(request, "Compressed request in FullFileDecompressor that's running partial decompression didn't contain compression read data."); CompressionInfo& compressionInfo = request->m_compressionInfo; AZ_Assert(compressionInfo.m_decompressor, "Partial decompressor job started, but there's no decompressor callback assigned."); diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/FullFileDecompressor.h b/Code/Framework/AzCore/AzCore/IO/Streamer/FullFileDecompressor.h index d9bd68f1a1..cb4226fd7c 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/FullFileDecompressor.h +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/FullFileDecompressor.h @@ -21,6 +21,11 @@ namespace AZ::IO { + namespace Requests + { + struct ReadRequestData; + } + struct FullFileDecompressorConfig final : public IStreamerStackConfig { @@ -87,7 +92,7 @@ namespace AZ::IO bool IsIdle() const; - void PrepareReadRequest(FileRequest* request, FileRequest::ReadRequestData& data); + void PrepareReadRequest(FileRequest* request, Requests::ReadRequestData& data); void PrepareDedicatedCache(FileRequest* request, const RequestPath& path); void FileExistsCheck(FileRequest* checkRequest); diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/ReadSplitter.cpp b/Code/Framework/AzCore/AzCore/IO/Streamer/ReadSplitter.cpp index a952e31a93..282a1e15c9 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/ReadSplitter.cpp +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/ReadSplitter.cpp @@ -118,7 +118,7 @@ namespace AZ::IO return; } - auto data = AZStd::get_if(&request->GetCommand()); + auto data = AZStd::get_if(&request->GetCommand()); if (data == nullptr) { StreamStackEntry::QueueRequest(request); @@ -156,7 +156,7 @@ namespace AZ::IO void ReadSplitter::QueueAlignedRead(FileRequest* request) { - auto data = AZStd::get_if(&request->GetCommand()); + auto data = AZStd::get_if(&request->GetCommand()); AZ_Assert(data != nullptr, "Provided request to queue by the Read Splitter did not contain a read command."); if (data->m_size <= m_maxReadSize) @@ -187,7 +187,7 @@ namespace AZ::IO bool ReadSplitter::QueueAlignedRead(PendingRead& pending) { - auto data = AZStd::get_if(&pending.m_request->GetCommand()); + auto data = AZStd::get_if(&pending.m_request->GetCommand()); AZ_Assert(data != nullptr, "Provided request to queue by the Read Splitter did not contain a read command."); while (pending.m_readSize > 0) @@ -237,7 +237,7 @@ namespace AZ::IO void ReadSplitter::QueueBufferedRead(FileRequest* request) { - auto data = AZStd::get_if(&request->GetCommand()); + auto data = AZStd::get_if(&request->GetCommand()); AZ_Assert(data != nullptr, "Provided request to queue by the Read Splitter did not contain a read command."); PendingRead pendingRead; @@ -262,7 +262,7 @@ namespace AZ::IO bool ReadSplitter::QueueBufferedRead(PendingRead& pending) { - auto data = AZStd::get_if(&pending.m_request->GetCommand()); + auto data = AZStd::get_if(&pending.m_request->GetCommand()); AZ_Assert(data != nullptr, "Provided request to queue by the Read Splitter did not contain a read command."); while (pending.m_readSize > 0) diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.cpp b/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.cpp index fe1d5a5eda..65f72946b0 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.cpp +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.cpp @@ -6,9 +6,11 @@ * */ +#include + +#include #include #include -#include #include #include @@ -35,6 +37,10 @@ namespace AZ::IO m_threadData.m_streamStack = AZStd::move(streamStack); } + Scheduler::~Scheduler() + { + } + void Scheduler::Start(const AZStd::thread_desc& threadDesc) { if (!m_isRunning) @@ -222,10 +228,10 @@ namespace AZ::IO { using Command = AZStd::decay_t; if constexpr ( - AZStd::is_same_v || - AZStd::is_same_v) + AZStd::is_same_v || + AZStd::is_same_v) { - auto parentReadRequest = next->GetCommandFromChain(); + auto parentReadRequest = next->GetCommandFromChain(); AZ_Assert(parentReadRequest != nullptr, "The issued read request can't be found for the (compressed) read command."); size_t size = parentReadRequest->m_size; @@ -234,7 +240,7 @@ namespace AZ::IO AZ_Assert(parentReadRequest->m_allocator, "The read request was issued without a memory allocator or valid output address."); u64 recommendedSize = size; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { recommendedSize = m_recommendations.CalculateRecommendedMemorySize(size, parentReadRequest->m_offset); } @@ -249,12 +255,12 @@ namespace AZ::IO parentReadRequest->m_output = allocation.m_address; parentReadRequest->m_outputSize = allocation.m_size; parentReadRequest->m_memoryType = allocation.m_type; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { args.m_output = parentReadRequest->m_output; args.m_outputSize = allocation.m_size; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { args.m_output = parentReadRequest->m_output; } @@ -267,7 +273,7 @@ namespace AZ::IO } #endif - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { m_threadData.m_lastFilePath = args.m_path; m_threadData.m_lastFileOffset = args.m_offset + args.m_size; @@ -275,7 +281,7 @@ namespace AZ::IO m_processingSize += args.m_size; #endif } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { const CompressionInfo& info = args.m_compressionInfo; m_threadData.m_lastFilePath = info.m_archiveFilename; @@ -288,15 +294,15 @@ namespace AZ::IO "Streamer queued %zu: %s", next->GetCommand().index(), parentReadRequest->m_path.GetRelativePath()); m_threadData.m_streamStack->QueueRequest(next); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { return Thread_ProcessCancelRequest(next, args); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { return Thread_ProcessRescheduleRequest(next, args); } - else if constexpr (AZStd::is_same_v || AZStd::is_same_v) + else if constexpr (AZStd::is_same_v || AZStd::is_same_v) { AZ_PROFILE_INTERVAL_START_COLORED(AzCore, next, ProfilerColor, "Streamer queued %zu", next->GetCommand().index()); @@ -345,7 +351,7 @@ namespace AZ::IO #endif { using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { if (args.m_output == nullptr && args.m_allocator != nullptr) { @@ -393,7 +399,7 @@ namespace AZ::IO } } - void Scheduler::Thread_ProcessCancelRequest(FileRequest* request, FileRequest::CancelData& data) + void Scheduler::Thread_ProcessCancelRequest(FileRequest* request, Requests::CancelData& data) { AZ_PROFILE_INTERVAL_START_COLORED(AzCore, request, ProfilerColor, "Streamer queued cancel"); auto& pending = m_context.GetPreparedRequests(); @@ -415,7 +421,7 @@ namespace AZ::IO m_threadData.m_streamStack->QueueRequest(request); } - void Scheduler::Thread_ProcessRescheduleRequest(FileRequest* request, FileRequest::RescheduleData& data) + void Scheduler::Thread_ProcessRescheduleRequest(FileRequest* request, Requests::RescheduleData& data) { AZ_PROFILE_INTERVAL_START_COLORED(AzCore, request, ProfilerColor, "Streamer queued reschedule"); auto& pendingRequests = m_context.GetPreparedRequests(); @@ -424,7 +430,7 @@ namespace AZ::IO if (pending->WorksOn(data.m_target)) { // Read requests are the only requests that use deadlines and dynamic priorities. - auto readRequest = pending->GetCommandFromChain(); + auto readRequest = pending->GetCommandFromChain(); if (readRequest) { readRequest->m_deadline = data.m_newDeadline; @@ -463,8 +469,8 @@ namespace AZ::IO // Order is the same for both requests, so prioritize the request that are at risk of missing // it's deadline. - const FileRequest::ReadRequestData* firstRead = first->GetCommandFromChain(); - const FileRequest::ReadRequestData* secondRead = second->GetCommandFromChain(); + const Requests::ReadRequestData* firstRead = first->GetCommandFromChain(); + const Requests::ReadRequestData* secondRead = second->GetCommandFromChain(); if (firstRead == nullptr || secondRead == nullptr) { @@ -496,11 +502,11 @@ namespace AZ::IO auto sameFile = [this](auto&& args) { using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { return m_threadData.m_lastFilePath == args.m_path; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { return m_threadData.m_lastFilePath == args.m_compressionInfo.m_archiveFilename; } @@ -517,11 +523,11 @@ namespace AZ::IO auto offset = [](auto&& args) -> s64 { using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { return aznumeric_caster(args.m_offset); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { return aznumeric_caster(args.m_compressionInfo.m_offset); } diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.h b/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.h index 053a57d332..502002fd27 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.h +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/Scheduler.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include #include @@ -24,11 +25,19 @@ namespace AZ::IO { class FileRequest; + namespace Requests + { + struct CancelData; + struct RescheduleData; + } // namespace Requests + class Scheduler final { public: explicit Scheduler(AZStd::shared_ptr streamStack, u64 memoryAlignment = AZCORE_GLOBAL_NEW_ALIGNMENT, u64 sizeAlignment = 1, u64 granularity = 1_mib); + ~Scheduler(); + void Start(const AZStd::thread_desc& threadDesc); void Stop(); @@ -61,14 +70,14 @@ namespace AZ::IO bool Thread_ExecuteRequests(); bool Thread_PrepareRequests(AZStd::vector& outstandingRequests); void Thread_ProcessTillIdle(); - void Thread_ProcessCancelRequest(FileRequest* request, FileRequest::CancelData& data); - void Thread_ProcessRescheduleRequest(FileRequest* request, FileRequest::RescheduleData& data); + void Thread_ProcessCancelRequest(FileRequest* request, Requests::CancelData& data); + void Thread_ProcessRescheduleRequest(FileRequest* request, Requests::RescheduleData& data); enum class Order { - FirstRequest, //< The first request is the most important to process next. - SecondRequest, //< The second request is the most important to process next. - Equal //< Both requests are equally important. + FirstRequest, //!< The first request is the most important to process next. + SecondRequest, //!< The second request is the most important to process next. + Equal //!< Both requests are equally important. }; //! Determine which of the two provided requests is more important to process next. Order Thread_PrioritizeRequests(const FileRequest* first, const FileRequest* second) const; diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/StorageDrive.cpp b/Code/Framework/AzCore/AzCore/IO/Streamer/StorageDrive.cpp index cfd191b68f..701eb563ec 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/StorageDrive.cpp +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/StorageDrive.cpp @@ -60,9 +60,9 @@ namespace AZ::IO AZ_PROFILE_FUNCTION(AzCore); AZ_Assert(request, "PrepareRequest was provided a null request."); - if (AZStd::holds_alternative(request->GetCommand())) + if (AZStd::holds_alternative(request->GetCommand())) { - auto& readRequest = AZStd::get(request->GetCommand()); + auto& readRequest = AZStd::get(request->GetCommand()); FileRequest* read = m_context->GetNewInternalRequest(); read->CreateRead(request, readRequest.m_output, readRequest.m_outputSize, readRequest.m_path, @@ -79,29 +79,29 @@ namespace AZ::IO AZStd::visit([this, request](auto&& args) { using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v || - AZStd::is_same_v || - AZStd::is_same_v) + if constexpr (AZStd::is_same_v || + AZStd::is_same_v || + AZStd::is_same_v) { m_pendingRequests.push_back(request); return; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { CancelRequest(request, args.m_target); return; } else { - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { FlushCache(args.m_path); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { FlushEntireCache(); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { Report(args); } @@ -118,15 +118,15 @@ namespace AZ::IO AZStd::visit([this, request](auto&& args) { using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { ReadFile(request); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { FileExistsRequest(request); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { FileMetaDataRetrievalRequest(request); } @@ -199,25 +199,25 @@ namespace AZ::IO AZStd::visit([&](auto&& args) { using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { targetFile = &args.m_path; readSize = args.m_size; offset = args.m_offset; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { targetFile = &args.m_compressionInfo.m_archiveFilename; readSize = args.m_compressionInfo.m_compressedSize; offset = args.m_compressionInfo.m_offset; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { readSize = 0; AZStd::chrono::microseconds averageTime = m_getFileExistsTimeAverage.CalculateAverage(); startTime += averageTime; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { readSize = 0; AZStd::chrono::microseconds averageTime = m_getFileMetaDataTimeAverage.CalculateAverage(); @@ -254,7 +254,7 @@ namespace AZ::IO { AZ_PROFILE_FUNCTION(AzCore); - auto data = AZStd::get_if(&request->GetCommand()); + auto data = AZStd::get_if(&request->GetCommand()); AZ_Assert(data, "FileRequest queued on StorageDrive to be read didn't contain read data."); SystemFile* file = nullptr; @@ -342,7 +342,7 @@ namespace AZ::IO AZ_PROFILE_FUNCTION(AzCore); TIMED_AVERAGE_WINDOW_SCOPE(m_getFileExistsTimeAverage); - auto& fileExists = AZStd::get(request->GetCommand()); + auto& fileExists = AZStd::get(request->GetCommand()); size_t cacheIndex = FindFileInCache(fileExists.m_path); if (cacheIndex != s_fileNotFound) { @@ -360,7 +360,7 @@ namespace AZ::IO AZ_PROFILE_FUNCTION(AzCore); TIMED_AVERAGE_WINDOW_SCOPE(m_getFileMetaDataTimeAverage); - auto& command = AZStd::get(request->GetCommand()); + auto& command = AZStd::get(request->GetCommand()); // If the file is already open, use the file handle which usually is cheaper than asking for the file by name. size_t cacheIndex = FindFileInCache(command.m_path); if (cacheIndex != s_fileNotFound) @@ -446,11 +446,11 @@ namespace AZ::IO } } - void StorageDrive::Report(const FileRequest::ReportData& data) const + void StorageDrive::Report(const Requests::ReportData& data) const { switch (data.m_reportType) { - case FileRequest::ReportData::ReportType::FileLocks: + case Requests::ReportType::FileLocks: for (u32 i = 0; i < m_fileHandles.size(); ++i) { if (m_fileHandles[i] != nullptr) diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/StorageDrive.h b/Code/Framework/AzCore/AzCore/IO/Streamer/StorageDrive.h index d90b31eeec..25f3d7b353 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/StorageDrive.h +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/StorageDrive.h @@ -8,6 +8,7 @@ #pragma once +#include #include #include #include @@ -16,6 +17,11 @@ #include #include +namespace AZ::IO::Requests +{ + struct ReportData; +} + namespace AZ::IO { struct StorageDriveConfig final : @@ -72,7 +78,7 @@ namespace AZ::IO void EstimateCompletionTimeForRequest(FileRequest* request, AZStd::chrono::system_clock::time_point& startTime, const RequestPath*& activeFile, u64& activeOffset) const; - void Report(const FileRequest::ReportData& data) const; + void Report(const Requests::ReportData& data) const; TimedAverageWindow m_fileOpenCloseTimeAverage; TimedAverageWindow m_getFileExistsTimeAverage; diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/Streamer.cpp b/Code/Framework/AzCore/AzCore/IO/Streamer/Streamer.cpp index e4976f7d1c..dfc156bbee 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/Streamer.cpp +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/Streamer.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -210,7 +211,7 @@ namespace AZ::IO IStreamerTypes::ClaimMemory claimMemory) const { AZ_Assert(request.m_request, "The request handle provided to Streamer::GetReadRequestResult is invalid."); - auto readRequest = AZStd::get_if(&request.m_request->GetCommand()); + auto readRequest = AZStd::get_if(&request.m_request->GetCommand()); if (readRequest != nullptr) { buffer = readRequest->m_output; @@ -281,14 +282,14 @@ namespace AZ::IO } } - FileRequestPtr Streamer::Report(FileRequest::ReportData::ReportType reportType) + FileRequestPtr Streamer::Report(Requests::ReportType reportType) { FileRequestPtr result = CreateRequest(); Report(result, reportType); return result; } - FileRequestPtr& Streamer::Report(FileRequestPtr& request, FileRequest::ReportData::ReportType reportType) + FileRequestPtr& Streamer::Report(FileRequestPtr& request, Requests::ReportType reportType) { request->m_request.CreateReport(reportType); return request; diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/Streamer.h b/Code/Framework/AzCore/AzCore/IO/Streamer/Streamer.h index bb363a0c64..7e3dd1a742 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/Streamer.h +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/Streamer.h @@ -20,6 +20,10 @@ namespace AZStd struct thread_desc; } +namespace AZ::IO::Requests +{ + enum class ReportType : int8_t; +} namespace AZ::IO { @@ -185,9 +189,9 @@ namespace AZ::IO void RecordStatistics(); //! Tells AZ::IO::Streamer the report the information for the report to the output. - FileRequestPtr Report(FileRequest::ReportData::ReportType reportType); + FileRequestPtr Report(Requests::ReportType reportType); //! Tells AZ::IO::Streamer the report the information for the report to the output. - FileRequestPtr& Report(FileRequestPtr& request, FileRequest::ReportData::ReportType reportType); + FileRequestPtr& Report(FileRequestPtr& request, Requests::ReportType reportType); Streamer(const AZStd::thread_desc& threadDesc, AZStd::unique_ptr streamStack); diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerComponent.cpp b/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerComponent.cpp index 9a465021c2..25fdb9bdfb 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerComponent.cpp +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerComponent.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -207,7 +208,7 @@ namespace AZ { if (m_streamer) { - m_streamer->QueueRequest(m_streamer->Report(AZ::IO::FileRequest::ReportData::ReportType::FileLocks)); + m_streamer->QueueRequest(m_streamer->Report(AZ::IO::Requests::ReportType::FileLocks)); } } diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerContext.cpp b/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerContext.cpp index 5cd483bc55..fc5d6468d8 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerContext.cpp +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerContext.cpp @@ -22,6 +22,10 @@ namespace AZ static constexpr char LatePredictionName[] = "Early completions"; static constexpr char MissedDeadlinesName[] = "Missed deadlines"; #endif // AZ_STREAMER_ADD_EXTRA_PROFILING_INFO + + StreamerContext::StreamerContext() + { + } StreamerContext::~StreamerContext() { for (FileRequest* entry : m_internalRecycleBin) @@ -204,7 +208,7 @@ namespace AZ m_latePredictionsPercentageStat.GetMostRecentSample()); } } - auto readRequest = AZStd::get_if(&top->GetCommand()); + auto readRequest = AZStd::get_if(&top->GetCommand()); if (readRequest != nullptr) { m_missedDeadlinePercentageStat.PushSample(now < readRequest->m_deadline ? 0.0 : 1.0); diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerContext.h b/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerContext.h index 356eb7ddac..f4caaffc70 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerContext.h +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/StreamerContext.h @@ -7,23 +7,28 @@ */ #pragma once -#include -#include #include #include #include -#include -#include -#include #include +#include +#include +#include +#include namespace AZ::IO { + class FileRequest; + class ExternalFileRequest; + + using FileRequestPtr = AZStd::intrusive_ptr; + class StreamerContext { public: using PreparedQueue = AZStd::deque; + StreamerContext(); ~StreamerContext(); //! Gets a new file request, either by creating a new instance or diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/IO/Streamer/StorageDrive_Windows.cpp b/Code/Framework/AzCore/Platform/Windows/AzCore/IO/Streamer/StorageDrive_Windows.cpp index feb8bce111..708bacd7cd 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/IO/Streamer/StorageDrive_Windows.cpp +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/IO/Streamer/StorageDrive_Windows.cpp @@ -172,9 +172,9 @@ namespace AZ::IO AZ_PROFILE_FUNCTION(AzCore); AZ_Assert(request, "PrepareRequest was provided a null request."); - if (AZStd::holds_alternative(request->GetCommand())) + if (AZStd::holds_alternative(request->GetCommand())) { - auto& readRequest = AZStd::get(request->GetCommand()); + auto& readRequest = AZStd::get(request->GetCommand()); if (IsServicedByThisDrive(readRequest.m_path.GetAbsolutePath())) { FileRequest* read = m_context->GetNewInternalRequest(); @@ -195,7 +195,7 @@ namespace AZ::IO AZStd::visit([this, request](auto&& args) { using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { if (IsServicedByThisDrive(args.m_path.GetAbsolutePath())) { @@ -203,8 +203,8 @@ namespace AZ::IO return; } } - else if constexpr (AZStd::is_same_v || - AZStd::is_same_v) + else if constexpr (AZStd::is_same_v || + AZStd::is_same_v) { if (IsServicedByThisDrive(args.m_path.GetAbsolutePath())) { @@ -212,7 +212,7 @@ namespace AZ::IO return; } } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { if (CancelRequest(request, args.m_target)) { @@ -221,15 +221,15 @@ namespace AZ::IO return; } } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { FlushCache(args.m_path); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { FlushEntireCache(); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { Report(args); } @@ -257,13 +257,13 @@ namespace AZ::IO hasWorked = AZStd::visit([this, request](auto&& args) { using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { FileExistsRequest(request); m_pendingRequests.pop_front(); return true; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { FileMetaDataRetrievalRequest(request); m_pendingRequests.pop_front(); @@ -308,7 +308,7 @@ namespace AZ::IO FileReadInformation& read = m_readSlots_readInfo[i]; u64 totalBytesRead = m_readSizeAverage.GetTotal(); double totalReadTimeUSec = aznumeric_caster(m_readTimeAverage.GetTotal().count()); - auto readCommand = AZStd::get_if(&read.m_request->GetCommand()); + auto readCommand = AZStd::get_if(&read.m_request->GetCommand()); AZ_Assert(readCommand, "Request currently reading doesn't contain a read command."); auto endTime = read.m_startTime + AZStd::chrono::microseconds(aznumeric_cast((readCommand->m_size * totalReadTimeUSec) / totalBytesRead)); earliestSlot = AZStd::min(earliestSlot, endTime); @@ -354,25 +354,25 @@ namespace AZ::IO AZStd::visit([&](auto&& args) { using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { targetFile = &args.m_path; readSize = args.m_size; offset = args.m_offset; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { targetFile = &args.m_compressionInfo.m_archiveFilename; readSize = args.m_compressionInfo.m_compressedSize; offset = args.m_compressionInfo.m_offset; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { readSize = 0; AZStd::chrono::microseconds getFileExistsTimeAverage = m_getFileExistsTimeAverage.CalculateAverage(); startTime += getFileExistsTimeAverage; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { readSize = 0; AZStd::chrono::microseconds getFileExistsTimeAverage = m_getFileMetaDataRetrievalTimeAverage.CalculateAverage(); @@ -411,15 +411,15 @@ namespace AZ::IO AZStd::visit([&, this](auto&& args) { using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v || - AZStd::is_same_v) + if constexpr (AZStd::is_same_v || + AZStd::is_same_v) { if (IsServicedByThisDrive(args.m_path.GetAbsolutePath())) { EstimateCompletionTimeForRequest(request, startTime, activeFile, activeOffset); } } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { if (IsServicedByThisDrive(args.m_compressionInfo.m_archiveFilename.GetAbsolutePath())) { @@ -435,7 +435,7 @@ namespace AZ::IO aznumeric_cast(m_pendingRequests.size()) - m_activeReads_Count; } - auto StorageDriveWin::OpenFile(HANDLE& fileHandle, size_t& cacheSlot, FileRequest* request, const FileRequest::ReadData& data) -> OpenFileResult + auto StorageDriveWin::OpenFile(HANDLE& fileHandle, size_t& cacheSlot, FileRequest* request, const Requests::ReadData& data) -> OpenFileResult { HANDLE file = INVALID_HANDLE_VALUE; @@ -553,7 +553,7 @@ namespace AZ::IO return false; } - auto data = AZStd::get_if(&request->GetCommand()); + auto data = AZStd::get_if(&request->GetCommand()); AZ_Assert(data, "Read request in StorageDriveWin doesn't contain read data."); HANDLE file = INVALID_HANDLE_VALUE; @@ -780,7 +780,7 @@ namespace AZ::IO void StorageDriveWin::FileExistsRequest(FileRequest* request) { - auto& fileExists = AZStd::get(request->GetCommand()); + auto& fileExists = AZStd::get(request->GetCommand()); AZ_PROFILE_SCOPE(AzCore, "StorageDriveWin::FileExistsRequest %s : %s", m_name.c_str(), fileExists.m_path.GetRelativePath()); @@ -836,7 +836,7 @@ namespace AZ::IO void StorageDriveWin::FileMetaDataRetrievalRequest(FileRequest* request) { - auto& command = AZStd::get(request->GetCommand()); + auto& command = AZStd::get(request->GetCommand()); AZ_PROFILE_SCOPE(AzCore, "StorageDriveWin::FileMetaDataRetrievalRequest %s : %s", m_name.c_str(), command.m_path.GetRelativePath()); @@ -1005,7 +1005,7 @@ namespace AZ::IO FileReadInformation& fileReadInfo = m_readSlots_readInfo[readSlot]; - auto readCommand = AZStd::get_if(&fileReadInfo.m_request->GetCommand()); + auto readCommand = AZStd::get_if(&fileReadInfo.m_request->GetCommand()); AZ_Assert(readCommand != nullptr, "Request stored with the overlapped I/O call did not contain a read request."); if (fileReadInfo.m_sectorAlignedOutput && !encounteredError) @@ -1147,11 +1147,11 @@ namespace AZ::IO StreamStackEntry::CollectStatistics(statistics); } - void StorageDriveWin::Report(const FileRequest::ReportData& data) const + void StorageDriveWin::Report(const Requests::ReportData& data) const { switch (data.m_reportType) { - case FileRequest::ReportData::ReportType::FileLocks: + case Requests::ReportType::FileLocks: if (m_cachesInitialized) { for (u32 i = 0; i < m_maxFileHandles; ++i) diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/IO/Streamer/StorageDrive_Windows.h b/Code/Framework/AzCore/Platform/Windows/AzCore/IO/Streamer/StorageDrive_Windows.h index c70eb7804d..5207d094ef 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/IO/Streamer/StorageDrive_Windows.h +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/IO/Streamer/StorageDrive_Windows.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include #include @@ -19,6 +20,12 @@ #include #include +namespace AZ::IO::Requests +{ + struct ReadData; + struct ReportData; +} + namespace AZ::IO { class StorageDriveWin @@ -111,7 +118,7 @@ namespace AZ::IO CacheFull }; - OpenFileResult OpenFile(HANDLE& fileHandle, size_t& cacheSlot, FileRequest* request, const FileRequest::ReadData& data); + OpenFileResult OpenFile(HANDLE& fileHandle, size_t& cacheSlot, FileRequest* request, const Requests::ReadData& data); bool ReadRequest(FileRequest* request); bool ReadRequest(FileRequest* request, size_t readSlot); bool CancelRequest(FileRequest* cancelRequest, FileRequestPtr& target); @@ -137,7 +144,7 @@ namespace AZ::IO void FinalizeSingleRequest(FileReadStatus& status, size_t readSlot, DWORD numBytesTransferred, bool isCanceled, bool encounteredError); - void Report(const FileRequest::ReportData& data) const; + void Report(const Requests::ReportData& data) const; TimedAverageWindow m_fileOpenCloseTimeAverage; TimedAverageWindow m_getFileExistsTimeAverage; diff --git a/Code/Framework/AzCore/Tests/Asset/AssetDataStreamTests.cpp b/Code/Framework/AzCore/Tests/Asset/AssetDataStreamTests.cpp index 27903495f1..3846c6cf16 100644 --- a/Code/Framework/AzCore/Tests/Asset/AssetDataStreamTests.cpp +++ b/Code/Framework/AzCore/Tests/Asset/AssetDataStreamTests.cpp @@ -6,6 +6,7 @@ * */ #include +#include #include #include #include diff --git a/Code/Framework/AzCore/Tests/Platform/Windows/Tests/IO/Streamer/StorageDriveTests_Windows.cpp b/Code/Framework/AzCore/Tests/Platform/Windows/Tests/IO/Streamer/StorageDriveTests_Windows.cpp index e312e2058d..95b0626d7f 100644 --- a/Code/Framework/AzCore/Tests/Platform/Windows/Tests/IO/Streamer/StorageDriveTests_Windows.cpp +++ b/Code/Framework/AzCore/Tests/Platform/Windows/Tests/IO/Streamer/StorageDriveTests_Windows.cpp @@ -406,7 +406,7 @@ namespace AZ::IO request->CreateFileMetaDataRetrieval(path); request->SetCompletionCallback([](const FileRequest& request) { - auto& fileMetaData = AZStd::get(request.GetCommand()); + auto& fileMetaData = AZStd::get(request.GetCommand()); EXPECT_FALSE(fileMetaData.m_found); EXPECT_EQ(0, fileMetaData.m_fileSize); }); @@ -424,7 +424,7 @@ namespace AZ::IO request->SetCompletionCallback([](const FileRequest& request) { - auto& fileMetaData = AZStd::get(request.GetCommand()); + auto& fileMetaData = AZStd::get(request.GetCommand()); EXPECT_TRUE(fileMetaData.m_found); EXPECT_EQ(4_kib, fileMetaData.m_fileSize); }); @@ -442,7 +442,7 @@ namespace AZ::IO request->CreateFileMetaDataRetrieval(path); request->SetCompletionCallback([](const FileRequest& request) { - auto& fileMetaData = AZStd::get(request.GetCommand()); + auto& fileMetaData = AZStd::get(request.GetCommand()); EXPECT_FALSE(fileMetaData.m_found); EXPECT_EQ(0, fileMetaData.m_fileSize); }); @@ -460,7 +460,7 @@ namespace AZ::IO request->SetCompletionCallback([](const FileRequest& request) { - auto& fileMetaData = AZStd::get(request.GetCommand()); + auto& fileMetaData = AZStd::get(request.GetCommand()); EXPECT_TRUE(fileMetaData.m_found); EXPECT_EQ(16_kib, fileMetaData.m_fileSize); }); @@ -484,7 +484,7 @@ namespace AZ::IO request->SetCompletionCallback([](const FileRequest& request) { - auto& fileMetaData = AZStd::get(request.GetCommand()); + auto& fileMetaData = AZStd::get(request.GetCommand()); EXPECT_TRUE(fileMetaData.m_found); EXPECT_EQ(4_kib, fileMetaData.m_fileSize); }); @@ -502,7 +502,7 @@ namespace AZ::IO request->CreateFileExistsCheck(invalidPath); request->SetCompletionCallback([](const FileRequest& request) { - auto& fileExistsCheck = AZStd::get(request.GetCommand()); + auto& fileExistsCheck = AZStd::get(request.GetCommand()); EXPECT_EQ(AZ::IO::IStreamerTypes::RequestStatus::Completed, request.GetStatus()); EXPECT_FALSE(fileExistsCheck.m_found); }); @@ -519,7 +519,7 @@ namespace AZ::IO request->CreateFileExistsCheck(path); request->SetCompletionCallback([](const FileRequest& request) { - auto& fileExistsCheck = AZStd::get(request.GetCommand()); + auto& fileExistsCheck = AZStd::get(request.GetCommand()); EXPECT_EQ(AZ::IO::IStreamerTypes::RequestStatus::Completed, request.GetStatus()); EXPECT_FALSE(fileExistsCheck.m_found); }); @@ -535,7 +535,7 @@ namespace AZ::IO request->CreateFileExistsCheck(m_dummyRequestPath); request->SetCompletionCallback([](const FileRequest& request) { - auto& fileExistsCheck = AZStd::get(request.GetCommand()); + auto& fileExistsCheck = AZStd::get(request.GetCommand()); EXPECT_EQ(AZ::IO::IStreamerTypes::RequestStatus::Completed, request.GetStatus()); EXPECT_TRUE(fileExistsCheck.m_found); }); @@ -551,7 +551,7 @@ namespace AZ::IO request->CreateFileExistsCheck(m_dummyRequestPath); request->SetCompletionCallback([](const FileRequest& request) { - auto& fileExistsCheck = AZStd::get(request.GetCommand()); + auto& fileExistsCheck = AZStd::get(request.GetCommand()); EXPECT_EQ(AZ::IO::IStreamerTypes::RequestStatus::Completed, request.GetStatus()); EXPECT_TRUE(fileExistsCheck.m_found); }); @@ -573,7 +573,7 @@ namespace AZ::IO request->CreateFileExistsCheck(m_dummyRequestPath); request->SetCompletionCallback([](const FileRequest& request) { - auto& fileExistsCheck = AZStd::get(request.GetCommand()); + auto& fileExistsCheck = AZStd::get(request.GetCommand()); EXPECT_EQ(AZ::IO::IStreamerTypes::RequestStatus::Completed, request.GetStatus()); EXPECT_TRUE(fileExistsCheck.m_found); }); @@ -603,7 +603,7 @@ namespace AZ::IO AZ_POP_DISABLE_WARNING { EXPECT_EQ(request.GetStatus(), AZ::IO::IStreamerTypes::RequestStatus::Completed); - auto& readRequest = AZStd::get(request.GetCommand()); + auto& readRequest = AZStd::get(request.GetCommand()); EXPECT_EQ(readRequest.m_size, fileSize); EXPECT_STREQ(readRequest.m_path.GetAbsolutePath(), m_dummyFilepath.c_str()); }; @@ -648,7 +648,7 @@ namespace AZ::IO AZ_POP_DISABLE_WARNING { EXPECT_EQ(request.GetStatus(), AZ::IO::IStreamerTypes::RequestStatus::Completed); - auto& readRequest = AZStd::get(request.GetCommand()); + auto& readRequest = AZStd::get(request.GetCommand()); EXPECT_EQ(readRequest.m_size, unalignedSize); EXPECT_EQ(readRequest.m_offset, unalignedOffset); EXPECT_STREQ(readRequest.m_path.GetAbsolutePath(), m_dummyFilepath.c_str()); @@ -796,7 +796,7 @@ namespace AZ::IO AZ_POP_DISABLE_WARNING { EXPECT_EQ(request.GetStatus(), AZ::IO::IStreamerTypes::RequestStatus::Completed); - auto& readRequest = AZStd::get(request.GetCommand()); + auto& readRequest = AZStd::get(request.GetCommand()); EXPECT_EQ(readRequest.m_size, chunkSize); EXPECT_EQ(readRequest.m_offset, i * chunkSize); }; diff --git a/Code/Framework/AzCore/Tests/Streamer/BlockCacheTests.cpp b/Code/Framework/AzCore/Tests/Streamer/BlockCacheTests.cpp index 3a107da61d..d9d3623fbd 100644 --- a/Code/Framework/AzCore/Tests/Streamer/BlockCacheTests.cpp +++ b/Code/Framework/AzCore/Tests/Streamer/BlockCacheTests.cpp @@ -100,7 +100,7 @@ namespace AZ::IO void QueueReadRequest(FileRequest* request) { - auto data = AZStd::get_if(&request->GetCommand()); + auto data = AZStd::get_if(&request->GetCommand()); if (data) { if (m_fakeFileFound) @@ -122,15 +122,15 @@ namespace AZ::IO m_context->MarkRequestAsCompleted(request); } else if ( - AZStd::holds_alternative(request->GetCommand()) || - AZStd::holds_alternative(request->GetCommand())) + AZStd::holds_alternative(request->GetCommand()) || + AZStd::holds_alternative(request->GetCommand())) { request->SetStatus(IStreamerTypes::RequestStatus::Completed); m_context->MarkRequestAsCompleted(request); } - else if (AZStd::holds_alternative(request->GetCommand())) + else if (AZStd::holds_alternative(request->GetCommand())) { - auto& data2 = AZStd::get(request->GetCommand()); + auto& data2 = AZStd::get(request->GetCommand()); data2.m_found = m_fakeFileFound; data2.m_fileSize = m_fakeFileLength; request->SetStatus(m_fakeFileFound ? IStreamerTypes::RequestStatus::Completed : IStreamerTypes::RequestStatus::Failed); @@ -158,16 +158,16 @@ namespace AZ::IO void QueueCanceledReadRequest(FileRequest* request) { - auto data = AZStd::get_if(&request->GetCommand()); + auto data = AZStd::get_if(&request->GetCommand()); if (data) { ReadFile(data->m_output, data->m_path, data->m_offset, data->m_size); request->SetStatus(IStreamerTypes::RequestStatus::Canceled); m_context->MarkRequestAsCompleted(request); } - else if (AZStd::holds_alternative(request->GetCommand())) + else if (AZStd::holds_alternative(request->GetCommand())) { - auto& data2 = AZStd::get(request->GetCommand()); + auto& data2 = AZStd::get(request->GetCommand()); data2.m_found = true; data2.m_fileSize = m_fakeFileLength; request->SetStatus(IStreamerTypes::RequestStatus::Completed); diff --git a/Code/Framework/AzCore/Tests/Streamer/FullDecompressorTests.cpp b/Code/Framework/AzCore/Tests/Streamer/FullDecompressorTests.cpp index 9f2f0dbd6b..f465a0dafb 100644 --- a/Code/Framework/AzCore/Tests/Streamer/FullDecompressorTests.cpp +++ b/Code/Framework/AzCore/Tests/Streamer/FullDecompressorTests.cpp @@ -145,7 +145,7 @@ namespace AZ::IO void PrepareReadRequest(FileRequest* request) { - auto data = AZStd::get_if(&request->GetCommand()); + auto data = AZStd::get_if(&request->GetCommand()); ASSERT_NE(nullptr, data); u64 size = data->m_size >> 2; diff --git a/Code/Framework/AzCore/Tests/Streamer/IStreamerMock.h b/Code/Framework/AzCore/Tests/Streamer/IStreamerMock.h index 7b784caffd..0059a25b93 100644 --- a/Code/Framework/AzCore/Tests/Streamer/IStreamerMock.h +++ b/Code/Framework/AzCore/Tests/Streamer/IStreamerMock.h @@ -9,6 +9,7 @@ #include #include +#include using namespace AZ::IO; diff --git a/Code/Framework/AzCore/Tests/Streamer/ReadSplitterTests.cpp b/Code/Framework/AzCore/Tests/Streamer/ReadSplitterTests.cpp index a68ce091b8..01fe2f6a12 100644 --- a/Code/Framework/AzCore/Tests/Streamer/ReadSplitterTests.cpp +++ b/Code/Framework/AzCore/Tests/Streamer/ReadSplitterTests.cpp @@ -155,7 +155,7 @@ namespace AZ::IO { EXPECT_EQ(subRequests[i]->GetParent(), readRequest); - FileRequest::ReadData* data = AZStd::get_if(&subRequests[i]->GetCommand()); + Requests::ReadData* data = AZStd::get_if(&subRequests[i]->GetCommand()); ASSERT_NE(nullptr, data); EXPECT_EQ(SplitSize, data->m_size); EXPECT_EQ(SplitSize * i, data->m_offset); @@ -210,7 +210,7 @@ namespace AZ::IO { EXPECT_EQ(subRequests[i]->GetParent(), readRequest); - FileRequest::ReadData* data = AZStd::get_if(&subRequests[i]->GetCommand()); + Requests::ReadData* data = AZStd::get_if(&subRequests[i]->GetCommand()); ASSERT_NE(nullptr, data); EXPECT_EQ(SplitSize, data->m_size); EXPECT_EQ(SplitSize * i, data->m_offset); @@ -230,7 +230,7 @@ namespace AZ::IO { EXPECT_EQ(subRequests[i]->GetParent(), readRequest); - FileRequest::ReadData* data = AZStd::get_if(&subRequests[i]->GetCommand()); + Requests::ReadData* data = AZStd::get_if(&subRequests[i]->GetCommand()); ASSERT_NE(nullptr, data); EXPECT_EQ(SplitSize, data->m_size); EXPECT_EQ(SplitSize * (batchSize + i), data->m_offset); @@ -265,7 +265,7 @@ namespace AZ::IO m_readSplitter->QueueRequest(readRequest); ASSERT_NE(nullptr, subRequest); - FileRequest::ReadData* data = AZStd::get_if(&subRequest->GetCommand()); + Requests::ReadData* data = AZStd::get_if(&subRequest->GetCommand()); EXPECT_NE(buffer, data->m_output); EXPECT_EQ(readSize, data->m_size); EXPECT_EQ(0, data->m_offset); @@ -311,7 +311,7 @@ namespace AZ::IO m_readSplitter->QueueRequest(readRequest); ASSERT_NE(nullptr, subRequest); - FileRequest::ReadData* data = AZStd::get_if(&subRequest->GetCommand()); + Requests::ReadData* data = AZStd::get_if(&subRequest->GetCommand()); EXPECT_NE(buffer, data->m_output); EXPECT_EQ(readSize + offsetAdjustment, data->m_size); EXPECT_EQ(0, data->m_offset); diff --git a/Code/Framework/AzCore/Tests/Streamer/SchedulerTests.cpp b/Code/Framework/AzCore/Tests/Streamer/SchedulerTests.cpp index 6c360b97de..d1484b7409 100644 --- a/Code/Framework/AzCore/Tests/Streamer/SchedulerTests.cpp +++ b/Code/Framework/AzCore/Tests/Streamer/SchedulerTests.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -86,7 +87,7 @@ namespace AZ::IO .WillOnce([this](FileRequest* request) { AZ_Assert(m_streamerContext, "AZ::IO::Streamer is not ready to process requests."); - auto readData = AZStd::get_if(&request->GetCommand()); + auto readData = AZStd::get_if(&request->GetCommand()); AZ_Assert(readData, "Test didn't pass in the correct request."); FileRequest* read = m_streamerContext->GetNewInternalRequest(); read->CreateRead(request, readData->m_output, readData->m_outputSize, readData->m_path, @@ -99,7 +100,7 @@ namespace AZ::IO .WillOnce([this](FileRequest* request) { AZ_Assert(m_streamerContext, "AZ::IO::Streamer is not ready to process requests."); - auto readData = AZStd::get_if(&request->GetCommand()); + auto readData = AZStd::get_if(&request->GetCommand()); AZ_Assert(readData, "Test didn't pass in the correct request."); auto output = reinterpret_cast(readData->m_output); AZ_Assert(output != nullptr, "Output buffer has not been set."); @@ -304,7 +305,7 @@ namespace AZ::IO EXPECT_CALL(*m_mock, QueueRequest(_)).Times(1) .WillOnce(Invoke([this](FileRequest* request) { - auto* read = request->GetCommandFromChain(); + auto* read = request->GetCommandFromChain(); ASSERT_NE(nullptr, read); EXPECT_LT(read->m_deadline, FileRequest::s_noDeadlineTime); EXPECT_EQ(read->m_priority, IStreamerTypes::s_priorityHighest); diff --git a/Code/Framework/AzCore/Tests/Streamer/StreamStackEntryConformityTests.h b/Code/Framework/AzCore/Tests/Streamer/StreamStackEntryConformityTests.h index 6cbec7ea8a..8a5805cccd 100644 --- a/Code/Framework/AzCore/Tests/Streamer/StreamStackEntryConformityTests.h +++ b/Code/Framework/AzCore/Tests/Streamer/StreamStackEntryConformityTests.h @@ -10,6 +10,7 @@ #include #include +#include #include #include #include diff --git a/Code/Framework/AzCore/Tests/StreamerTests.cpp b/Code/Framework/AzCore/Tests/StreamerTests.cpp index 78f9f9060f..937b6d29de 100644 --- a/Code/Framework/AzCore/Tests/StreamerTests.cpp +++ b/Code/Framework/AzCore/Tests/StreamerTests.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetSystemComponent.cpp b/Code/Framework/AzFramework/AzFramework/Asset/AssetSystemComponent.cpp index bb361e56de..35c23d119a 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/AssetSystemComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetSystemComponent.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/IO/RemoteStorageDrive.cpp b/Code/Framework/AzFramework/AzFramework/IO/RemoteStorageDrive.cpp index 589c805871..23d275cb78 100644 --- a/Code/Framework/AzFramework/AzFramework/IO/RemoteStorageDrive.cpp +++ b/Code/Framework/AzFramework/AzFramework/IO/RemoteStorageDrive.cpp @@ -83,9 +83,9 @@ namespace AzFramework AZ_PROFILE_FUNCTION(AzCore); AZ_Assert(request, "PrepareRequest was provided a null request."); - if (AZStd::holds_alternative(request->GetCommand())) + if (AZStd::holds_alternative(request->GetCommand())) { - auto& readRequest = AZStd::get(request->GetCommand()); + auto& readRequest = AZStd::get(request->GetCommand()); FileRequest* read = m_context->GetNewInternalRequest(); read->CreateRead(request, readRequest.m_output, readRequest.m_outputSize, readRequest.m_path, @@ -106,14 +106,14 @@ namespace AzFramework { using namespace AZ::IO; using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v || - AZStd::is_same_v || - AZStd::is_same_v) + if constexpr (AZStd::is_same_v || + AZStd::is_same_v || + AZStd::is_same_v) { m_pendingRequests.push_back(request); return; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { if (CancelRequest(request, args.m_target)) { @@ -124,15 +124,15 @@ namespace AzFramework } else { - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { FlushCache(args.m_path); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { FlushEntireCache(); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { Report(args); } @@ -152,15 +152,15 @@ namespace AzFramework { using namespace AZ::IO; using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { ReadFile(request); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { FileExistsRequest(request); } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { FileMetaDataRetrievalRequest(request); } @@ -232,23 +232,23 @@ namespace AzFramework { using namespace AZ::IO; using Command = AZStd::decay_t; - if constexpr (AZStd::is_same_v) + if constexpr (AZStd::is_same_v) { targetFile = &args.m_path; readSize = args.m_size; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { targetFile = &args.m_compressionInfo.m_archiveFilename; readSize = args.m_compressionInfo.m_compressedSize; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { readSize = 0; AZStd::chrono::microseconds averageTime = m_getFileExistsTimeAverage.CalculateAverage(); startTime += averageTime; } - else if constexpr (AZStd::is_same_v) + else if constexpr (AZStd::is_same_v) { readSize = 0; AZStd::chrono::microseconds averageTime = m_getFileMetaDataTimeAverage.CalculateAverage(); @@ -280,7 +280,7 @@ namespace AzFramework AZ_PROFILE_FUNCTION(AzCore); - auto data = AZStd::get_if(&request->GetCommand()); + auto data = AZStd::get_if(&request->GetCommand()); AZ_Assert(data, "Request doing reading in the RemoteStorageDrive didn't contain read data."); HandleType file = InvalidHandle; @@ -397,7 +397,7 @@ namespace AzFramework TIMED_AVERAGE_WINDOW_SCOPE(m_getFileExistsTimeAverage); - auto& fileExists = AZStd::get(request->GetCommand()); + auto& fileExists = AZStd::get(request->GetCommand()); size_t cacheIndex = FindFileInCache(fileExists.m_path); if (cacheIndex != s_fileNotFound) { @@ -430,7 +430,7 @@ namespace AzFramework AZ::u64 fileSize = 0; bool found = false; - auto& command = AZStd::get(request->GetCommand()); + auto& command = AZStd::get(request->GetCommand()); // If the file is already open, use the file handle which usually is cheaper than asking for the file by name. size_t cacheIndex = FindFileInCache(command.m_path); if (cacheIndex != s_fileNotFound) @@ -526,13 +526,13 @@ namespace AzFramework StreamStackEntry::CollectStatistics(statistics); } - void RemoteStorageDrive::Report(const AZ::IO::FileRequest::ReportData& data) const + void RemoteStorageDrive::Report(const AZ::IO::Requests::ReportData& data) const { using namespace AZ::IO; switch (data.m_reportType) { - case FileRequest::ReportData::ReportType::FileLocks: + case Requests::ReportType::FileLocks: for (AZ::u32 i = 0; i < m_fileHandles.size(); ++i) { if (m_fileHandles[i] != InvalidHandle) diff --git a/Code/Framework/AzFramework/AzFramework/IO/RemoteStorageDrive.h b/Code/Framework/AzFramework/AzFramework/IO/RemoteStorageDrive.h index c3e28f2e55..de0b855dcc 100644 --- a/Code/Framework/AzFramework/AzFramework/IO/RemoteStorageDrive.h +++ b/Code/Framework/AzFramework/AzFramework/IO/RemoteStorageDrive.h @@ -16,6 +16,15 @@ #include #include +namespace AZ::IO +{ + class RequestPath; + namespace Requests + { + struct ReportData; + } +} + namespace AzFramework { struct RemoteStorageDriveConfig final : @@ -63,7 +72,7 @@ namespace AzFramework const AZ::IO::RequestPath*& activeFile) const; void FlushCache(const AZ::IO::RequestPath& filePath); void FlushEntireCache(); - void Report(const AZ::IO::FileRequest::ReportData& data) const; + void Report(const AZ::IO::Requests::ReportData& data) const; AZ::IO::RemoteFileIO m_fileIO; AZ::IO::TimedAverageWindow m_fileOpenCloseTimeAverage; diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBody.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBody.cpp index 168152f686..bb1270a387 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBody.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBody.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBodyAutomation.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBodyAutomation.cpp index e78ff49f2d..a86ef12216 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBodyAutomation.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBodyAutomation.cpp @@ -8,6 +8,7 @@ #include +#include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBodyEvents.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBodyEvents.cpp index b51298a797..005ce291f6 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBodyEvents.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBodyEvents.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include diff --git a/Code/Framework/AzFramework/AzFramework/Physics/PhysicsScene.cpp b/Code/Framework/AzFramework/AzFramework/Physics/PhysicsScene.cpp index a5ebdd04c6..1937c50555 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/PhysicsScene.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/PhysicsScene.cpp @@ -9,6 +9,7 @@ #include #include +#include #include diff --git a/Code/Framework/AzFramework/AzFramework/Physics/PhysicsSystem.cpp b/Code/Framework/AzFramework/AzFramework/Physics/PhysicsSystem.cpp index 2ff4780c9e..a0bb2d9366 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/PhysicsSystem.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/PhysicsSystem.cpp @@ -8,6 +8,7 @@ #include +#include #include namespace AzPhysics diff --git a/Code/Framework/AzFramework/AzFramework/Script/ScriptComponent.cpp b/Code/Framework/AzFramework/AzFramework/Script/ScriptComponent.cpp index 79365f1ebe..b2c36bc1c8 100644 --- a/Code/Framework/AzFramework/AzFramework/Script/ScriptComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Script/ScriptComponent.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/ToolsAssetCatalogComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/ToolsAssetCatalogComponent.h index a68b82468e..56a3e7005c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/ToolsAssetCatalogComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ToolsComponents/ToolsAssetCatalogComponent.h @@ -7,6 +7,7 @@ */ #pragma once +#include #include #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h index 4596d70657..34b3a0a0b6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/Model/AssetCompleterModel.h @@ -10,12 +10,13 @@ #if !defined(Q_MOC_RUN) #include +#include #endif namespace AzToolsFramework { using namespace AzToolsFramework::AssetBrowser; - + //! Model storing all the files that can be suggested in the Asset Autocompleter for PropertyAssetCtrl class AssetCompleterModel : public QAbstractTableModel @@ -45,7 +46,7 @@ namespace AzToolsFramework void SetFetchEntryType(AssetBrowserEntry::AssetEntryType entryType); private: - struct AssetItem + struct AssetItem { AZStd::string m_displayName; AZStd::string m_path; diff --git a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp index 78244ab02c..78e71ab3f2 100644 --- a/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilder/AssetBuilderComponent.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderVariantAsyncLoader.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderVariantAsyncLoader.h index 982de92739..838cdd2256 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderVariantAsyncLoader.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderVariantAsyncLoader.h @@ -7,13 +7,15 @@ */ #pragma once -#include -#include #include #include #include #include +#include +#include +#include + namespace AZ { class ReflectContext; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/PrecompiledShaderAssetSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/PrecompiledShaderAssetSourceData.h index ce5a4c8a7a..701b90ace9 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/PrecompiledShaderAssetSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/PrecompiledShaderAssetSourceData.h @@ -10,6 +10,7 @@ #include #include +#include namespace AZ { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index bd196a2e2b..b97ffecccd 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -267,7 +267,7 @@ namespace AZ return m_visScene->GetEntryCount(); } - + struct WorklistData { CullingDebugContext* m_debugCtx = nullptr; @@ -296,13 +296,13 @@ namespace AZ #endif return worklistData; } - + constexpr size_t WorkListCapacity = 5; using WorkListType = AZStd::fixed_vector; #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED static MaskedOcclusionCulling::CullingResult TestOcclusionCulling( - const AZStd::shared_ptr& worklistData, + const AZStd::shared_ptr& worklistData, AzFramework::VisibilityEntry* visibleEntry); #endif @@ -320,8 +320,8 @@ namespace AZ for (const AzFramework::IVisibilityScene::NodeData& nodeData : worklist) { //If a node is entirely contained within the frustum, then we can skip the fine grained culling. - bool nodeIsContainedInFrustum = - !worklistData->m_debugCtx->m_enableFrustumCulling || + bool nodeIsContainedInFrustum = + !worklistData->m_debugCtx->m_enableFrustumCulling || ShapeIntersection::Contains(worklistData->m_frustum, nodeData.m_bounds); #ifdef AZ_CULL_PROFILE_VERBOSE @@ -460,12 +460,14 @@ namespace AZ cullStats.m_numVisibleCullables += numVisibleCullables; ++cullStats.m_numJobs; } +#else + (void)numDrawPackets; // prevent unused variable warning->error #endif //AZ_CULL_DEBUG_ENABLED } #if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED static MaskedOcclusionCulling::CullingResult TestOcclusionCulling( - const AZStd::shared_ptr& worklistData, + const AZStd::shared_ptr& worklistData, AzFramework::VisibilityEntry* visibleEntry) { if (!worklistData->m_maskedOcclusionCulling) @@ -527,9 +529,9 @@ namespace AZ #endif void CullingScene::ProcessCullablesCommon( - const Scene& scene [[maybe_unused]], - View& view, - AZ::Frustum& frustum [[maybe_unused]], + const Scene& scene [[maybe_unused]], + View& view, + AZ::Frustum& frustum [[maybe_unused]], void*& maskedOcclusionCulling [[maybe_unused]]) { AZ_PROFILE_SCOPE(RPI, "CullingScene::ProcessCullablesCommon() - %s", view.GetName().GetCStr()); @@ -898,7 +900,7 @@ namespace AZ { const Matrix4x4& worldToClip = viewPtr->GetWorldToClipMatrix(); Frustum frustum = Frustum::CreateFromMatrixColumnMajor(worldToClip, Frustum::ReverseDepth::True); - m_debugCtx.m_frozenFrustums.insert({ viewPtr.get(), frustum }); + m_debugCtx.m_frozenFrustums.insert({ viewPtr.get(), frustum }); } } } @@ -911,7 +913,7 @@ namespace AZ } void CullingScene::EndCulling() - { + { m_cullDataConcurrencyCheck.soft_unlock(); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Metrics/ShaderMetricsSystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Metrics/ShaderMetricsSystem.cpp index e11624a921..460e671b4c 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Metrics/ShaderMetricsSystem.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Metrics/ShaderMetricsSystem.cpp @@ -11,13 +11,13 @@ #include +#include +#include #include #include #include - #include -#include namespace AZ { diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.cpp b/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.cpp index fd19c6bcb8..83e8dbf085 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.cpp +++ b/Gems/Atom/RPI/Code/Tests/Common/AssetManagerTestFixture.cpp @@ -7,6 +7,8 @@ */ #include "AssetManagerTestFixture.h" + +#include #include #include diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/AssetCollectionAsyncLoader.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/AssetCollectionAsyncLoader.h index d1027daa36..b974b4443d 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/AssetCollectionAsyncLoader.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/AssetCollectionAsyncLoader.h @@ -9,6 +9,7 @@ #include #include +#include #include #include #include diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index 58b3d8b56e..35ae1b1257 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -38,6 +38,8 @@ #include #include +#include + namespace AZ::Render { static constexpr uint32_t s_maxActiveWrinkleMasks = 16; diff --git a/Gems/AtomTressFX/Code/Rendering/SharedBuffer.cpp b/Gems/AtomTressFX/Code/Rendering/SharedBuffer.cpp index b31d9f8ae0..6f97613c89 100644 --- a/Gems/AtomTressFX/Code/Rendering/SharedBuffer.cpp +++ b/Gems/AtomTressFX/Code/Rendering/SharedBuffer.cpp @@ -16,6 +16,8 @@ #include #include +#include + namespace AZ::Render { //! Setting the constructor as private will create compile error to remind the developer to set diff --git a/Gems/AudioSystem/Code/Source/Engine/ATLEntities.cpp b/Gems/AudioSystem/Code/Source/Engine/ATLEntities.cpp index 2d95ddf4dd..ce17803531 100644 --- a/Gems/AudioSystem/Code/Source/Engine/ATLEntities.cpp +++ b/Gems/AudioSystem/Code/Source/Engine/ATLEntities.cpp @@ -8,6 +8,7 @@ #include +#include namespace Audio { @@ -285,5 +286,22 @@ namespace Audio return sResult; } + CATLAudioFileEntry::CATLAudioFileEntry(const char * const filePath, IATLAudioFileEntryData * const implData) + : m_filePath(filePath) + , m_fileSize(0) + , m_useCount(0) + , m_memoryBlockAlignment(AUDIO_MEMORY_ALIGNMENT) + , m_flags(eAFF_NOTFOUND) + , m_dataScope(eADS_ALL) + , m_memoryBlock(nullptr) + , m_implData(implData) + { + } + + CATLAudioFileEntry::~CATLAudioFileEntry() + { + + } + #endif // !AUDIO_RELEASE } // namespace Audio diff --git a/Gems/AudioSystem/Code/Source/Engine/ATLEntities.h b/Gems/AudioSystem/Code/Source/Engine/ATLEntities.h index f1ff74c370..4dfceeebfc 100644 --- a/Gems/AudioSystem/Code/Source/Engine/ATLEntities.h +++ b/Gems/AudioSystem/Code/Source/Engine/ATLEntities.h @@ -379,19 +379,9 @@ namespace Audio class CATLAudioFileEntry { public: - explicit CATLAudioFileEntry(const char* const filePath = nullptr, IATLAudioFileEntryData* const implData = nullptr) - : m_filePath(filePath) - , m_fileSize(0) - , m_useCount(0) - , m_memoryBlockAlignment(AUDIO_MEMORY_ALIGNMENT) - , m_flags(eAFF_NOTFOUND) - , m_dataScope(eADS_ALL) - , m_memoryBlock(nullptr) - , m_implData(implData) - { - } + explicit CATLAudioFileEntry(const char* const filePath = nullptr, IATLAudioFileEntryData* const implData = nullptr); - ~CATLAudioFileEntry() = default; + ~CATLAudioFileEntry(); AZStd::string m_filePath; size_t m_fileSize; diff --git a/Gems/AudioSystem/Code/Source/Engine/FileCacheManager.cpp b/Gems/AudioSystem/Code/Source/Engine/FileCacheManager.cpp index ffa94ad956..d1f2187942 100644 --- a/Gems/AudioSystem/Code/Source/Engine/FileCacheManager.cpp +++ b/Gems/AudioSystem/Code/Source/Engine/FileCacheManager.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/AudioSystem/Code/Tests/AudioSystemTest.cpp b/Gems/AudioSystem/Code/Tests/AudioSystemTest.cpp index 14e9f74fd2..a197fee96b 100644 --- a/Gems/AudioSystem/Code/Tests/AudioSystemTest.cpp +++ b/Gems/AudioSystem/Code/Tests/AudioSystemTest.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/AudioSystem/Code/Tests/Mocks/FileCacheManagerMock.h b/Gems/AudioSystem/Code/Tests/Mocks/FileCacheManagerMock.h index 06646216ae..1fb48bb3fb 100644 --- a/Gems/AudioSystem/Code/Tests/Mocks/FileCacheManagerMock.h +++ b/Gems/AudioSystem/Code/Tests/Mocks/FileCacheManagerMock.h @@ -13,6 +13,11 @@ #include #include +namespace AZ::IO +{ + class FileRequestHandle; +} + namespace Audio { class FileCacheManagerMock diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/ActorInstance.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/ActorInstance.cpp index c196f34716..bde1259c44 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/ActorInstance.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/ActorInstance.cpp @@ -34,6 +34,8 @@ #include #include +#include + namespace EMotionFX { AZ_CLASS_ALLOCATOR_IMPL(ActorInstance, ActorInstanceAllocator, 0) diff --git a/Gems/EMotionFX/Code/Tests/TestAssetCode/SimpleActors.cpp b/Gems/EMotionFX/Code/Tests/TestAssetCode/SimpleActors.cpp index 3e1dac41c2..e6415817cc 100644 --- a/Gems/EMotionFX/Code/Tests/TestAssetCode/SimpleActors.cpp +++ b/Gems/EMotionFX/Code/Tests/TestAssetCode/SimpleActors.cpp @@ -15,6 +15,8 @@ #include #include +#include + namespace EMotionFX { SimpleJointChainActor::SimpleJointChainActor(size_t jointCount, const char* name) diff --git a/Gems/LmbrCentral/Code/Source/Asset/AssetSystemDebugComponent.cpp b/Gems/LmbrCentral/Code/Source/Asset/AssetSystemDebugComponent.cpp index acd1bc8dae..91ba63ddd1 100644 --- a/Gems/LmbrCentral/Code/Source/Asset/AssetSystemDebugComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Asset/AssetSystemDebugComponent.cpp @@ -9,7 +9,9 @@ #include "AssetSystemDebugComponent.h" #include "ISystem.h" #include "IRenderAuxGeom.h" + #include "AzCore/Asset/AssetManager.h" +#include #include #include #include diff --git a/Gems/LmbrCentral/Code/Source/Audio/AudioAreaEnvironmentComponent.cpp b/Gems/LmbrCentral/Code/Source/Audio/AudioAreaEnvironmentComponent.cpp index 827e20b02b..3b14822076 100644 --- a/Gems/LmbrCentral/Code/Source/Audio/AudioAreaEnvironmentComponent.cpp +++ b/Gems/LmbrCentral/Code/Source/Audio/AudioAreaEnvironmentComponent.cpp @@ -8,6 +8,7 @@ #include "AudioAreaEnvironmentComponent.h" +#include #include #include #include diff --git a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothColliders.h b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothColliders.h index a400f742de..baac5b3776 100644 --- a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothColliders.h +++ b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothColliders.h @@ -10,6 +10,7 @@ #include #include +#include #include namespace NvCloth diff --git a/Gems/NvCloth/Code/Source/Utils/AssetHelper.h b/Gems/NvCloth/Code/Source/Utils/AssetHelper.h index e3e5a5e7ad..4a40fe26f0 100644 --- a/Gems/NvCloth/Code/Source/Utils/AssetHelper.h +++ b/Gems/NvCloth/Code/Source/Utils/AssetHelper.h @@ -10,6 +10,7 @@ #include #include +#include #include diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.h index 3f6d001112..11215ef29b 100644 --- a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.h +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeAngleCone.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.h b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.h index 843fffd4c8..c7a50c43f5 100644 --- a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.h +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsSubComponentModeSnap.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include diff --git a/Gems/PhysX/Code/Source/ForceRegionComponent.cpp b/Gems/PhysX/Code/Source/ForceRegionComponent.cpp index f8f5f1991e..eba902049d 100644 --- a/Gems/PhysX/Code/Source/ForceRegionComponent.cpp +++ b/Gems/PhysX/Code/Source/ForceRegionComponent.cpp @@ -9,6 +9,8 @@ #include #include +#include +#include #include #include #include diff --git a/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp b/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp index 975fec2181..c02324ed18 100644 --- a/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp +++ b/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.cpp @@ -6,18 +6,22 @@ * */ -#include -#include -#include -#include +#include #include #include #include #include -#include #include +#include +#include +#include +#include +#include + + + namespace PhysX::Utils { struct PxJointActorData diff --git a/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.h b/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.h index da7b3dc4e2..d5aa082763 100644 --- a/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.h +++ b/Gems/PhysX/Code/Source/Joint/PhysXJointUtils.h @@ -14,8 +14,15 @@ #include +#include + namespace PhysX { + struct D6JointLimitConfiguration; + struct FixedJointConfiguration; + struct BallJointConfiguration; + struct HingeJointConfiguration; + namespace JointConstants { // Setting joint limits to very small values can cause extreme stability problems, so clamp above a small diff --git a/Gems/PhysX/Code/Source/JointComponent.cpp b/Gems/PhysX/Code/Source/JointComponent.cpp index d5c04598a5..085fc34b12 100644 --- a/Gems/PhysX/Code/Source/JointComponent.cpp +++ b/Gems/PhysX/Code/Source/JointComponent.cpp @@ -5,17 +5,18 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ +#include +#include +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include #include -#include namespace PhysX { diff --git a/Gems/PhysX/Code/Source/Material.cpp b/Gems/PhysX/Code/Source/Material.cpp index be79728cc5..fa131b5159 100644 --- a/Gems/PhysX/Code/Source/Material.cpp +++ b/Gems/PhysX/Code/Source/Material.cpp @@ -7,9 +7,10 @@ */ #include "Material.h" +#include #include -#include #include +#include #include namespace PhysX diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/API/CharacterUtils.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/API/CharacterUtils.cpp index f4cdd01889..fbadb8aa79 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/API/CharacterUtils.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/API/CharacterUtils.cpp @@ -5,13 +5,10 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ - #include + #include #include -#include -#include -#include #include #include #include @@ -20,6 +17,12 @@ #include #include +#include +#include +#include + +#include + namespace PhysX::Utils::Characters { AZ::Outcome GetNodeIndex(const Physics::RagdollConfiguration& configuration, const AZStd::string& nodeName) diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/API/RagdollNode.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/API/RagdollNode.cpp index 34fe3d0295..3e240f3611 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/API/RagdollNode.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/API/RagdollNode.cpp @@ -5,16 +5,17 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ - -#include -#include -#include #include + #include #include #include - #include +#include +#include +#include +#include + namespace PhysX { diff --git a/Gems/PhysX/Code/Source/Pipeline/HeightFieldAssetHandler.cpp b/Gems/PhysX/Code/Source/Pipeline/HeightFieldAssetHandler.cpp index 2d05612d74..ece6acbd6f 100644 --- a/Gems/PhysX/Code/Source/Pipeline/HeightFieldAssetHandler.cpp +++ b/Gems/PhysX/Code/Source/Pipeline/HeightFieldAssetHandler.cpp @@ -6,15 +6,16 @@ * */ +#include #include #include +#include #include #include #include #include #include -#include #include #include diff --git a/Gems/PhysX/Code/Source/Pipeline/StreamWrapper.h b/Gems/PhysX/Code/Source/Pipeline/StreamWrapper.h index 15f9bfb36e..d987b7194c 100644 --- a/Gems/PhysX/Code/Source/Pipeline/StreamWrapper.h +++ b/Gems/PhysX/Code/Source/Pipeline/StreamWrapper.h @@ -10,6 +10,7 @@ #include #include +#include #include namespace PhysX diff --git a/Gems/PhysX/Code/Source/Scene/PhysXScene.cpp b/Gems/PhysX/Code/Source/Scene/PhysXScene.cpp index dfac43b703..6c02697e90 100644 --- a/Gems/PhysX/Code/Source/Scene/PhysXScene.cpp +++ b/Gems/PhysX/Code/Source/Scene/PhysXScene.cpp @@ -7,14 +7,6 @@ */ #include -#include -#include -#include -#include -#include -#include -#include -#include #include #include @@ -31,6 +23,16 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + namespace PhysX { AZ_CLASS_ALLOCATOR_IMPL(PhysXScene, AZ::SystemAllocator, 0); diff --git a/Gems/PhysX/Code/Source/System/PhysXSystem.cpp b/Gems/PhysX/Code/Source/System/PhysXSystem.cpp index 168adc8910..d7ce797b47 100644 --- a/Gems/PhysX/Code/Source/System/PhysXSystem.cpp +++ b/Gems/PhysX/Code/Source/System/PhysXSystem.cpp @@ -5,18 +5,20 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ -#include +#include + +#include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include -#include - -#include +#include +#include +#include // only enable physx timestep warning when not running debug or in Release #if !defined(DEBUG) && !defined(RELEASE) diff --git a/Gems/PhysX/Code/Tests/PhysXTestUtil.cpp b/Gems/PhysX/Code/Tests/PhysXTestUtil.cpp index 2366f65e07..f79b7c8d34 100644 --- a/Gems/PhysX/Code/Tests/PhysXTestUtil.cpp +++ b/Gems/PhysX/Code/Tests/PhysXTestUtil.cpp @@ -9,6 +9,7 @@ #include "PhysXTestUtil.h" #include #include +#include namespace PhysX { diff --git a/Gems/PhysXDebug/Code/Source/SystemComponent.cpp b/Gems/PhysXDebug/Code/Source/SystemComponent.cpp index 65115f2790..746809a7ca 100644 --- a/Gems/PhysXDebug/Code/Source/SystemComponent.cpp +++ b/Gems/PhysXDebug/Code/Source/SystemComponent.cpp @@ -8,10 +8,7 @@ #include "SystemComponent.h" -#include -#include -#include -#include +#include #include #include @@ -19,20 +16,24 @@ #include #include +#include +#include +#include +#include + +#include #include #include #include #include #include -#include -#include -#include +#include +#include +#include +#include +#include -#include -#include - -#include namespace PhysXDebug { diff --git a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp index 439f9a8383..d9ec1de757 100644 --- a/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp +++ b/Gems/ScriptCanvas/Code/Editor/Assets/ScriptCanvasMemoryAsset.cpp @@ -10,11 +10,14 @@ #include "ScriptCanvasMemoryAsset.h" #include "ScriptCanvasUndoHelper.h" -#include +#include +#include +#include #include -#include -#include #include +#include +#include +#include namespace ScriptCanvasEditor { diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp index 49a35eac8a..95b4fbb843 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/FileSaver.cpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/Gems/ScriptEvents/Code/Source/ScriptEventsSystemComponent.h b/Gems/ScriptEvents/Code/Source/ScriptEventsSystemComponent.h index 64a0e49bca..922bfb1dbc 100644 --- a/Gems/ScriptEvents/Code/Source/ScriptEventsSystemComponent.h +++ b/Gems/ScriptEvents/Code/Source/ScriptEventsSystemComponent.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include diff --git a/Gems/WhiteBox/Code/Source/Viewport/WhiteBoxVertexTranslationModifier.h b/Gems/WhiteBox/Code/Source/Viewport/WhiteBoxVertexTranslationModifier.h index a9565aedbe..d9bae70a31 100644 --- a/Gems/WhiteBox/Code/Source/Viewport/WhiteBoxVertexTranslationModifier.h +++ b/Gems/WhiteBox/Code/Source/Viewport/WhiteBoxVertexTranslationModifier.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include From 3bca63bb7187d640928505d1662c395afb9c4894 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sat, 11 Dec 2021 15:50:37 -0600 Subject: [PATCH 002/136] Temporary fix for material component losing image overrides with prefabs The bug reported that overridden texture properties would be lost whenever an entity was created, destroyed, or a prefab was created. Initially, it seemed like there was a problem with the custom JSON serializer for material properties. Debugging proved this to be incorrect because all of the data was converted to JSON values in the serializer on multiple passes. At some point during prefab patching, the data for the asset properties is lost while other values like colors and floats serialize correctly. Converting the asset data values into asset IDs resolves the immediate problem for the material component but the underlying issue is still under investigation by the prefab team. This change is being posted for review in case the underlying issue cannot be resolved in time for the next release. Signed-off-by: Guthrie Adams Fixing unittests and moving texture conversion into material component controller Signed-off-by: Guthrie Adams --- .../Material/MaterialAssignmentSerializer.cpp | 24 ++++++++++---- .../Material/MaterialAssignmentSerializer.h | 18 +++++++--- .../Code/Source/Util/MaterialPropertyUtil.cpp | 12 ++++--- .../Material/MaterialComponentController.cpp | 33 +++++++++++++++++++ .../Material/MaterialComponentController.h | 5 +++ 5 files changed, 76 insertions(+), 16 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp index b757e4bd7e..85dc26089f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.cpp @@ -16,7 +16,9 @@ namespace AZ AZ_CLASS_ALLOCATOR_IMPL(JsonMaterialAssignmentSerializer, AZ::SystemAllocator, 0); JsonSerializationResult::Result JsonMaterialAssignmentSerializer::Load( - void* outputValue, [[maybe_unused]] const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, + void* outputValue, + [[maybe_unused]] const Uuid& outputValueTypeId, + const rapidjson::Value& inputValue, JsonDeserializerContext& context) { namespace JSR = JsonSerializationResult; @@ -62,6 +64,7 @@ namespace AZ LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || + LoadAny>(propertyValue, inputPropertyPair.value, context, result) || LoadAny>(propertyValue, inputPropertyPair.value, context, result) || LoadAny>(propertyValue, inputPropertyPair.value, context, result)) { @@ -78,7 +81,10 @@ namespace AZ } JsonSerializationResult::Result JsonMaterialAssignmentSerializer::Store( - rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, [[maybe_unused]] const Uuid& valueTypeId, + rapidjson::Value& outputValue, + const void* inputValue, + const void* defaultValue, + [[maybe_unused]] const Uuid& valueTypeId, JsonSerializerContext& context) { namespace JSR = AZ::JsonSerializationResult; @@ -138,9 +144,9 @@ namespace AZ StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || + StoreAny>(propertyValue, outputPropertyValue, context, result) || StoreAny>(propertyValue, outputPropertyValue, context, result) || - StoreAny>( - propertyValue, outputPropertyValue, context, result)) + StoreAny>(propertyValue, outputPropertyValue, context, result)) { outputPropertyValueContainer.AddMember( rapidjson::Value::StringRefType(propertyName.GetCStr()), outputPropertyValue, @@ -164,7 +170,9 @@ namespace AZ template bool JsonMaterialAssignmentSerializer::LoadAny( - AZStd::any& propertyValue, const rapidjson::Value& inputPropertyValue, AZ::JsonDeserializerContext& context, + AZStd::any& propertyValue, + const rapidjson::Value& inputPropertyValue, + AZ::JsonDeserializerContext& context, AZ::JsonSerializationResult::ResultCode& result) { if (inputPropertyValue.IsObject() && inputPropertyValue.HasMember("Value") && inputPropertyValue.HasMember("$type")) @@ -187,7 +195,9 @@ namespace AZ template bool JsonMaterialAssignmentSerializer::StoreAny( - const AZStd::any& propertyValue, rapidjson::Value& outputPropertyValue, AZ::JsonSerializerContext& context, + const AZStd::any& propertyValue, + rapidjson::Value& outputPropertyValue, + AZ::JsonSerializerContext& context, AZ::JsonSerializationResult::ResultCode& result) { if (propertyValue.is()) @@ -199,7 +209,7 @@ namespace AZ result.Combine(StoreTypeId(typeValue, azrtti_typeid(), context)); outputPropertyValue.AddMember("$type", typeValue, context.GetJsonAllocator()); - T value = AZStd::any_cast(propertyValue); + const T& value = AZStd::any_cast(propertyValue); result.Combine( ContinueStoringToJsonObjectField(outputPropertyValue, "Value", &value, nullptr, azrtti_typeid(), context)); return true; diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.h b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.h index e92d756639..069b4d4cdb 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.h +++ b/Gems/Atom/Feature/Common/Code/Source/Material/MaterialAssignmentSerializer.h @@ -25,21 +25,31 @@ namespace AZ AZ_CLASS_ALLOCATOR_DECL; JsonSerializationResult::Result Load( - void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, + 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, + rapidjson::Value& outputValue, + const void* inputValue, + const void* defaultValue, + const Uuid& valueTypeId, JsonSerializerContext& context) override; private: template bool LoadAny( - AZStd::any& propertyValue, const rapidjson::Value& inputPropertyValue, AZ::JsonDeserializerContext& context, + AZStd::any& propertyValue, + const rapidjson::Value& inputPropertyValue, + AZ::JsonDeserializerContext& context, AZ::JsonSerializationResult::ResultCode& result); + template bool StoreAny( - const AZStd::any& propertyValue, rapidjson::Value& outputPropertyValue, AZ::JsonSerializerContext& context, + const AZStd::any& propertyValue, + rapidjson::Value& outputPropertyValue, + AZ::JsonSerializerContext& context, AZ::JsonSerializationResult::ResultCode& result); }; } // namespace Render diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp index 3ffd8efa6e..2ad4522094 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp @@ -33,11 +33,13 @@ namespace AtomToolsFramework { if (value.Is>()) { - const AZ::Data::Asset& imageAsset = value.GetValue>(); - return AZStd::any(AZ::Data::Asset( - imageAsset.GetId(), - azrtti_typeid(), - imageAsset.GetHint())); + const auto& imageAsset = value.GetValue>(); + return AZStd::any(AZ::Data::Asset(imageAsset.GetId(), azrtti_typeid(), imageAsset.GetHint())); + } + else if (value.Is>()) + { + const auto& image = value.GetValue>(); + return AZStd::any(AZ::Data::Asset(image->GetAssetId(), azrtti_typeid())); } return AZ::RPI::MaterialPropertyValue::ToAny(value); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp index 0ccdae28de..996a575c69 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.cpp @@ -104,6 +104,7 @@ namespace AZ MaterialComponentController::MaterialComponentController(const MaterialComponentConfig& config) : m_configuration(config) { + ConvertAssetsForSerialization(); } void MaterialComponentController::Activate(EntityId entityId) @@ -135,6 +136,7 @@ namespace AZ void MaterialComponentController::SetConfiguration(const MaterialComponentConfig& config) { m_configuration = config; + ConvertAssetsForSerialization(); } const MaterialComponentConfig& MaterialComponentController::GetConfiguration() const @@ -338,6 +340,7 @@ namespace AZ // before LoadMaterials() is called [LYN-2249] auto temp = m_configuration.m_materials; m_configuration.m_materials = materials; + ConvertAssetsForSerialization(); LoadMaterials(); } @@ -489,6 +492,7 @@ namespace AZ auto& materialAssignment = m_configuration.m_materials[materialAssignmentId]; const bool wasEmpty = materialAssignment.m_propertyOverrides.empty(); materialAssignment.m_propertyOverrides[AZ::Name(propertyName)] = value; + ConvertAssetsForSerialization(); if (materialAssignment.RequiresLoading()) { @@ -586,6 +590,7 @@ namespace AZ auto& materialAssignment = m_configuration.m_materials[materialAssignmentId]; const bool wasEmpty = materialAssignment.m_propertyOverrides.empty(); materialAssignment.m_propertyOverrides = propertyOverrides; + ConvertAssetsForSerialization(); if (materialAssignment.RequiresLoading()) { @@ -667,5 +672,33 @@ namespace AZ TickBus::Handler::BusConnect(); } } + + void MaterialComponentController::ConvertAssetsForSerialization() + { + for (auto& materialAssignmentPair : m_configuration.m_materials) + { + MaterialAssignment& materialAssignment = materialAssignmentPair.second; + for (auto& propertyPair : materialAssignment.m_propertyOverrides) + { + auto& value = propertyPair.second; + if (value.is>()) + { + value = AZStd::any_cast>(value).GetId(); + } + else if (value.is>()) + { + value = AZStd::any_cast>(value).GetId(); + } + else if (value.is>()) + { + value = AZStd::any_cast>(value).GetId(); + } + else if (value.is>()) + { + value = AZStd::any_cast>(value)->GetAssetId(); + } + } + } + } } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h index 74b1cfda4d..d3eaa4433d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/MaterialComponentController.h @@ -99,6 +99,11 @@ namespace AZ //! Queue material instance recreation notifiucations until tick void QueueMaterialUpdateNotification(); + //! Converts property overrides storing image asset references into asset IDs. This addresses a problem where image property + //! overrides are lost during prefab serialization and patching. This suboptimal function will be removed once the underlying + //! problem is resolved. + void ConvertAssetsForSerialization(); + EntityId m_entityId; MaterialComponentConfig m_configuration; AZStd::unordered_set m_materialsWithDirtyProperties; From c019fe8946269e581683c383966651a81c5f9d38 Mon Sep 17 00:00:00 2001 From: Mike Chang Date: Thu, 2 Dec 2021 17:05:42 -0800 Subject: [PATCH 003/136] Add conditional to pull O3DE_BUILD_VERSION through environment var (#6096) Signed-off-by: Mike Chang --- cmake/Version.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/Version.cmake b/cmake/Version.cmake index de93ebefef..c5504ec62a 100644 --- a/cmake/Version.cmake +++ b/cmake/Version.cmake @@ -16,3 +16,8 @@ if("$ENV{O3DE_VERSION}") # Overriding through environment set(LY_VERSION_STRING "$ENV{O3DE_VERSION}") endif() + +if("$ENV{O3DE_BUILD_VERSION}") + # Overriding through environment + set(LY_VERSION_BUILD_NUMBER "$ENV{O3DE_BUILD_VERSION}") +endif() From f44697fbf45b6288d9f2995cd43b2cef4927b9dc Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Tue, 7 Dec 2021 14:05:05 -0800 Subject: [PATCH 004/136] Check whether env variables are defined Signed-off-by: AMZN-Phil --- cmake/Version.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/Version.cmake b/cmake/Version.cmake index c5504ec62a..6fa32e9c73 100644 --- a/cmake/Version.cmake +++ b/cmake/Version.cmake @@ -12,12 +12,12 @@ set(LY_VERSION_STRING "0.0.0.0" CACHE STRING "Open 3D Engine's version") set(LY_VERSION_BUILD_NUMBER 0 CACHE STRING "Open 3D Engine's build number") set(LY_VERSION_ENGINE_NAME "o3de" CACHE STRING "Open 3D Engine's engine name") -if("$ENV{O3DE_VERSION}") +if(DEFINED ENV{O3DE_VERSION}) # Overriding through environment set(LY_VERSION_STRING "$ENV{O3DE_VERSION}") endif() -if("$ENV{O3DE_BUILD_VERSION}") +if(DEFINED ENV{O3DE_BUILD_VERSION}) # Overriding through environment set(LY_VERSION_BUILD_NUMBER "$ENV{O3DE_BUILD_VERSION}") endif() From 38c8d941564ae709a7839a25883807b723fa4657 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Tue, 7 Dec 2021 15:12:11 -0800 Subject: [PATCH 005/136] Use version check to allow for a defined empty string to fail and greater to check build number is a number greater than 0 Signed-off-by: AMZN-Phil --- cmake/Version.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/Version.cmake b/cmake/Version.cmake index 6fa32e9c73..d15d5b9f86 100644 --- a/cmake/Version.cmake +++ b/cmake/Version.cmake @@ -12,12 +12,12 @@ set(LY_VERSION_STRING "0.0.0.0" CACHE STRING "Open 3D Engine's version") set(LY_VERSION_BUILD_NUMBER 0 CACHE STRING "Open 3D Engine's build number") set(LY_VERSION_ENGINE_NAME "o3de" CACHE STRING "Open 3D Engine's engine name") -if(DEFINED ENV{O3DE_VERSION}) +if("$ENV{O3DE_VERSION}" VERSION_GREATER "0.0.0.0") # Overriding through environment set(LY_VERSION_STRING "$ENV{O3DE_VERSION}") endif() -if(DEFINED ENV{O3DE_BUILD_VERSION}) +if("$ENV{O3DE_BUILD_VERSION}" GREATER 0) # Overriding through environment set(LY_VERSION_BUILD_NUMBER "$ENV{O3DE_BUILD_VERSION}") endif() From 82af1e6870ba7f8e705d5f0559591ce42fa57384 Mon Sep 17 00:00:00 2001 From: AMZN-Phil Date: Tue, 7 Dec 2021 17:10:26 -0800 Subject: [PATCH 006/136] Force a string check on the version numbers Signed-off-by: AMZN-Phil --- cmake/Version.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/Version.cmake b/cmake/Version.cmake index d15d5b9f86..876c34f8c4 100644 --- a/cmake/Version.cmake +++ b/cmake/Version.cmake @@ -12,12 +12,12 @@ set(LY_VERSION_STRING "0.0.0.0" CACHE STRING "Open 3D Engine's version") set(LY_VERSION_BUILD_NUMBER 0 CACHE STRING "Open 3D Engine's build number") set(LY_VERSION_ENGINE_NAME "o3de" CACHE STRING "Open 3D Engine's engine name") -if("$ENV{O3DE_VERSION}" VERSION_GREATER "0.0.0.0") +if(NOT "$ENV{O3DE_VERSION}" STREQUAL "") # Overriding through environment set(LY_VERSION_STRING "$ENV{O3DE_VERSION}") endif() -if("$ENV{O3DE_BUILD_VERSION}" GREATER 0) +if(NOT "$ENV{O3DE_BUILD_VERSION}" STREQUAL "") # Overriding through environment set(LY_VERSION_BUILD_NUMBER "$ENV{O3DE_BUILD_VERSION}") endif() From 6643b4b53cb209e57904c5ff6b51e08d481c98eb Mon Sep 17 00:00:00 2001 From: "T.J. McGrath-Daly" Date: Mon, 6 Dec 2021 08:48:24 +0800 Subject: [PATCH 007/136] Fix: LOD stops animation Signed-off-by: T.J. McGrath-Daly --- .../SkinnedMeshFeatureProcessor.cpp | 65 ++++++++++++------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp index 37b18291dc..8cd20b77d5 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshFeatureProcessor.cpp @@ -204,35 +204,56 @@ namespace AZ // do the enumeration for each view, keep track of the lowest lod for each entry, // and submit the appropriate dispatch item - //the [1][1] element of a perspective projection matrix stores cot(FovY/2) (equal to 2*nearPlaneDistance/nearPlaneHeight), - //which is used to determine the (vertical) projected size in screen space - const float yScale = viewToClip.GetElement(1, 1); - const bool isPerspective = viewToClip.GetElement(3, 3) == 0.f; - const Vector3 cameraPos = view->GetViewToWorldMatrix().GetTranslation(); - - const Vector3 pos = cullable.m_cullData.m_boundingSphere.GetCenter(); - - const float approxScreenPercentage = RPI::ModelLodUtils::ApproxScreenPercentage( - pos, cullable.m_lodData.m_lodSelectionRadius, cameraPos, yScale, isPerspective); - - for (size_t lodIndex = 0; lodIndex < cullable.m_lodData.m_lods.size(); ++lodIndex) + switch (cullable.m_lodData.m_lodConfiguration.m_lodType) { - const RPI::Cullable::LodData::Lod& lod = cullable.m_lodData.m_lods[lodIndex]; - - //Note that this supports overlapping lod ranges (to support cross-fading lods, for example) - if (approxScreenPercentage >= lod.m_screenCoverageMin && approxScreenPercentage <= lod.m_screenCoverageMax) + case RPI::Cullable::LodType::SpecificLod: + { + AZStd::lock_guard lock(m_dispatchItemMutex); + auto lodIndex = cullable.m_lodData.m_lodConfiguration.m_lodOverride; + m_skinningDispatches.insert(&renderProxy.m_dispatchItemsByLod[lodIndex]->GetRHIDispatchItem()); + for (size_t morphTargetIndex = 0; morphTargetIndex < renderProxy.m_morphTargetDispatchItemsByLod[lodIndex].size(); morphTargetIndex++) { - AZStd::lock_guard lock(m_dispatchItemMutex); - m_skinningDispatches.insert(&renderProxy.m_dispatchItemsByLod[lodIndex]->GetRHIDispatchItem()); - for (size_t morphTargetIndex = 0; morphTargetIndex < renderProxy.m_morphTargetDispatchItemsByLod[lodIndex].size(); morphTargetIndex++) + const MorphTargetDispatchItem* dispatchItem = renderProxy.m_morphTargetDispatchItemsByLod[lodIndex][morphTargetIndex].get(); + if (dispatchItem && dispatchItem->GetWeight() > AZ::Constants::FloatEpsilon) { - const MorphTargetDispatchItem* dispatchItem = renderProxy.m_morphTargetDispatchItemsByLod[lodIndex][morphTargetIndex].get(); - if (dispatchItem && dispatchItem->GetWeight() > AZ::Constants::FloatEpsilon) + m_morphTargetDispatches.insert(&dispatchItem->GetRHIDispatchItem()); + } + } + } + break; + case RPI::Cullable::LodType::ScreenCoverage: + default: + //the [1][1] element of a perspective projection matrix stores cot(FovY/2) (equal to 2*nearPlaneDistance/nearPlaneHeight), + //which is used to determine the (vertical) projected size in screen space + const float yScale = viewToClip.GetElement(1, 1); + const bool isPerspective = viewToClip.GetElement(3, 3) == 0.f; + const Vector3 cameraPos = view->GetViewToWorldMatrix().GetTranslation(); + + const Vector3 pos = cullable.m_cullData.m_boundingSphere.GetCenter(); + + const float approxScreenPercentage = RPI::ModelLodUtils::ApproxScreenPercentage( + pos, cullable.m_lodData.m_lodSelectionRadius, cameraPos, yScale, isPerspective); + + for (size_t lodIndex = 0; lodIndex < cullable.m_lodData.m_lods.size(); ++lodIndex) + { + const RPI::Cullable::LodData::Lod& lod = cullable.m_lodData.m_lods[lodIndex]; + + //Note that this supports overlapping lod ranges (to support cross-fading lods, for example) + if (approxScreenPercentage >= lod.m_screenCoverageMin && approxScreenPercentage <= lod.m_screenCoverageMax) + { + AZStd::lock_guard lock(m_dispatchItemMutex); + m_skinningDispatches.insert(&renderProxy.m_dispatchItemsByLod[lodIndex]->GetRHIDispatchItem()); + for (size_t morphTargetIndex = 0; morphTargetIndex < renderProxy.m_morphTargetDispatchItemsByLod[lodIndex].size(); morphTargetIndex++) { - m_morphTargetDispatches.insert(&dispatchItem->GetRHIDispatchItem()); + const MorphTargetDispatchItem* dispatchItem = renderProxy.m_morphTargetDispatchItemsByLod[lodIndex][morphTargetIndex].get(); + if (dispatchItem && dispatchItem->GetWeight() > AZ::Constants::FloatEpsilon) + { + m_morphTargetDispatches.insert(&dispatchItem->GetRHIDispatchItem()); + } } } } + break; } } } From 7af3bef84c7170b0d91f812a30a476ffb37a4107 Mon Sep 17 00:00:00 2001 From: "T.J. McGrath-Daly" Date: Fri, 15 Oct 2021 15:15:26 +0800 Subject: [PATCH 008/136] Model drag causes crash Signed-off-by: T.J. McGrath-Daly --- Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp index 861271fdb3..0c05da6981 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Actor.cpp @@ -434,6 +434,17 @@ namespace EMotionFX m_morphSetups.resize(numLODs); AZStd::fill(begin(m_morphSetups), AZStd::next(begin(m_morphSetups), numLODs), nullptr); } + else + { + if (m_morphSetups.size() < numLODs) + { + AZ::u32 num = m_morphSetups.empty() ? 0 : (AZ::u32)m_morphSetups.size(); + for (AZ::u32 i = num; i < numLODs; ++i) + { + m_morphSetups.push_back(nullptr); + } + } + } } // removes all node meshes and stacks From 5231cb9b53b86d442effdbbfd46292b3f20732d5 Mon Sep 17 00:00:00 2001 From: "T.J. McGrath-Daly" Date: Fri, 15 Oct 2021 10:58:31 +0800 Subject: [PATCH 009/136] Shortcut keys issue Signed-off-by: T.J. McGrath-Daly --- .../Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp index b75fb71060..952b3134b6 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/EMStudioSDK/Source/MainWindow.cpp @@ -532,7 +532,7 @@ namespace EMStudio QAction* characterLayoutAction = new QAction( "Character", this); - characterLayoutAction->setShortcut(Qt::Key_1 | Qt::AltModifier); + characterLayoutAction->setShortcut(Qt::Key_3 | Qt::AltModifier); m_shortcutManager->RegisterKeyboardShortcut(characterLayoutAction, layoutGroupName, false); connect(characterLayoutAction, &QAction::triggered, [this]{ m_applicationMode->setCurrentIndex(2); }); addAction(characterLayoutAction); From 90f710b8c2564547293487a53af0b474572a8481 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 31 Oct 2021 09:48:06 -0700 Subject: [PATCH 010/136] feat: add cursor wrapped mode Signed-off-by: Michael Pollind --- Code/Editor/EditorViewportSettings.cpp | 11 ++ Code/Editor/EditorViewportSettings.h | 3 + .../test_ModularViewportCameraController.cpp | 4 +- .../Input/QtEventToAzInputMapper.cpp | 109 ++++++++++++++---- .../Input/QtEventToAzInputMapper.h | 19 ++- .../Source/Viewport/RenderViewportWidget.cpp | 4 +- 6 files changed, 122 insertions(+), 28 deletions(-) diff --git a/Code/Editor/EditorViewportSettings.cpp b/Code/Editor/EditorViewportSettings.cpp index e06b9696e1..5711d1c3d3 100644 --- a/Code/Editor/EditorViewportSettings.cpp +++ b/Code/Editor/EditorViewportSettings.cpp @@ -23,6 +23,7 @@ namespace SandboxEditor constexpr AZStd::string_view AngleSizeSetting = "/Amazon/Preferences/Editor/AngleSize"; constexpr AZStd::string_view ShowGridSetting = "/Amazon/Preferences/Editor/ShowGrid"; constexpr AZStd::string_view StickySelectSetting = "/Amazon/Preferences/Editor/StickySelect"; + constexpr AZStd::string_view ManipulatorMouseWrapSetting = "/Amazon/Preferences/Editor/Manipulator/MouseWrapping"; constexpr AZStd::string_view ManipulatorLineBoundWidthSetting = "/Amazon/Preferences/Editor/Manipulator/LineBoundWidth"; constexpr AZStd::string_view ManipulatorCircleBoundWidthSetting = "/Amazon/Preferences/Editor/Manipulator/CircleBoundWidth"; constexpr AZStd::string_view CameraTranslateSpeedSetting = "/Amazon/Preferences/Editor/Camera/TranslateSpeed"; @@ -186,6 +187,16 @@ namespace SandboxEditor AzToolsFramework::SetRegistry(ManipulatorLineBoundWidthSetting, lineBoundWidth); } + bool ManipulatorMouseWrap() + { + return aznumeric_cast(GetRegistry(ManipulatorMouseWrapSetting, false)); + } + + void SetManipulatorMouseWrap(bool wrapping) + { + SetRegistry(ManipulatorMouseWrapSetting, wrapping); + } + float ManipulatorCircleBoundWidth() { return aznumeric_cast(AzToolsFramework::GetRegistry(ManipulatorCircleBoundWidthSetting, 0.1)); diff --git a/Code/Editor/EditorViewportSettings.h b/Code/Editor/EditorViewportSettings.h index fe1253ed0c..975feff307 100644 --- a/Code/Editor/EditorViewportSettings.h +++ b/Code/Editor/EditorViewportSettings.h @@ -57,6 +57,9 @@ namespace SandboxEditor SANDBOX_API float ManipulatorLineBoundWidth(); SANDBOX_API void SetManipulatorLineBoundWidth(float lineBoundWidth); + SANDBOX_API bool ManipulatorMouseWrap(); + SANDBOX_API void SetManipulatorMouseWrap(bool wrapping); + SANDBOX_API float ManipulatorCircleBoundWidth(); SANDBOX_API void SetManipulatorCircleBoundWidth(float circleBoundWidth); diff --git a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp index 67d89ad967..f2ee3c79aa 100644 --- a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp +++ b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp @@ -47,12 +47,12 @@ namespace UnitTest void ViewportMouseCursorRequestImpl::BeginCursorCapture() { - m_inputChannelMapper->SetCursorCaptureEnabled(true); + m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CURSOR_MODE_CAPTURED); } void ViewportMouseCursorRequestImpl::EndCursorCapture() { - m_inputChannelMapper->SetCursorCaptureEnabled(false); + m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CURSOR_MODE_NONE); } bool ViewportMouseCursorRequestImpl::IsMouseOver() const diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp index 066bdc1654..0b6df58c1a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp @@ -241,22 +241,39 @@ namespace AzToolsFramework } } + + void QtEventToAzInputMapper::SetCursorMode(QtEventToAzInputMapper::CursorInputMode mode) + { + if(mode != m_cursorMode) + { + m_cursorMode = mode; + switch(m_cursorMode) + { + case CURSOR_MODE_CAPTURED: + qApp->setOverrideCursor(Qt::BlankCursor); + m_mouseDevice->SetSystemCursorState(AzFramework::SystemCursorState::ConstrainedAndHidden); + break; + case CURSOR_MODE_WRAPPED: + qApp->restoreOverrideCursor(); + m_mouseDevice->SetSystemCursorState(AzFramework::SystemCursorState::UnconstrainedAndVisible); + break; + case CURSOR_MODE_NONE: + qApp->restoreOverrideCursor(); + m_mouseDevice->SetSystemCursorState(AzFramework::SystemCursorState::UnconstrainedAndVisible); + break; + } + } + } + void QtEventToAzInputMapper::SetCursorCaptureEnabled(bool enabled) { - if (m_capturingCursor != enabled) + if (enabled) { - m_capturingCursor = enabled; - - if (m_capturingCursor) - { - m_mouseDevice->SetSystemCursorState(AzFramework::SystemCursorState::ConstrainedAndHidden); - qApp->setOverrideCursor(Qt::BlankCursor); - } - else - { - m_mouseDevice->SetSystemCursorState(AzFramework::SystemCursorState::UnconstrainedAndVisible); - qApp->restoreOverrideCursor(); - } + SetCursorMode(CURSOR_MODE_CAPTURED); + } + else + { + SetCursorMode(CURSOR_MODE_NONE); } } @@ -436,25 +453,73 @@ namespace AzToolsFramework return QPoint{ denormalizedX, denormalizedY }; } + void wrapCursorX(const QRect& rect, QPoint& point) { + if (rect.left() < point.x()) + { + point.setX(rect.right() - 1); + } + else if (rect.right() > point.x()) + { + point.setX(rect.left() + 1); + } + } + + void wrapCursorY(const QRect& rect, QPoint& point) { + if (rect.top() < point.y()) + { + point.setY(rect.bottom() - 1); + } + else if (rect.bottom() > point.y()) + { + point.setY(rect.top() + 1); + } + } + + void QtEventToAzInputMapper::HandleMouseMoveEvent(const QPoint& globalCursorPosition) { const QPoint cursorDelta = globalCursorPosition - m_previousGlobalCursorPosition; + QScreen* screen = m_sourceWidget->screen(); + const QRect widgetRect(m_sourceWidget->mapToGlobal(QPoint(0,0)), m_sourceWidget->size()); m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition = WidgetPositionToNormalizedPosition(m_sourceWidget->mapFromGlobal(globalCursorPosition)); m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta = WidgetPositionToNormalizedPosition(cursorDelta); - ProcessPendingMouseEvents(cursorDelta); + switch(m_cursorMode) + { + case CURSOR_MODE_CAPTURED: + AzQtComponents::SetCursorPos(m_previousGlobalCursorPosition); + break; + case CURSOR_MODE_WRAPPED_X: + QPoint screenPos(globalCursorPosition); + wrapCursorX(widgetRect, screenPos); + QCursor::setPos(screen, screenPos); + QPoint screenDelta = globalCursorPosition - screenPos; + m_previousGlobalCursorPosition = globalCursorPosition - screenDelta; + break; + case CURSOR_MODE_WRAPPED_Y: + QPoint screenPos(globalCursorPosition); + wrapCursorY(widgetRect, screenPos); + QCursor::setPos(screen, screenPos); + QPoint screenDelta = globalCursorPosition - screenPos; + m_previousGlobalCursorPosition = globalCursorPosition - screenDelta; + break; + case CURSOR_MODE_WRAPPED: + QPoint screenPos(globalCursorPosition); + wrapCursorX(widgetRect, screenPos); + wrapCursorY(widgetRect, screenPos); + QCursor::setPos(screen, screenPos); + QPoint screenDelta = globalCursorPosition - screenPos; + m_previousGlobalCursorPosition = globalCursorPosition - screenDelta; + break; + default: + m_previousGlobalCursorPosition = globalCursorPosition; + break; + - if (m_capturingCursor) - { - // Reset our cursor position to the previous point - AzQtComponents::SetCursorPos(m_previousGlobalCursorPosition); - } - else - { - m_previousGlobalCursorPosition = globalCursorPosition; } + ProcessPendingMouseEvents(cursorDelta); } void QtEventToAzInputMapper::HandleKeyEvent(QKeyEvent* keyEvent) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.h index 373945d445..7ba4e21bd4 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.h @@ -41,6 +41,17 @@ namespace AzToolsFramework Q_OBJECT public: + enum CursorInputMode { + CURSOR_MODE_NONE, + CURSOR_MODE_CAPTURED, //< Sets whether or not the cursor should be constrained to the source widget and invisible. + //< Internally, this will reset the cursor position after each move event to ensure movement + //< events don't allow the cursor to escape. This can be used for typical camera controls + //< like a dolly or rotation, where mouse movement is important but cursor location is not. + CURSOR_MODE_WRAPPED, //< Flags whether the curser is going to wrap around the soruce widget. + CURSOR_MODE_WRAPPED_X, + CURSOR_MODE_WRAPPED_Y + }; + QtEventToAzInputMapper(QWidget* sourceWidget, int syntheticDeviceId = 0); ~QtEventToAzInputMapper() = default; @@ -56,8 +67,12 @@ namespace AzToolsFramework //! Internally, this will reset the cursor position after each move event to ensure movement //! events don't allow the cursor to escape. This can be used for typical camera controls //! like a dolly or rotation, where mouse movement is important but cursor location is not. + //! @deprecated Use #SetCursorMode() void SetCursorCaptureEnabled(bool enabled); + //! Set the cursor mode. + void SetCursorMode(QtEventToAzInputMapper::CursorInputMode mode); + void SetOverrideCursor(ViewportInteraction::CursorStyleOverride cursorStyleOverride); void ClearOverrideCursor(); @@ -176,8 +191,8 @@ namespace AzToolsFramework QWidget* m_sourceWidget; // Flags whether or not Qt events should currently be processed. bool m_enabled = true; - // Flags whether or not the cursor is being constrained to the source widget (for invisible mouse movement). - bool m_capturingCursor = false; + // Controls the cursor behavior. + QtEventToAzInputMapper::CursorInputMode m_cursorMode = CURSOR_MODE_NONE; // Flags whether the cursor has been overridden. bool m_overrideCursor = false; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp index 505ff70122..cbede827e2 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp @@ -331,12 +331,12 @@ namespace AtomToolsFramework void RenderViewportWidget::BeginCursorCapture() { - m_inputChannelMapper->SetCursorCaptureEnabled(true); + m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CURSOR_MODE_CAPTURED); } void RenderViewportWidget::EndCursorCapture() { - m_inputChannelMapper->SetCursorCaptureEnabled(false); + m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CURSOR_MODE_NONE); } void RenderViewportWidget::SetOverrideCursor(AzToolsFramework::ViewportInteraction::CursorStyleOverride cursorStyleOverride) From fa809a76ca3804e95377c0776a40cf4004da90c8 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 13 Dec 2021 07:28:28 -0800 Subject: [PATCH 011/136] chore: address changes - updated checkstyle - update enum CursorInputMode - minor refeactor to QtEventToAzInputMapper Signed-off-by: Michael Pollind --- Code/Editor/EditorViewportSettings.cpp | 10 +- Code/Editor/EditorViewportSettings.h | 4 +- .../test_ModularViewportCameraController.cpp | 4 +- .../Input/QtEventToAzInputMapper.cpp | 116 +++++++++--------- .../Input/QtEventToAzInputMapper.h | 14 +-- .../Source/Viewport/RenderViewportWidget.cpp | 4 +- 6 files changed, 74 insertions(+), 78 deletions(-) diff --git a/Code/Editor/EditorViewportSettings.cpp b/Code/Editor/EditorViewportSettings.cpp index 5711d1c3d3..883eb91863 100644 --- a/Code/Editor/EditorViewportSettings.cpp +++ b/Code/Editor/EditorViewportSettings.cpp @@ -23,7 +23,7 @@ namespace SandboxEditor constexpr AZStd::string_view AngleSizeSetting = "/Amazon/Preferences/Editor/AngleSize"; constexpr AZStd::string_view ShowGridSetting = "/Amazon/Preferences/Editor/ShowGrid"; constexpr AZStd::string_view StickySelectSetting = "/Amazon/Preferences/Editor/StickySelect"; - constexpr AZStd::string_view ManipulatorMouseWrapSetting = "/Amazon/Preferences/Editor/Manipulator/MouseWrapping"; + constexpr AZStd::string_view ViewportMouseWrapSetting = "/Amazon/Preferences/Editor/Manipulator/MouseWrapping"; constexpr AZStd::string_view ManipulatorLineBoundWidthSetting = "/Amazon/Preferences/Editor/Manipulator/LineBoundWidth"; constexpr AZStd::string_view ManipulatorCircleBoundWidthSetting = "/Amazon/Preferences/Editor/Manipulator/CircleBoundWidth"; constexpr AZStd::string_view CameraTranslateSpeedSetting = "/Amazon/Preferences/Editor/Camera/TranslateSpeed"; @@ -187,14 +187,14 @@ namespace SandboxEditor AzToolsFramework::SetRegistry(ManipulatorLineBoundWidthSetting, lineBoundWidth); } - bool ManipulatorMouseWrap() + bool ViewportMouseWrapSetting() { - return aznumeric_cast(GetRegistry(ManipulatorMouseWrapSetting, false)); + return aznumeric_cast(GetRegistry(ViewportMouseWrapSetting, false)); } - void SetManipulatorMouseWrap(bool wrapping) + void SetViewportMouseWrapSetting(bool wrapping) { - SetRegistry(ManipulatorMouseWrapSetting, wrapping); + SetRegistry(ViewportMouseWrapSetting, wrapping); } float ManipulatorCircleBoundWidth() diff --git a/Code/Editor/EditorViewportSettings.h b/Code/Editor/EditorViewportSettings.h index 975feff307..a27187bc55 100644 --- a/Code/Editor/EditorViewportSettings.h +++ b/Code/Editor/EditorViewportSettings.h @@ -57,8 +57,8 @@ namespace SandboxEditor SANDBOX_API float ManipulatorLineBoundWidth(); SANDBOX_API void SetManipulatorLineBoundWidth(float lineBoundWidth); - SANDBOX_API bool ManipulatorMouseWrap(); - SANDBOX_API void SetManipulatorMouseWrap(bool wrapping); + SANDBOX_API bool ViewportMouseWrapSetting(); + SANDBOX_API void SetViewportMouseWrapSetting(bool wrapping); SANDBOX_API float ManipulatorCircleBoundWidth(); SANDBOX_API void SetManipulatorCircleBoundWidth(float circleBoundWidth); diff --git a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp index f2ee3c79aa..9bfd9d396e 100644 --- a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp +++ b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp @@ -47,12 +47,12 @@ namespace UnitTest void ViewportMouseCursorRequestImpl::BeginCursorCapture() { - m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CURSOR_MODE_CAPTURED); + m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CursorModeCaptured); } void ViewportMouseCursorRequestImpl::EndCursorCapture() { - m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CURSOR_MODE_NONE); + m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CursorModeNone); } bool ViewportMouseCursorRequestImpl::IsMouseOver() const diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp index 0b6df58c1a..77f297b98c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp @@ -241,40 +241,32 @@ namespace AzToolsFramework } } - - void QtEventToAzInputMapper::SetCursorMode(QtEventToAzInputMapper::CursorInputMode mode) + void QtEventToAzInputMapper::SetCursorMode(QtEventToAzInputMapper::CursorInputMode mode) { - if(mode != m_cursorMode) + if (mode != m_cursorMode) { m_cursorMode = mode; - switch(m_cursorMode) + switch (m_cursorMode) { - case CURSOR_MODE_CAPTURED: - qApp->setOverrideCursor(Qt::BlankCursor); - m_mouseDevice->SetSystemCursorState(AzFramework::SystemCursorState::ConstrainedAndHidden); - break; - case CURSOR_MODE_WRAPPED: - qApp->restoreOverrideCursor(); - m_mouseDevice->SetSystemCursorState(AzFramework::SystemCursorState::UnconstrainedAndVisible); - break; - case CURSOR_MODE_NONE: - qApp->restoreOverrideCursor(); - m_mouseDevice->SetSystemCursorState(AzFramework::SystemCursorState::UnconstrainedAndVisible); - break; + case CursorInputMode::CursorModeCaptured: + qApp->setOverrideCursor(Qt::BlankCursor); + m_mouseDevice->SetSystemCursorState(AzFramework::SystemCursorState::ConstrainedAndHidden); + break; + case CursorInputMode::CursorModeWrapped: + qApp->restoreOverrideCursor(); + m_mouseDevice->SetSystemCursorState(AzFramework::SystemCursorState::UnconstrainedAndVisible); + break; + case CursorInputMode::CursorModeNone: + qApp->restoreOverrideCursor(); + m_mouseDevice->SetSystemCursorState(AzFramework::SystemCursorState::UnconstrainedAndVisible); + break; } } } void QtEventToAzInputMapper::SetCursorCaptureEnabled(bool enabled) { - if (enabled) - { - SetCursorMode(CURSOR_MODE_CAPTURED); - } - else - { - SetCursorMode(CURSOR_MODE_NONE); - } + SetCursorMode(enabled ? CursorInputMode::CursorModeCaptured : CursorInputMode::CursorModeNone); } bool QtEventToAzInputMapper::eventFilter(QObject* object, QEvent* event) @@ -453,71 +445,75 @@ namespace AzToolsFramework return QPoint{ denormalizedX, denormalizedY }; } - void wrapCursorX(const QRect& rect, QPoint& point) { - if (rect.left() < point.x()) + void wrapCursorX(const QRect& rect, QPoint& point) + { + if (rect.left() < point.x()) { point.setX(rect.right() - 1); } - else if (rect.right() > point.x()) + else if (rect.right() > point.x()) { point.setX(rect.left() + 1); } } - void wrapCursorY(const QRect& rect, QPoint& point) { - if (rect.top() < point.y()) + void wrapCursorY(const QRect& rect, QPoint& point) + { + if (rect.top() < point.y()) { point.setY(rect.bottom() - 1); } - else if (rect.bottom() > point.y()) + else if (rect.bottom() > point.y()) { point.setY(rect.top() + 1); } } - void QtEventToAzInputMapper::HandleMouseMoveEvent(const QPoint& globalCursorPosition) { const QPoint cursorDelta = globalCursorPosition - m_previousGlobalCursorPosition; QScreen* screen = m_sourceWidget->screen(); - const QRect widgetRect(m_sourceWidget->mapToGlobal(QPoint(0,0)), m_sourceWidget->size()); + const QRect widgetRect(m_sourceWidget->mapToGlobal(QPoint(0, 0)), m_sourceWidget->size()); m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition = WidgetPositionToNormalizedPosition(m_sourceWidget->mapFromGlobal(globalCursorPosition)); m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta = WidgetPositionToNormalizedPosition(cursorDelta); - switch(m_cursorMode) + switch (m_cursorMode) { - case CURSOR_MODE_CAPTURED: - AzQtComponents::SetCursorPos(m_previousGlobalCursorPosition); - break; - case CURSOR_MODE_WRAPPED_X: + case CursorInputMode::CursorModeCaptured: + AzQtComponents::SetCursorPos(m_previousGlobalCursorPosition); + break; + case CursorInputMode::CursorModeWrappedX: + case CursorInputMode::CursorModeWrappedY: + case CursorInputMode::CursorModeWrapped: + { QPoint screenPos(globalCursorPosition); - wrapCursorX(widgetRect, screenPos); + switch (m_cursorMode) + { + case CursorInputMode::CursorModeWrappedX: + wrapCursorX(widgetRect, screenPos); + break; + case CursorInputMode::CursorModeWrappedY: + wrapCursorY(widgetRect, screenPos); + break; + case CursorInputMode::CursorModeWrapped: + wrapCursorX(widgetRect, screenPos); + wrapCursorY(widgetRect, screenPos); + break; + default: + // this should never happen + AZ_Assert(false, "Invalid Curosr Mode: %i.", m_cursorMode); + break; + } QCursor::setPos(screen, screenPos); - QPoint screenDelta = globalCursorPosition - screenPos; + const QPoint screenDelta = globalCursorPosition - screenPos; m_previousGlobalCursorPosition = globalCursorPosition - screenDelta; - break; - case CURSOR_MODE_WRAPPED_Y: - QPoint screenPos(globalCursorPosition); - wrapCursorY(widgetRect, screenPos); - QCursor::setPos(screen, screenPos); - QPoint screenDelta = globalCursorPosition - screenPos; - m_previousGlobalCursorPosition = globalCursorPosition - screenDelta; - break; - case CURSOR_MODE_WRAPPED: - QPoint screenPos(globalCursorPosition); - wrapCursorX(widgetRect, screenPos); - wrapCursorY(widgetRect, screenPos); - QCursor::setPos(screen, screenPos); - QPoint screenDelta = globalCursorPosition - screenPos; - m_previousGlobalCursorPosition = globalCursorPosition - screenDelta; - break; - default: - m_previousGlobalCursorPosition = globalCursorPosition; - break; - - + } + break; + default: + AZ_Assert(false, "Invalid Curosr Mode: %i.", m_cursorMode); + break; } ProcessPendingMouseEvents(cursorDelta); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.h index 7ba4e21bd4..a6d9fdd753 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.h @@ -41,15 +41,15 @@ namespace AzToolsFramework Q_OBJECT public: - enum CursorInputMode { - CURSOR_MODE_NONE, - CURSOR_MODE_CAPTURED, //< Sets whether or not the cursor should be constrained to the source widget and invisible. + enum class CursorInputMode { + CursorModeNone, + CursorModeCaptured, //< Sets whether or not the cursor should be constrained to the source widget and invisible. //< Internally, this will reset the cursor position after each move event to ensure movement //< events don't allow the cursor to escape. This can be used for typical camera controls //< like a dolly or rotation, where mouse movement is important but cursor location is not. - CURSOR_MODE_WRAPPED, //< Flags whether the curser is going to wrap around the soruce widget. - CURSOR_MODE_WRAPPED_X, - CURSOR_MODE_WRAPPED_Y + CursorModeWrapped, //< Flags whether the curser is going to wrap around the soruce widget. + CursorModeWrappedX, + CursorModeWrappedY }; QtEventToAzInputMapper(QWidget* sourceWidget, int syntheticDeviceId = 0); @@ -192,7 +192,7 @@ namespace AzToolsFramework // Flags whether or not Qt events should currently be processed. bool m_enabled = true; // Controls the cursor behavior. - QtEventToAzInputMapper::CursorInputMode m_cursorMode = CURSOR_MODE_NONE; + QtEventToAzInputMapper::CursorInputMode m_cursorMode = CursorInputMode::CursorModeNone; // Flags whether the cursor has been overridden. bool m_overrideCursor = false; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp index cbede827e2..ef23560d57 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp @@ -331,12 +331,12 @@ namespace AtomToolsFramework void RenderViewportWidget::BeginCursorCapture() { - m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CURSOR_MODE_CAPTURED); + m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CursorModeCaptured); } void RenderViewportWidget::EndCursorCapture() { - m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CURSOR_MODE_NONE); + m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CursorModeNone); } void RenderViewportWidget::SetOverrideCursor(AzToolsFramework::ViewportInteraction::CursorStyleOverride cursorStyleOverride) From 3a6f877a9f79157424d5a86d05f9f1b7a98d1585 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 14 Dec 2021 23:05:13 -0800 Subject: [PATCH 012/136] chore: add first test Signed-off-by: Michael Pollind --- .../Input/QtEventToAzInputMapper.cpp | 8 ++--- .../Input/QtEventToAzInputMapperTests.cpp | 32 +++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp index 77f297b98c..7852a4a5d5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp @@ -447,11 +447,11 @@ namespace AzToolsFramework void wrapCursorX(const QRect& rect, QPoint& point) { - if (rect.left() < point.x()) + if (point.x() < rect.left()) { point.setX(rect.right() - 1); } - else if (rect.right() > point.x()) + else if (point.x() > rect.right()) { point.setX(rect.left() + 1); } @@ -459,11 +459,11 @@ namespace AzToolsFramework void wrapCursorY(const QRect& rect, QPoint& point) { - if (rect.top() < point.y()) + if (point.y() < rect.top()) { point.setY(rect.bottom() - 1); } - else if (rect.bottom() > point.y()) + else if (point.y() > rect.bottom()) { point.setY(rect.top() + 1); } diff --git a/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp b/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp index 4c813a4bdd..e645c365e2 100644 --- a/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp @@ -44,6 +44,10 @@ namespace UnitTest QObject::connect(m_inputChannelMapper.get(), &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, m_rootWidget.get(), [this]([[maybe_unused]] const AzFramework::InputChannel* inputChannel, QEvent* event) { + if(event == nullptr) { + return; + } + const QEvent::Type eventType = event->type(); if (eventType == QEvent::Type::MouseButtonPress || @@ -512,4 +516,32 @@ namespace UnitTest return info.param.m_az.GetName(); } ); + + TEST_F(QtEventToAzInputMapperFixture, MouseWrapMouseViewportQtEventToAzInputMapperFixture) + { + AzFramework::InputChannelNotificationBus::Handler::BusConnect(); + m_captureAzEvents = false; + + + const auto startPos = QPoint(WidgetSize.width() - 2, WidgetSize.height() / 2); + MouseMove(m_rootWidget.get(), startPos, QPoint(0,0)); + m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CursorInputMode::CursorModeWrappedX); + + const auto deltaPos = QPoint(200.0f, 0); + const auto expectedPosition = m_rootWidget->mapToGlobal(QPoint(200, WidgetSize.height() / 2)); + const int iterations = 50; + + for(float i = 0; i < iterations; i++) { + MouseMove(m_rootWidget.get(), m_rootWidget->mapFromGlobal(QCursor::pos()), (deltaPos / iterations)); + } + + QPointF endPosition = QCursor::pos(); + EXPECT_NEAR(endPosition.x(), expectedPosition.x(), 5.0f); + EXPECT_NEAR(endPosition.y(), expectedPosition.y(), 5.0f); + + // cleanup + m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CursorInputMode::CursorModeNone); + AzFramework::InputChannelNotificationBus::Handler::BusDisconnect(); + } + } // namespace UnitTest From 9e91c1872670c73cd1f3de98de616675ce9da8a5 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 15 Dec 2021 13:32:24 -0800 Subject: [PATCH 013/136] chore: address changes add test cases Signed-off-by: Michael Pollind --- Code/Editor/EditorViewportSettings.cpp | 2 +- .../Input/QtEventToAzInputMapper.cpp | 14 +- .../Input/QtEventToAzInputMapper.h | 26 +-- .../Input/QtEventToAzInputMapperTests.cpp | 151 +++++++++++++++--- 4 files changed, 153 insertions(+), 40 deletions(-) diff --git a/Code/Editor/EditorViewportSettings.cpp b/Code/Editor/EditorViewportSettings.cpp index 883eb91863..7108beca5a 100644 --- a/Code/Editor/EditorViewportSettings.cpp +++ b/Code/Editor/EditorViewportSettings.cpp @@ -189,7 +189,7 @@ namespace SandboxEditor bool ViewportMouseWrapSetting() { - return aznumeric_cast(GetRegistry(ViewportMouseWrapSetting, false)); + return GetRegistry(ViewportMouseWrapSetting, false); } void SetViewportMouseWrapSetting(bool wrapping) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp index 7852a4a5d5..edd45a7200 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp @@ -241,7 +241,7 @@ namespace AzToolsFramework } } - void QtEventToAzInputMapper::SetCursorMode(QtEventToAzInputMapper::CursorInputMode mode) + void QtEventToAzInputMapper::SetCursorMode(AzToolsFramework::CursorInputMode mode) { if (mode != m_cursorMode) { @@ -445,7 +445,7 @@ namespace AzToolsFramework return QPoint{ denormalizedX, denormalizedY }; } - void wrapCursorX(const QRect& rect, QPoint& point) + void WrapCursorX(const QRect& rect, QPoint& point) { if (point.x() < rect.left()) { @@ -457,7 +457,7 @@ namespace AzToolsFramework } } - void wrapCursorY(const QRect& rect, QPoint& point) + void WrapCursorY(const QRect& rect, QPoint& point) { if (point.y() < rect.top()) { @@ -492,14 +492,14 @@ namespace AzToolsFramework switch (m_cursorMode) { case CursorInputMode::CursorModeWrappedX: - wrapCursorX(widgetRect, screenPos); + WrapCursorX(widgetRect, screenPos); break; case CursorInputMode::CursorModeWrappedY: - wrapCursorY(widgetRect, screenPos); + WrapCursorY(widgetRect, screenPos); break; case CursorInputMode::CursorModeWrapped: - wrapCursorX(widgetRect, screenPos); - wrapCursorY(widgetRect, screenPos); + WrapCursorX(widgetRect, screenPos); + WrapCursorY(widgetRect, screenPos); break; default: // this should never happen diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.h index a6d9fdd753..b84ac99c74 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.h @@ -32,6 +32,17 @@ class QWheelEvent; namespace AzToolsFramework { + enum class CursorInputMode { + CursorModeNone, + CursorModeCaptured, //!< Sets whether or not the cursor should be constrained to the source widget and invisible. + //!< Internally, this will reset the cursor position after each move event to ensure movement + //!< events don't allow the cursor to escape. This can be used for typical camera controls + //!< like a dolly or rotation, where mouse movement is important but cursor location is not. + CursorModeWrapped, //!< Flags whether the curser is going to wrap around the soruce widget. + CursorModeWrappedX, + CursorModeWrappedY + }; + //! Maps events from the Qt input system to synthetic InputChannels in AzFramework //! that can be used by AzFramework::ViewportControllers. class QtEventToAzInputMapper final @@ -41,17 +52,6 @@ namespace AzToolsFramework Q_OBJECT public: - enum class CursorInputMode { - CursorModeNone, - CursorModeCaptured, //< Sets whether or not the cursor should be constrained to the source widget and invisible. - //< Internally, this will reset the cursor position after each move event to ensure movement - //< events don't allow the cursor to escape. This can be used for typical camera controls - //< like a dolly or rotation, where mouse movement is important but cursor location is not. - CursorModeWrapped, //< Flags whether the curser is going to wrap around the soruce widget. - CursorModeWrappedX, - CursorModeWrappedY - }; - QtEventToAzInputMapper(QWidget* sourceWidget, int syntheticDeviceId = 0); ~QtEventToAzInputMapper() = default; @@ -71,7 +71,7 @@ namespace AzToolsFramework void SetCursorCaptureEnabled(bool enabled); //! Set the cursor mode. - void SetCursorMode(QtEventToAzInputMapper::CursorInputMode mode); + void SetCursorMode(AzToolsFramework::CursorInputMode mode); void SetOverrideCursor(ViewportInteraction::CursorStyleOverride cursorStyleOverride); void ClearOverrideCursor(); @@ -192,7 +192,7 @@ namespace AzToolsFramework // Flags whether or not Qt events should currently be processed. bool m_enabled = true; // Controls the cursor behavior. - QtEventToAzInputMapper::CursorInputMode m_cursorMode = CursorInputMode::CursorModeNone; + AzToolsFramework::CursorInputMode m_cursorMode = AzToolsFramework::CursorInputMode::CursorModeNone; // Flags whether the cursor has been overridden. bool m_overrideCursor = false; diff --git a/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp b/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp index e645c365e2..9af445850c 100644 --- a/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp @@ -44,10 +44,10 @@ namespace UnitTest QObject::connect(m_inputChannelMapper.get(), &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, m_rootWidget.get(), [this]([[maybe_unused]] const AzFramework::InputChannel* inputChannel, QEvent* event) { - if(event == nullptr) { + if(event == nullptr) + { return; } - const QEvent::Type eventType = event->type(); if (eventType == QEvent::Type::MouseButtonPress || @@ -517,31 +517,144 @@ namespace UnitTest } ); - TEST_F(QtEventToAzInputMapperFixture, MouseWrapMouseViewportQtEventToAzInputMapperFixture) + struct MouseMoveParam { + AzToolsFramework::CursorInputMode mode; + int iterations; + QPoint startPos; + QPoint deltaPos; + QPoint expectedPos; + const char* name; + }; + + class MoveMoveWrapParamQtEventToAzInputMapperFixture + : public QtEventToAzInputMapperFixture + , public ::testing::WithParamInterface + { + }; + + TEST_P(MoveMoveWrapParamQtEventToAzInputMapperFixture, MouseMove_NoAzHandlers_VerifyMouseMovmentViewport) + { + // setup + const MouseMoveParam mouseMoveParam = GetParam(); + AzFramework::InputChannelNotificationBus::Handler::BusConnect(); m_captureAzEvents = false; + m_inputChannelMapper->SetCursorMode(mouseMoveParam.mode); + m_rootWidget->move(100, 100); - - const auto startPos = QPoint(WidgetSize.width() - 2, WidgetSize.height() / 2); - MouseMove(m_rootWidget.get(), startPos, QPoint(0,0)); - m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CursorInputMode::CursorModeWrappedX); - const auto deltaPos = QPoint(200.0f, 0); - const auto expectedPosition = m_rootWidget->mapToGlobal(QPoint(200, WidgetSize.height() / 2)); - const int iterations = 50; - - for(float i = 0; i < iterations; i++) { - MouseMove(m_rootWidget.get(), m_rootWidget->mapFromGlobal(QCursor::pos()), (deltaPos / iterations)); + MouseMove(m_rootWidget.get(), mouseMoveParam.startPos, QPoint(0,0)); + for(float i = 0; i < mouseMoveParam.iterations; i++) { + MouseMove(m_rootWidget.get(), m_rootWidget->mapFromGlobal(QCursor::pos()), (mouseMoveParam.deltaPos / mouseMoveParam.iterations)); } - - QPointF endPosition = QCursor::pos(); - EXPECT_NEAR(endPosition.x(), expectedPosition.x(), 5.0f); - EXPECT_NEAR(endPosition.y(), expectedPosition.y(), 5.0f); - + + QPointF endPosition = m_rootWidget->mapFromGlobal(QCursor::pos()); + EXPECT_NEAR(endPosition.x(), mouseMoveParam.expectedPos.x(), 1.0f); + EXPECT_NEAR(endPosition.y(), mouseMoveParam.expectedPos.y(), 1.0f); + // cleanup - m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CursorInputMode::CursorModeNone); + m_rootWidget->move(0, 0); + m_inputChannelMapper->SetCursorMode(AzToolsFramework::CursorInputMode::CursorModeNone); AzFramework::InputChannelNotificationBus::Handler::BusDisconnect(); } + INSTANTIATE_TEST_CASE_P(All, MoveMoveWrapParamQtEventToAzInputMapperFixture, + testing::Values( + // verify CursorModeWrappedX wrapping + MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedX, + 40, + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(40, 0), + QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + "CursorModeWrappedX_Test_Right" + }, + MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedX, + 40, + QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(-40, 0), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + "CursorModeWrappedX_Test_Left" + }, + MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedX, + 40, + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, 20.0f), + QPoint(0, -40), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, -20.0f), + "CursorModeWrappedX_Test_Top" + }, + MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedX, + 40, + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() - 20), + QPoint(0, 40), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() + 20), + "CursorModeWrappedX_Test_Bottom" + }, + + // verify CursorModeWrappedY wrapping + MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedY, + 40, + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(40, 0), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() + 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + "CursorModeWrappedY_Test_Right" + }, + MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedY, + 40, + QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(-40, 0), + QPoint(-20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + "CursorModeWrappedY_Test_Left" + }, + MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedY, + 40, + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, 20.0f), + QPoint(0, -40), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() - 20.0f), + "CursorModeWrappedY_Test_Top" + }, + MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedY, + 40, + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() - 20), + QPoint(0, 40), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, 20), + "CursorModeWrappedY_Test_Bottom" + }, + + // verify CursorModeWrapped wrapping + MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrapped, + 40, + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(40, 0), + QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + "CursorModeWrapped_Test_Right" + }, + MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrapped, + 40, + QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(-40, 0), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + "CursorModeWrapped_Test_Left" + }, + MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrapped, + 40, + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, 20.0f), + QPoint(0, -40), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() - 20.0f), + "CursorModeWrapped_Test_Top" + }, + MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrapped, + 40, + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() - 20), + QPoint(0, 40), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, 20), + "CursorModeWrapped_Test_Bottom" + } + ), + [](const ::testing::TestParamInfo& info) + { + return info.param.name; + } + ); + } // namespace UnitTest From 1654ff052041567778624fd7078164533bc37f42 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Thu, 16 Dec 2021 22:37:31 -0800 Subject: [PATCH 014/136] chore: correct test case MouseMove_NoAzHandlers_VerifyMouseMovementViewport Signed-off-by: Michael Pollind --- .../Input/QtEventToAzInputMapper.cpp | 3 ++ .../Input/QtEventToAzInputMapper.h | 4 +- .../Input/QtEventToAzInputMapperTests.cpp | 43 ++++++++++++++++--- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp index edd45a7200..b660e87b56 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.cpp @@ -511,6 +511,9 @@ namespace AzToolsFramework m_previousGlobalCursorPosition = globalCursorPosition - screenDelta; } break; + case CursorInputMode::CursorModeNone: + m_previousGlobalCursorPosition = globalCursorPosition; + break; default: AZ_Assert(false, "Invalid Curosr Mode: %i.", m_cursorMode); break; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.h index b84ac99c74..67ef195363 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Input/QtEventToAzInputMapper.h @@ -39,8 +39,8 @@ namespace AzToolsFramework //!< events don't allow the cursor to escape. This can be used for typical camera controls //!< like a dolly or rotation, where mouse movement is important but cursor location is not. CursorModeWrapped, //!< Flags whether the curser is going to wrap around the soruce widget. - CursorModeWrappedX, - CursorModeWrappedY + CursorModeWrappedX, //!< Flags whether the curser is going to wrap around the soruce widget only on the left and right side. + CursorModeWrappedY //!< Flags whether the curser is going to wrap around the soruce widget only on the top and bottom side. }; //! Maps events from the Qt input system to synthetic InputChannels in AzFramework diff --git a/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp b/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp index 9af445850c..0282812be7 100644 --- a/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp @@ -533,23 +533,38 @@ namespace UnitTest { }; - TEST_P(MoveMoveWrapParamQtEventToAzInputMapperFixture, MouseMove_NoAzHandlers_VerifyMouseMovmentViewport) + TEST_P(MoveMoveWrapParamQtEventToAzInputMapperFixture, MouseMove_NoAzHandlers_VerifyMouseMovementViewport) { + //TODO: mouseMove is bugged mapToGlobal is called twice + auto mouseMoveFix = [](QWidget* wid, QPoint globalPos, QPoint deltaPos) + { + QPoint globalPosition = globalPos + deltaPos; + QPoint localPosition = wid->mapFromGlobal(globalPosition); + QTest::mouseMove(wid, localPosition); + QMouseEvent mouseMoveEvent(QEvent::MouseMove, localPosition, globalPosition, Qt::NoButton, Qt::NoButton, Qt::NoModifier); + QApplication::sendEvent(wid, &mouseMoveEvent); + }; + // setup const MouseMoveParam mouseMoveParam = GetParam(); AzFramework::InputChannelNotificationBus::Handler::BusConnect(); m_captureAzEvents = false; - m_inputChannelMapper->SetCursorMode(mouseMoveParam.mode); + m_rootWidget->move(100, 100); + mouseMoveFix(m_rootWidget.get(), m_rootWidget->mapToGlobal(mouseMoveParam.startPos), QPoint(0, 0)); + // given + m_inputChannelMapper->SetCursorMode(mouseMoveParam.mode); - MouseMove(m_rootWidget.get(), mouseMoveParam.startPos, QPoint(0,0)); - for(float i = 0; i < mouseMoveParam.iterations; i++) { - MouseMove(m_rootWidget.get(), m_rootWidget->mapFromGlobal(QCursor::pos()), (mouseMoveParam.deltaPos / mouseMoveParam.iterations)); + mouseMoveFix(m_rootWidget.get(), m_rootWidget->mapToGlobal(mouseMoveParam.startPos), QPoint(0, 0)); + for (float i = 0; i < mouseMoveParam.iterations; i++) + { + mouseMoveFix(m_rootWidget.get(), QCursor::pos(), (mouseMoveParam.deltaPos / mouseMoveParam.iterations)); } - QPointF endPosition = m_rootWidget->mapFromGlobal(QCursor::pos()); + // validate + QPoint endPosition = m_rootWidget->mapFromGlobal(QCursor::pos()); EXPECT_NEAR(endPosition.x(), mouseMoveParam.expectedPos.x(), 1.0f); EXPECT_NEAR(endPosition.y(), mouseMoveParam.expectedPos.y(), 1.0f); @@ -649,6 +664,22 @@ namespace UnitTest QPoint(0, 40), QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, 20), "CursorModeWrapped_Test_Bottom" + }, + // verify CursorModeCaptured + MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeCaptured, + 40, + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() / 2.0f), + QPoint(0, 40), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() / 2.0f), + "CursorModeCaptured" + }, + // verify CursorModeNone + MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeNone, + 40, + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() / 2.0f), + QPoint(40.0f, 0), + QPoint((QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f) + 40.0f, (QtEventToAzInputMapperFixture::WidgetSize.height() / 2.0f)), + "CursorModeNone" } ), [](const ::testing::TestParamInfo& info) From 95c0c83642b2496f96418745b6c245ee50cf87b9 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 18 Dec 2021 18:29:39 -0800 Subject: [PATCH 015/136] chore: remove unused setting and fixed compiling errors Signed-off-by: Michael Pollind --- Code/Editor/EditorViewportSettings.cpp | 11 ----------- Code/Editor/EditorViewportSettings.h | 3 --- .../Tests/test_ModularViewportCameraController.cpp | 4 ++-- .../Code/Source/Viewport/RenderViewportWidget.cpp | 4 ++-- 4 files changed, 4 insertions(+), 18 deletions(-) diff --git a/Code/Editor/EditorViewportSettings.cpp b/Code/Editor/EditorViewportSettings.cpp index 7108beca5a..e06b9696e1 100644 --- a/Code/Editor/EditorViewportSettings.cpp +++ b/Code/Editor/EditorViewportSettings.cpp @@ -23,7 +23,6 @@ namespace SandboxEditor constexpr AZStd::string_view AngleSizeSetting = "/Amazon/Preferences/Editor/AngleSize"; constexpr AZStd::string_view ShowGridSetting = "/Amazon/Preferences/Editor/ShowGrid"; constexpr AZStd::string_view StickySelectSetting = "/Amazon/Preferences/Editor/StickySelect"; - constexpr AZStd::string_view ViewportMouseWrapSetting = "/Amazon/Preferences/Editor/Manipulator/MouseWrapping"; constexpr AZStd::string_view ManipulatorLineBoundWidthSetting = "/Amazon/Preferences/Editor/Manipulator/LineBoundWidth"; constexpr AZStd::string_view ManipulatorCircleBoundWidthSetting = "/Amazon/Preferences/Editor/Manipulator/CircleBoundWidth"; constexpr AZStd::string_view CameraTranslateSpeedSetting = "/Amazon/Preferences/Editor/Camera/TranslateSpeed"; @@ -187,16 +186,6 @@ namespace SandboxEditor AzToolsFramework::SetRegistry(ManipulatorLineBoundWidthSetting, lineBoundWidth); } - bool ViewportMouseWrapSetting() - { - return GetRegistry(ViewportMouseWrapSetting, false); - } - - void SetViewportMouseWrapSetting(bool wrapping) - { - SetRegistry(ViewportMouseWrapSetting, wrapping); - } - float ManipulatorCircleBoundWidth() { return aznumeric_cast(AzToolsFramework::GetRegistry(ManipulatorCircleBoundWidthSetting, 0.1)); diff --git a/Code/Editor/EditorViewportSettings.h b/Code/Editor/EditorViewportSettings.h index a27187bc55..fe1253ed0c 100644 --- a/Code/Editor/EditorViewportSettings.h +++ b/Code/Editor/EditorViewportSettings.h @@ -57,9 +57,6 @@ namespace SandboxEditor SANDBOX_API float ManipulatorLineBoundWidth(); SANDBOX_API void SetManipulatorLineBoundWidth(float lineBoundWidth); - SANDBOX_API bool ViewportMouseWrapSetting(); - SANDBOX_API void SetViewportMouseWrapSetting(bool wrapping); - SANDBOX_API float ManipulatorCircleBoundWidth(); SANDBOX_API void SetManipulatorCircleBoundWidth(float circleBoundWidth); diff --git a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp index 9bfd9d396e..5009c626e2 100644 --- a/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp +++ b/Code/Editor/Lib/Tests/test_ModularViewportCameraController.cpp @@ -47,12 +47,12 @@ namespace UnitTest void ViewportMouseCursorRequestImpl::BeginCursorCapture() { - m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CursorModeCaptured); + m_inputChannelMapper->SetCursorMode(AzToolsFramework::CursorInputMode::CursorModeCaptured); } void ViewportMouseCursorRequestImpl::EndCursorCapture() { - m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CursorModeNone); + m_inputChannelMapper->SetCursorMode(AzToolsFramework::CursorInputMode::CursorModeNone); } bool ViewportMouseCursorRequestImpl::IsMouseOver() const diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp index ef23560d57..d6871a8795 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp @@ -331,12 +331,12 @@ namespace AtomToolsFramework void RenderViewportWidget::BeginCursorCapture() { - m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CursorModeCaptured); + m_inputChannelMapper->SetCursorMode(AzToolsFramework::CursorInputMode::CursorModeCaptured); } void RenderViewportWidget::EndCursorCapture() { - m_inputChannelMapper->SetCursorMode(AzToolsFramework::QtEventToAzInputMapper::CursorModeNone); + m_inputChannelMapper->SetCursorMode(AzToolsFramework::CursorInputMode::CursorModeNone); } void RenderViewportWidget::SetOverrideCursor(AzToolsFramework::ViewportInteraction::CursorStyleOverride cursorStyleOverride) From ed39c784c304c0cf9a374b297f3521f7f0787fc2 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 19 Dec 2021 18:22:14 -0800 Subject: [PATCH 016/136] chore: add accumulated test for mouse position Signed-off-by: Michael Pollind --- .../Tests/Input/QtEventToAzInputMapperTests.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp b/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp index 0282812be7..5047c19044 100644 --- a/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp @@ -100,6 +100,11 @@ namespace UnitTest m_azChannelEvents.push_back(AzEventInfo(inputChannel)); hasBeenConsumed = m_captureAzEvents; } + else if (inputChannelId == AzFramework::InputDeviceMouse::SystemCursorPosition) + { + m_azCursorPositions.push_back(*inputChannel.GetCustomData()); + hasBeenConsumed = m_captureAzEvents; + } } else if (AzFramework::InputDeviceKeyboard::IsKeyboardDevice(inputDeviceId)) { @@ -165,6 +170,7 @@ namespace UnitTest AZStd::vector m_signalEvents; AZStd::vector m_azChannelEvents; AZStd::vector m_azTextEvents; + AZStd::vector m_azCursorPositions; bool m_captureAzEvents{ false }; bool m_captureTextEvents{ false }; @@ -549,13 +555,14 @@ namespace UnitTest const MouseMoveParam mouseMoveParam = GetParam(); AzFramework::InputChannelNotificationBus::Handler::BusConnect(); - m_captureAzEvents = false; + m_captureAzEvents = true; m_rootWidget->move(100, 100); mouseMoveFix(m_rootWidget.get(), m_rootWidget->mapToGlobal(mouseMoveParam.startPos), QPoint(0, 0)); // given m_inputChannelMapper->SetCursorMode(mouseMoveParam.mode); + m_azCursorPositions.clear(); mouseMoveFix(m_rootWidget.get(), m_rootWidget->mapToGlobal(mouseMoveParam.startPos), QPoint(0, 0)); for (float i = 0; i < mouseMoveParam.iterations; i++) @@ -563,11 +570,19 @@ namespace UnitTest mouseMoveFix(m_rootWidget.get(), QCursor::pos(), (mouseMoveParam.deltaPos / mouseMoveParam.iterations)); } + AZ::Vector2 accumalatedPosition(0.0f,0.0f); + for(const auto& pos: m_azCursorPositions) { + accumalatedPosition += (pos.m_normalizedPositionDelta * AZ::Vector2(WidgetSize.width(), WidgetSize.height())); + } + // validate QPoint endPosition = m_rootWidget->mapFromGlobal(QCursor::pos()); EXPECT_NEAR(endPosition.x(), mouseMoveParam.expectedPos.x(), 1.0f); EXPECT_NEAR(endPosition.y(), mouseMoveParam.expectedPos.y(), 1.0f); + EXPECT_NEAR(accumalatedPosition.GetX(), mouseMoveParam.deltaPos.x(), 1.0f); + EXPECT_NEAR(accumalatedPosition.GetY(), mouseMoveParam.deltaPos.y(), 1.0f); + // cleanup m_rootWidget->move(0, 0); m_inputChannelMapper->SetCursorMode(AzToolsFramework::CursorInputMode::CursorModeNone); From 832c525f67a0ea24ad004066c0d556c8c449a9af Mon Sep 17 00:00:00 2001 From: nemerle <96597+nemerle@users.noreply.github.com> Date: Sat, 8 Jan 2022 23:22:04 +0100 Subject: [PATCH 017/136] Fix missing include file Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> --- .../Include/Atom/RPI.Public/Shader/ShaderVariantAsyncLoader.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderVariantAsyncLoader.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderVariantAsyncLoader.h index 838cdd2256..60417adf36 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderVariantAsyncLoader.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Shader/ShaderVariantAsyncLoader.h @@ -15,6 +15,7 @@ #include #include #include +#include namespace AZ { From c65a903c7dc8ae5ce441df130f26e735534dd6bd Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 8 Jan 2022 21:01:29 -0800 Subject: [PATCH 018/136] chore: fix unit test Signed-off-by: Michael Pollind --- .../Input/QtEventToAzInputMapperTests.cpp | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp b/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp index 5047c19044..d7ab896462 100644 --- a/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp @@ -541,15 +541,6 @@ namespace UnitTest TEST_P(MoveMoveWrapParamQtEventToAzInputMapperFixture, MouseMove_NoAzHandlers_VerifyMouseMovementViewport) { - //TODO: mouseMove is bugged mapToGlobal is called twice - auto mouseMoveFix = [](QWidget* wid, QPoint globalPos, QPoint deltaPos) - { - QPoint globalPosition = globalPos + deltaPos; - QPoint localPosition = wid->mapFromGlobal(globalPosition); - QTest::mouseMove(wid, localPosition); - QMouseEvent mouseMoveEvent(QEvent::MouseMove, localPosition, globalPosition, Qt::NoButton, Qt::NoButton, Qt::NoModifier); - QApplication::sendEvent(wid, &mouseMoveEvent); - }; // setup const MouseMoveParam mouseMoveParam = GetParam(); @@ -558,30 +549,29 @@ namespace UnitTest m_captureAzEvents = true; m_rootWidget->move(100, 100); - mouseMoveFix(m_rootWidget.get(), m_rootWidget->mapToGlobal(mouseMoveParam.startPos), QPoint(0, 0)); + QScreen* screen = m_rootWidget->screen(); + MouseMove(m_rootWidget.get(), mouseMoveParam.startPos, QPoint(0, 0)); // given m_inputChannelMapper->SetCursorMode(mouseMoveParam.mode); m_azCursorPositions.clear(); - - mouseMoveFix(m_rootWidget.get(), m_rootWidget->mapToGlobal(mouseMoveParam.startPos), QPoint(0, 0)); for (float i = 0; i < mouseMoveParam.iterations; i++) { - mouseMoveFix(m_rootWidget.get(), QCursor::pos(), (mouseMoveParam.deltaPos / mouseMoveParam.iterations)); + MouseMove(m_rootWidget.get(), m_rootWidget->mapFromGlobal(QCursor::pos(screen)), (mouseMoveParam.deltaPos / mouseMoveParam.iterations)); } - AZ::Vector2 accumalatedPosition(0.0f,0.0f); + AZ::Vector2 accumulatedPosition(0.0f,0.0f); for(const auto& pos: m_azCursorPositions) { - accumalatedPosition += (pos.m_normalizedPositionDelta * AZ::Vector2(WidgetSize.width(), WidgetSize.height())); + accumulatedPosition += (pos.m_normalizedPositionDelta * AZ::Vector2(WidgetSize.width(), WidgetSize.height())); } // validate - QPoint endPosition = m_rootWidget->mapFromGlobal(QCursor::pos()); + const QPoint endPosition = m_rootWidget->mapFromGlobal(QCursor::pos(screen)); EXPECT_NEAR(endPosition.x(), mouseMoveParam.expectedPos.x(), 1.0f); EXPECT_NEAR(endPosition.y(), mouseMoveParam.expectedPos.y(), 1.0f); - EXPECT_NEAR(accumalatedPosition.GetX(), mouseMoveParam.deltaPos.x(), 1.0f); - EXPECT_NEAR(accumalatedPosition.GetY(), mouseMoveParam.deltaPos.y(), 1.0f); + EXPECT_NEAR(accumulatedPosition.GetX(), mouseMoveParam.deltaPos.x(), 1.0f); + EXPECT_NEAR(accumulatedPosition.GetY(), mouseMoveParam.deltaPos.y(), 1.0f); // cleanup m_rootWidget->move(0, 0); From 3cac520280a586e38292f6906947b143ac9147e7 Mon Sep 17 00:00:00 2001 From: nemerle <96597+nemerle@users.noreply.github.com> Date: Tue, 11 Jan 2022 00:47:00 +0100 Subject: [PATCH 019/136] Fix non-unity windows build Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> --- Code/Framework/AzCore/Tests/TestCatalog.h | 1 + Gems/Blast/Code/Include/Blast/BlastSystemBus.h | 1 + Gems/Blast/Code/Source/Family/BlastFamilyImpl.cpp | 1 + .../Code/Source/Components/TerrainPhysicsColliderComponent.cpp | 2 ++ 4 files changed, 5 insertions(+) diff --git a/Code/Framework/AzCore/Tests/TestCatalog.h b/Code/Framework/AzCore/Tests/TestCatalog.h index 9a1fb9b5e6..bbcd952f78 100644 --- a/Code/Framework/AzCore/Tests/TestCatalog.h +++ b/Code/Framework/AzCore/Tests/TestCatalog.h @@ -11,6 +11,7 @@ #include #include #include +#include namespace UnitTest { diff --git a/Gems/Blast/Code/Include/Blast/BlastSystemBus.h b/Gems/Blast/Code/Include/Blast/BlastSystemBus.h index 95ffd75057..bda684181a 100644 --- a/Gems/Blast/Code/Include/Blast/BlastSystemBus.h +++ b/Gems/Blast/Code/Include/Blast/BlastSystemBus.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include diff --git a/Gems/Blast/Code/Source/Family/BlastFamilyImpl.cpp b/Gems/Blast/Code/Source/Family/BlastFamilyImpl.cpp index 56c785b310..70e7c28bac 100644 --- a/Gems/Blast/Code/Source/Family/BlastFamilyImpl.cpp +++ b/Gems/Blast/Code/Source/Family/BlastFamilyImpl.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include diff --git a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp index 8c2c0e80b6..fccbedd8fa 100644 --- a/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp +++ b/Gems/Terrain/Code/Source/Components/TerrainPhysicsColliderComponent.cpp @@ -6,12 +6,14 @@ * */ + #include #include #include #include #include +#include #include #include #include From 7b6ce50fe87c8306bc6b3ab1b65e4ddbdaf463be Mon Sep 17 00:00:00 2001 From: nemerle <96597+nemerle@users.noreply.github.com> Date: Tue, 11 Jan 2022 00:52:21 +0100 Subject: [PATCH 020/136] Remove un-needed `Requests` namespace use Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/IO/Streamer/FileRequest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzCore/AzCore/IO/Streamer/FileRequest.cpp b/Code/Framework/AzCore/AzCore/IO/Streamer/FileRequest.cpp index 90014578ea..13c01b2efc 100644 --- a/Code/Framework/AzCore/AzCore/IO/Streamer/FileRequest.cpp +++ b/Code/Framework/AzCore/AzCore/IO/Streamer/FileRequest.cpp @@ -139,7 +139,7 @@ namespace AZ::IO::Requests { } - Requests::ReportData::ReportData(ReportType reportType) + ReportData::ReportData(ReportType reportType) : m_reportType(reportType) { } From 5dc97e7e4b5e9272f4940628833315007a060c8b Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Tue, 11 Jan 2022 16:34:22 -0800 Subject: [PATCH 021/136] Fix Prefab instance assets not preloading PrefabCatchmentProcessor::ProcessPrefab was no longer updating the ProcessedObjectStore's referenced object list, this change exposes the referenced asset list in the new PrefabDocument API and uses them to update the referenced asset list. Signed-off-by: Nicholas Van Sickle --- .../Prefab/Spawnable/PrefabCatchmentProcessor.cpp | 1 + .../Prefab/Spawnable/PrefabDocument.cpp | 12 +++++++++++- .../Prefab/Spawnable/PrefabDocument.h | 4 ++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp index 40cd52cac8..a5ca034c36 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabCatchmentProcessor.cpp @@ -64,6 +64,7 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils AZStd::move(uniqueName), context.GetSourceUuid(), AZStd::move(serializer)); AZ_Assert(spawnable, "Failed to create a new spawnable."); + object.GetReferencedAssets() = prefab.GetReferencedAssets(); Instance& instance = prefab.GetInstance(); // Resolve entity aliases that store PrefabDOM information to use the spawnable instead. This is done before the entities are // moved from the instance as they'd otherwise can't be found. diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.cpp index 04fdea30d2..230c2226cd 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.cpp @@ -124,12 +124,22 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils return *m_instance; } + AZStd::vector>& PrefabDocument::GetReferencedAssets() + { + return m_referencedAssets; + } + + const AZStd::vector>& PrefabDocument::GetReferencedAssets() const + { + return m_referencedAssets; + } + bool PrefabDocument::ConstructInstanceFromPrefabDom(const PrefabDom& prefab) { using namespace AzToolsFramework::Prefab; m_instance->Reset(); - if (PrefabDomUtils::LoadInstanceFromPrefabDom(*m_instance, prefab, PrefabDomUtils::LoadFlags::AssignRandomEntityId)) + if (PrefabDomUtils::LoadInstanceFromPrefabDom(*m_instance, prefab, m_referencedAssets, PrefabDomUtils::LoadFlags::AssignRandomEntityId)) { return true; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.h index 215daf7f71..661dba5edf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Spawnable/PrefabDocument.h @@ -53,12 +53,16 @@ namespace AzToolsFramework::Prefab::PrefabConversionUtils AzToolsFramework::Prefab::Instance& GetInstance(); const AzToolsFramework::Prefab::Instance& GetInstance() const; + AZStd::vector>& GetReferencedAssets(); + const AZStd::vector>& GetReferencedAssets() const; + private: bool ConstructInstanceFromPrefabDom(const PrefabDom& prefab); mutable PrefabDom m_dom; AZStd::unique_ptr m_instance; AZStd::string m_name; + AZStd::vector> m_referencedAssets; mutable bool m_isDirty{ false }; }; } // namespace AzToolsFramework::Prefab::PrefabConversionUtils From 2e19b703ef00e4f1bc94a904901c83f2e6fa3e3e Mon Sep 17 00:00:00 2001 From: nemerle <96597+nemerle@users.noreply.github.com> Date: Wed, 12 Jan 2022 01:37:02 +0100 Subject: [PATCH 022/136] fix release build Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> --- Gems/AudioSystem/Code/Source/Engine/ATLEntities.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gems/AudioSystem/Code/Source/Engine/ATLEntities.cpp b/Gems/AudioSystem/Code/Source/Engine/ATLEntities.cpp index 45a95a71d7..f799e8e69f 100644 --- a/Gems/AudioSystem/Code/Source/Engine/ATLEntities.cpp +++ b/Gems/AudioSystem/Code/Source/Engine/ATLEntities.cpp @@ -286,7 +286,9 @@ namespace Audio return sResult; } - CATLAudioFileEntry::CATLAudioFileEntry(const char * const filePath, IATLAudioFileEntryData * const implData) + +#endif // !AUDIO_RELEASE + CATLAudioFileEntry::CATLAudioFileEntry(const char* const filePath, IATLAudioFileEntryData* const implData) : m_filePath(filePath) , m_fileSize(0) , m_useCount(0) @@ -299,6 +301,4 @@ namespace Audio } CATLAudioFileEntry::~CATLAudioFileEntry() = default; - -#endif // !AUDIO_RELEASE } // namespace Audio From b772d7b3e8abd15acaf1db40d5a79357927f014d Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 12 Jan 2022 11:10:34 -0800 Subject: [PATCH 023/136] Removing multiplayer script canvas translation files from the scriptcanvas gem; these will eventually move into AutomatedTesting project once repopulated (if needed). Signed-off-by: Gene Walters --- ...orityToAutonomousNoParamsNotifyEvent.names | 50 -- .../AuthorityToAutonomousNotifyEvent.names | 56 --- ...AuthorityToClientNoParamsNotifyEvent.names | 50 -- .../AuthorityToClientNotifyEvent.names | 56 --- ...nomousToAuthorityNoParamsNotifyEvent.names | 50 -- .../AutonomousToAuthorityNotifyEvent.names | 56 --- .../ServerToAuthorityNoParamNotifyEvent.names | 50 -- .../ServerToAuthorityNotifyEvent.names | 56 --- .../Classes/NetworkTestPlayerComponent.names | 438 ------------------ ...tworkTestPlayerComponentNetworkInput.names | 129 ------ 10 files changed, 991 deletions(-) delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNoParamsNotifyEvent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNotifyEvent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNoParamsNotifyEvent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNotifyEvent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNoParamsNotifyEvent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNotifyEvent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNoParamNotifyEvent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNotifyEvent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponent.names delete mode 100644 Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponentNetworkInput.names diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNoParamsNotifyEvent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNoParamsNotifyEvent.names deleted file mode 100644 index 216212ca4a..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNoParamsNotifyEvent.names +++ /dev/null @@ -1,50 +0,0 @@ -{ - "entries": [ - { - "base": "AuthorityToAutonomousNoParams Notify Event", - "context": "AZEventHandler", - "variant": "", - "details": { - "name": "Authority To Autonomous No Params Notify Event" - }, - "slots": [ - { - "base": "AuthorityToAutonomousNoParams Notify Event", - "details": { - "name": "AuthorityToAutonomousNoParams Notify Event" - } - }, - { - "base": "Connect", - "details": { - "name": "Connect" - } - }, - { - "base": "Disconnect", - "details": { - "name": "Disconnect" - } - }, - { - "base": "On Connected", - "details": { - "name": "On Connected" - } - }, - { - "base": "On Disconnected", - "details": { - "name": "On Disconnected" - } - }, - { - "base": "OnEvent", - "details": { - "name": "OnEvent" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNotifyEvent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNotifyEvent.names deleted file mode 100644 index 50c0ec6013..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNotifyEvent.names +++ /dev/null @@ -1,56 +0,0 @@ -{ - "entries": [ - { - "base": "AuthorityToAutonomous Notify Event", - "context": "AZEventHandler", - "variant": "", - "details": { - "name": "Authority To Autonomous Notify Event" - }, - "slots": [ - { - "base": "someFloat", - "details": { - "name": "someFloat" - } - }, - { - "base": "AuthorityToAutonomous Notify Event", - "details": { - "name": "AuthorityToAutonomous Notify Event" - } - }, - { - "base": "Connect", - "details": { - "name": "Connect" - } - }, - { - "base": "Disconnect", - "details": { - "name": "Disconnect" - } - }, - { - "base": "On Connected", - "details": { - "name": "On Connected" - } - }, - { - "base": "On Disconnected", - "details": { - "name": "On Disconnected" - } - }, - { - "base": "OnEvent", - "details": { - "name": "OnEvent" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNoParamsNotifyEvent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNoParamsNotifyEvent.names deleted file mode 100644 index bf5b975d63..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNoParamsNotifyEvent.names +++ /dev/null @@ -1,50 +0,0 @@ -{ - "entries": [ - { - "base": "AuthorityToClientNoParams Notify Event", - "context": "AZEventHandler", - "variant": "", - "details": { - "name": "Authority To Client No Params Notify Event" - }, - "slots": [ - { - "base": "AuthorityToClientNoParams Notify Event", - "details": { - "name": "AuthorityToClientNoParams Notify Event" - } - }, - { - "base": "Connect", - "details": { - "name": "Connect" - } - }, - { - "base": "Disconnect", - "details": { - "name": "Disconnect" - } - }, - { - "base": "On Connected", - "details": { - "name": "On Connected" - } - }, - { - "base": "On Disconnected", - "details": { - "name": "On Disconnected" - } - }, - { - "base": "OnEvent", - "details": { - "name": "OnEvent" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNotifyEvent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNotifyEvent.names deleted file mode 100644 index d3ba2e9299..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNotifyEvent.names +++ /dev/null @@ -1,56 +0,0 @@ -{ - "entries": [ - { - "base": "AuthorityToClient Notify Event", - "context": "AZEventHandler", - "variant": "", - "details": { - "name": "Authority To Client Notify Event" - }, - "slots": [ - { - "base": "someFloat", - "details": { - "name": "someFloat" - } - }, - { - "base": "AuthorityToClient Notify Event", - "details": { - "name": "AuthorityToClient Notify Event" - } - }, - { - "base": "Connect", - "details": { - "name": "Connect" - } - }, - { - "base": "Disconnect", - "details": { - "name": "Disconnect" - } - }, - { - "base": "On Connected", - "details": { - "name": "On Connected" - } - }, - { - "base": "On Disconnected", - "details": { - "name": "On Disconnected" - } - }, - { - "base": "OnEvent", - "details": { - "name": "OnEvent" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNoParamsNotifyEvent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNoParamsNotifyEvent.names deleted file mode 100644 index ba5f7aec0c..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNoParamsNotifyEvent.names +++ /dev/null @@ -1,50 +0,0 @@ -{ - "entries": [ - { - "base": "AutonomousToAuthorityNoParams Notify Event", - "context": "AZEventHandler", - "variant": "", - "details": { - "name": "Autonomous To Authority No Params Notify Event" - }, - "slots": [ - { - "base": "AutonomousToAuthorityNoParams Notify Event", - "details": { - "name": "AutonomousToAuthorityNoParams Notify Event" - } - }, - { - "base": "Connect", - "details": { - "name": "Connect" - } - }, - { - "base": "Disconnect", - "details": { - "name": "Disconnect" - } - }, - { - "base": "On Connected", - "details": { - "name": "On Connected" - } - }, - { - "base": "On Disconnected", - "details": { - "name": "On Disconnected" - } - }, - { - "base": "OnEvent", - "details": { - "name": "OnEvent" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNotifyEvent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNotifyEvent.names deleted file mode 100644 index 73566d177e..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNotifyEvent.names +++ /dev/null @@ -1,56 +0,0 @@ -{ - "entries": [ - { - "base": "AutonomousToAuthority Notify Event", - "context": "AZEventHandler", - "variant": "", - "details": { - "name": "Autonomous To Authority Notify Event" - }, - "slots": [ - { - "base": "someFloat", - "details": { - "name": "someFloat" - } - }, - { - "base": "AutonomousToAuthority Notify Event", - "details": { - "name": "AutonomousToAuthority Notify Event" - } - }, - { - "base": "Connect", - "details": { - "name": "Connect" - } - }, - { - "base": "Disconnect", - "details": { - "name": "Disconnect" - } - }, - { - "base": "On Connected", - "details": { - "name": "On Connected" - } - }, - { - "base": "On Disconnected", - "details": { - "name": "On Disconnected" - } - }, - { - "base": "OnEvent", - "details": { - "name": "OnEvent" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNoParamNotifyEvent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNoParamNotifyEvent.names deleted file mode 100644 index b6694211cd..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNoParamNotifyEvent.names +++ /dev/null @@ -1,50 +0,0 @@ -{ - "entries": [ - { - "base": "ServerToAuthorityNoParam Notify Event", - "context": "AZEventHandler", - "variant": "", - "details": { - "name": "Server To Authority No Param Notify Event" - }, - "slots": [ - { - "base": "ServerToAuthorityNoParam Notify Event", - "details": { - "name": "ServerToAuthorityNoParam Notify Event" - } - }, - { - "base": "Connect", - "details": { - "name": "Connect" - } - }, - { - "base": "Disconnect", - "details": { - "name": "Disconnect" - } - }, - { - "base": "On Connected", - "details": { - "name": "On Connected" - } - }, - { - "base": "On Disconnected", - "details": { - "name": "On Disconnected" - } - }, - { - "base": "OnEvent", - "details": { - "name": "OnEvent" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNotifyEvent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNotifyEvent.names deleted file mode 100644 index 71ab303260..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNotifyEvent.names +++ /dev/null @@ -1,56 +0,0 @@ -{ - "entries": [ - { - "base": "ServerToAuthority Notify Event", - "context": "AZEventHandler", - "variant": "", - "details": { - "name": "Server To Authority Notify Event" - }, - "slots": [ - { - "base": "someFloat", - "details": { - "name": "someFloat" - } - }, - { - "base": "ServerToAuthority Notify Event", - "details": { - "name": "ServerToAuthority Notify Event" - } - }, - { - "base": "Connect", - "details": { - "name": "Connect" - } - }, - { - "base": "Disconnect", - "details": { - "name": "Disconnect" - } - }, - { - "base": "On Connected", - "details": { - "name": "On Connected" - } - }, - { - "base": "On Disconnected", - "details": { - "name": "On Disconnected" - } - }, - { - "base": "OnEvent", - "details": { - "name": "OnEvent" - } - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponent.names b/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponent.names deleted file mode 100644 index 22636e0453..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponent.names +++ /dev/null @@ -1,438 +0,0 @@ -{ - "entries": [ - { - "base": "NetworkTestPlayerComponent", - "context": "BehaviorClass", - "variant": "", - "details": { - "name": "Network Test Player Component" - }, - "methods": [ - { - "base": "AutonomousToAuthority", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Autonomous To Authority" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Autonomous To Authority is invoked" - }, - "details": { - "name": "Autonomous To Authority" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "float" - } - } - ] - }, - { - "base": "ServerToAuthority", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Server To Authority" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Server To Authority is invoked" - }, - "details": { - "name": "Server To Authority" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "float" - } - } - ] - }, - { - "base": "AutonomousToAuthorityByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Autonomous To Authority By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Autonomous To Authority By Entity Id is invoked" - }, - "details": { - "name": "Autonomous To Authority By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "some Float" - } - } - ] - }, - { - "base": "ServerToAuthorityByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Server To Authority By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Server To Authority By Entity Id is invoked" - }, - "details": { - "name": "Server To Authority By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "some Float" - } - } - ] - }, - { - "base": "AutonomousToAuthorityNoParams", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Autonomous To Authority No Params" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Autonomous To Authority No Params is invoked" - }, - "details": { - "name": "Autonomous To Authority No Params" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - } - ] - }, - { - "base": "AuthorityToAutonomous", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Authority To Autonomous" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Authority To Autonomous is invoked" - }, - "details": { - "name": "Authority To Autonomous" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "float" - } - } - ] - }, - { - "base": "AuthorityToClientNoParams", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Authority To Client No Params" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Authority To Client No Params is invoked" - }, - "details": { - "name": "Authority To Client No Params" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - } - ] - }, - { - "base": "AuthorityToClientByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Authority To Client By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Authority To Client By Entity Id is invoked" - }, - "details": { - "name": "Authority To Client By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "some Float" - } - } - ] - }, - { - "base": "AuthorityToClient", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Authority To Client" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Authority To Client is invoked" - }, - "details": { - "name": "Authority To Client" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "float" - } - } - ] - }, - { - "base": "AuthorityToAutonomousNoParams", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Authority To Autonomous No Params" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Authority To Autonomous No Params is invoked" - }, - "details": { - "name": "Authority To Autonomous No Params" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - } - ] - }, - { - "base": "ServerToAuthorityNoParamByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Server To Authority No Param By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Server To Authority No Param By Entity Id is invoked" - }, - "details": { - "name": "Server To Authority No Param By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - } - ] - }, - { - "base": "AuthorityToClientNoParamsByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Authority To Client No Params By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Authority To Client No Params By Entity Id is invoked" - }, - "details": { - "name": "Authority To Client No Params By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - } - ] - }, - { - "base": "AuthorityToAutonomousByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Authority To Autonomous By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Authority To Autonomous By Entity Id is invoked" - }, - "details": { - "name": "Authority To Autonomous By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "some Float" - } - } - ] - }, - { - "base": "AutonomousToAuthorityNoParamsByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Autonomous To Authority No Params By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Autonomous To Authority No Params By Entity Id is invoked" - }, - "details": { - "name": "Autonomous To Authority No Params By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - } - ] - }, - { - "base": "AuthorityToAutonomousNoParamsByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Authority To Autonomous No Params By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Authority To Autonomous No Params By Entity Id is invoked" - }, - "details": { - "name": "Authority To Autonomous No Params By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - } - ] - }, - { - "base": "ServerToAuthorityNoParam", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Server To Authority No Param" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Server To Authority No Param is invoked" - }, - "details": { - "name": "Server To Authority No Param" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - } - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponentNetworkInput.names b/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponentNetworkInput.names deleted file mode 100644 index d8c016db0f..0000000000 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponentNetworkInput.names +++ /dev/null @@ -1,129 +0,0 @@ -{ - "entries": [ - { - "base": "NetworkTestPlayerComponentNetworkInput", - "context": "BehaviorClass", - "variant": "", - "details": { - "name": "Network Test Player Component Network Input" - }, - "methods": [ - { - "base": "CreateFromValues", - "context": "NetworkTestPlayerComponentNetworkInput", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Create From Values" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Create From Values is invoked" - }, - "details": { - "name": "Create From Values" - }, - "params": [ - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "left Right" - } - } - ], - "results": [ - { - "typeid": "{12A1776B-61F6-4E5F-356A-AD718A62051F}", - "details": { - "name": "Network Test Player Component Network Input" - } - } - ] - }, - { - "base": "GetFwdBack", - "details": { - "name": "Get Fwd Back" - }, - "params": [ - { - "typeid": "{12A1776B-61F6-4E5F-356A-AD718A62051F}", - "details": { - "name": "Network Test Player Component Network Input" - } - } - ], - "results": [ - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "Fwd Back" - } - } - ] - }, - { - "base": "SetFwdBack", - "details": { - "name": "Set Fwd Back" - }, - "params": [ - { - "typeid": "{12A1776B-61F6-4E5F-356A-AD718A62051F}", - "details": { - "name": "Network Test Player Component Network Input" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "Fwd Back" - } - } - ] - }, - { - "base": "GetLeftRight", - "details": { - "name": "Get Left Right" - }, - "params": [ - { - "typeid": "{12A1776B-61F6-4E5F-356A-AD718A62051F}", - "details": { - "name": "Network Test Player Component Network Input" - } - } - ], - "results": [ - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "Left Right" - } - } - ] - }, - { - "base": "SetLeftRight", - "details": { - "name": "Set Left Right" - }, - "params": [ - { - "typeid": "{12A1776B-61F6-4E5F-356A-AD718A62051F}", - "details": { - "name": "Network Test Player Component Network Input" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "Left Right" - } - } - ] - } - ] - } - ] -} \ No newline at end of file From 561ff40c8154c335ad435086923a20aefa66a2d5 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 12 Jan 2022 11:13:10 -0800 Subject: [PATCH 024/136] Creating a new multiplayer component which we'll assign to a networked level entity (as opposed to a network player). Signed-off-by: Gene Walters --- ...workTestLevelEntityComponent.AutoComponent.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml diff --git a/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml new file mode 100644 index 0000000000..2fd196a2f6 --- /dev/null +++ b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml @@ -0,0 +1,15 @@ + + + + + + + + + From ee3196d64a9d31929951ad60134b22dbe4b1db02 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 12 Jan 2022 11:31:45 -0800 Subject: [PATCH 025/136] Removed an RPC that's now being used inside the NetLevelEntity autocomponent Signed-off-by: Gene Walters --- .../Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml index 251d2b25af..b4dd35d741 100644 --- a/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml +++ b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml @@ -29,8 +29,6 @@ - - From 3b84049a1d12409d0cfa7bffcd5a059cc592915f Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 12 Jan 2022 12:18:06 -0800 Subject: [PATCH 026/136] Adding NetworkTestLevelEntityComponent to cmake for compilation Signed-off-by: Gene Walters --- AutomatedTesting/Gem/Code/automatedtesting_files.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/AutomatedTesting/Gem/Code/automatedtesting_files.cmake b/AutomatedTesting/Gem/Code/automatedtesting_files.cmake index eb619104a4..1f6dbbd772 100644 --- a/AutomatedTesting/Gem/Code/automatedtesting_files.cmake +++ b/AutomatedTesting/Gem/Code/automatedtesting_files.cmake @@ -12,4 +12,5 @@ set(FILES Source/AutomatedTestingSystemComponent.cpp Source/AutomatedTestingSystemComponent.h Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml + Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml ) From 4e811d5af8383844889ed45f903b8650319c0d08 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 12 Jan 2022 12:19:59 -0800 Subject: [PATCH 027/136] Small update: adding the component type to a warning in order to help debug what component is failing Signed-off-by: Gene Walters --- Code/Framework/AzCore/AzCore/Component/Component.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Component/Component.cpp b/Code/Framework/AzCore/AzCore/Component/Component.cpp index c9829c6dd8..c11e4ef69f 100644 --- a/Code/Framework/AzCore/AzCore/Component/Component.cpp +++ b/Code/Framework/AzCore/AzCore/Component/Component.cpp @@ -49,7 +49,7 @@ namespace AZ return m_entity->GetId(); } - AZ_Warning("System", false, "Can't get component %p entity ID as it is not attached to an entity yet!", this); + AZ_Warning("System", false, "Can't get component (type: %s, addr: %p) entity ID as it is not attached to an entity yet!", RTTI_GetTypeName(), this); return EntityId(); } @@ -60,7 +60,7 @@ namespace AZ return NamedEntityId(m_entity->GetId(), m_entity->GetName()); } - AZ_Warning("System", false, "Can't get component %p entity ID as it is not attached to an entity yet!", this); + AZ_Warning("System", false, "Can't get component (type: %s, addr: %p) entity ID as it is not attached to an entity yet!", RTTI_GetTypeName(), this); return NamedEntityId(); } From a635e935e3893ad974e92a52fe4c71a115f1a325 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 12 Jan 2022 12:20:46 -0800 Subject: [PATCH 028/136] minor typo fix on code warning Signed-off-by: Gene Walters --- Code/Framework/AzCore/AzCore/Component/Entity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzCore/AzCore/Component/Entity.cpp b/Code/Framework/AzCore/AzCore/Component/Entity.cpp index c5cda98f2c..db9ead93ad 100644 --- a/Code/Framework/AzCore/AzCore/Component/Entity.cpp +++ b/Code/Framework/AzCore/AzCore/Component/Entity.cpp @@ -230,7 +230,7 @@ namespace AZ EBUS_EVENT_ID(m_id, EntityBus, OnEntityDeactivated, m_id); EBUS_EVENT(EntitySystemBus, OnEntityDeactivated, m_id); - AZ_Assert(m_state == State::Active, "Component should be in Active state to br Deactivated!"); + AZ_Assert(m_state == State::Active, "Component should be in Active state to be Deactivated!"); SetState(State::Deactivating); for (ComponentArrayType::reverse_iterator it = m_components.rbegin(); it != m_components.rend(); ++it) From 49a0c78013391ca62424560a05a59434ff30c8f9 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 12 Jan 2022 12:33:28 -0800 Subject: [PATCH 029/136] Check if transform component is attached to an entity before sending out notifications that rely upon having an entity; this stops runtime warnings when calling GetEntityId() Signed-off-by: Gene Walters --- .../Components/TransformComponent.cpp | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp index 809f664a10..e4e0ea08b2 100644 --- a/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp +++ b/Code/Framework/AzFramework/AzFramework/Components/TransformComponent.cpp @@ -585,21 +585,25 @@ namespace AzFramework EBUS_EVENT_PTR(m_notificationBus, AZ::TransformNotificationBus, OnParentChanged, oldParent, parentId); m_parentChangedEvent.Signal(oldParent, parentId); - if (oldParent != parentId) // Don't send removal notification while activating. + // Check if we're attached to an entity; the following notifications rely upon having a valid entity id + if (m_entity != nullptr) { - EBUS_EVENT_ID(oldParent, AZ::TransformNotificationBus, OnChildRemoved, GetEntityId()); - auto oldParentTransform = AZ::TransformBus::FindFirstHandler(oldParent); - if (oldParentTransform) + if (oldParent != parentId) // Don't send removal notification while activating. { - oldParentTransform->NotifyChildChangedEvent(AZ::ChildChangeType::Removed, GetEntityId()); + EBUS_EVENT_ID(oldParent, AZ::TransformNotificationBus, OnChildRemoved, GetEntityId()); + auto oldParentTransform = AZ::TransformBus::FindFirstHandler(oldParent); + if (oldParentTransform) + { + oldParentTransform->NotifyChildChangedEvent(AZ::ChildChangeType::Removed, GetEntityId()); + } } - } - EBUS_EVENT_ID(parentId, AZ::TransformNotificationBus, OnChildAdded, GetEntityId()); - auto newParentTransform = AZ::TransformBus::FindFirstHandler(parentId); - if (newParentTransform) - { - newParentTransform->NotifyChildChangedEvent(AZ::ChildChangeType::Added, GetEntityId()); + EBUS_EVENT_ID(parentId, AZ::TransformNotificationBus, OnChildAdded, GetEntityId()); + auto newParentTransform = AZ::TransformBus::FindFirstHandler(parentId); + if (newParentTransform) + { + newParentTransform->NotifyChildChangedEvent(AZ::ChildChangeType::Added, GetEntityId()); + } } } From ffde76208154d9e6c20f44f1d151eff82e763e9e Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Wed, 12 Jan 2022 12:43:39 -0800 Subject: [PATCH 030/136] Minor comment tweak, and code readability Signed-off-by: Gene Walters --- .../Code/Source/Editor/MultiplayerEditorConnection.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp index c8c1ed15bd..3ae4eb6444 100644 --- a/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp +++ b/Gems/Multiplayer/Code/Source/Editor/MultiplayerEditorConnection.cpp @@ -100,8 +100,8 @@ namespace Multiplayer { // Editor Server Init is intended for non-release targets m_byteStream.Write(packet.GetAssetData().GetSize(), reinterpret_cast(packet.ModifyAssetData().GetBuffer())); - - // In case if this is the last update, process the byteStream buffer. Otherwise more packets are expected + + // If this is the last update then process the byteStream buffer. Otherwise more packets are expected if (packet.GetLastUpdate()) { // This is the last expected packet @@ -150,9 +150,8 @@ namespace Multiplayer AZ::Interface::Get()->BuildSpawnablesList(); // Load the level via the root spawnable that was registered - const AZ::CVarFixedString loadLevelString = "LoadLevel Root.spawnable"; const auto console = AZ::Interface::Get(); - console->PerformCommand(loadLevelString.c_str()); + console->PerformCommand("LoadLevel Root.spawnable"); // Setup the normal multiplayer connection AZ::Interface::Get()->InitializeMultiplayer(MultiplayerAgentType::DedicatedServer); From fabb2b186c4d3f0b9cd2aa49a1233977fa796e12 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 12 Jan 2022 20:52:57 -0800 Subject: [PATCH 031/136] chore: disable mouse move test Signed-off-by: Michael Pollind --- .../Tests/Input/QtEventToAzInputMapperTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp b/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp index d7ab896462..31193f6f05 100644 --- a/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp @@ -539,7 +539,7 @@ namespace UnitTest { }; - TEST_P(MoveMoveWrapParamQtEventToAzInputMapperFixture, MouseMove_NoAzHandlers_VerifyMouseMovementViewport) + TEST_P(MoveMoveWrapParamQtEventToAzInputMapperFixture, DISABLED_MouseMove_NoAzHandlers_VerifyMouseMovementViewport) { // setup From c8e5bcc901c989c12c3e485df9427d0546d8d7ac Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Fri, 14 Jan 2022 12:01:32 -0800 Subject: [PATCH 032/136] Dont allow spawning netbound entities by default, we first need to initialize multiplayer and know our network agent type (dedicated-server/client-server/client). This will stop the editor playmode (which doesn't init multiplayer until it connects to the server) from spawning netbound entities Signed-off-by: Gene Walters --- Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index dd2e7956ca..47238cc729 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -184,7 +184,7 @@ namespace Multiplayer double m_serverSendAccumulator = 0.0; float m_renderBlendFactor = 0.0f; float m_tickFactor = 0.0f; - bool m_spawnNetboundEntities = true; + bool m_spawnNetboundEntities = false; #if !defined(AZ_RELEASE_BUILD) MultiplayerEditorConnection m_editorConnectionListener; From e4bd28f636d9421bb1807bac8c1586afa26afe37 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Fri, 14 Jan 2022 13:48:37 -0800 Subject: [PATCH 033/136] Update NetworkSpawnableLibrary to only hold onto network.spawnables (instead of all spawnables) Signed-off-by: Gene Walters --- .../Source/NetworkEntity/NetworkSpawnableLibrary.cpp | 4 ++-- .../Code/Source/NetworkEntity/NetworkSpawnableLibrary.h | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.cpp index f60778dbb4..7fb7bfdc39 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include namespace Multiplayer @@ -42,7 +41,8 @@ namespace Multiplayer auto enumerateCallback = [this](const AZ::Data::AssetId id, const AZ::Data::AssetInfo& info) { - if (info.m_assetType == AZ::AzTypeInfo::Uuid()) + if (info.m_assetType == AZ::AzTypeInfo::Uuid() && + info.m_relativePath.ends_with(".network.spawnable")) { ProcessSpawnableAsset(info.m_relativePath, id); } diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.h b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.h index 0fc3ae07cc..db22ccf9de 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkSpawnableLibrary.h @@ -22,13 +22,16 @@ namespace Multiplayer NetworkSpawnableLibrary(); ~NetworkSpawnableLibrary(); - - /// INetworkSpawnableLibrary overrides. + + //! INetworkSpawnableLibrary overrides. + //! @{ + // Iterates over all assets (on-disk and in-memory) and stores any spawnables that are "network.spawnables" + // This allows us to look up network spawnable assets by name or id for later use void BuildSpawnablesList() override; void ProcessSpawnableAsset(const AZStd::string& relativePath, AZ::Data::AssetId id) override; AZ::Name GetSpawnableNameFromAssetId(AZ::Data::AssetId assetId) override; AZ::Data::AssetId GetAssetIdByName(AZ::Name name) override; - + //! @} private: AZStd::unordered_map m_spawnables; From 786d6b5f85e7c1f5bf1f9ce8d24a0571c8d06ba1 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Tue, 18 Jan 2022 10:22:31 -0800 Subject: [PATCH 034/136] minor code readability tweak Signed-off-by: Gene Walters --- .../Code/Source/NetworkEntity/NetworkEntityManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp index fa524d464a..0a6aeea8a8 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp @@ -542,7 +542,7 @@ namespace Multiplayer optionalArgs.m_preInsertionCallback = [netSpawnableName, rootTransform = transform] (AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableEntityContainerView entities) { - bool shouldUpdateTransform = (rootTransform.IsClose(AZ::Transform::Identity()) == false); + const bool shouldUpdateTransform = !rootTransform.IsClose(AZ::Transform::Identity()); for (uint32_t netEntityIndex = 0, entitiesSize = aznumeric_cast(entities.size()); netEntityIndex < entitiesSize; ++netEntityIndex) From c262696056811660aa3e55cb6a83136232fb12fb Mon Sep 17 00:00:00 2001 From: abrmich Date: Tue, 18 Jan 2022 16:13:28 -0800 Subject: [PATCH 035/136] Move remaining two LyShine headers to the gem Signed-off-by: abrmich --- Code/Legacy/CryCommon/crycommon_files.cmake | 2 -- Code/Legacy/CrySystem/System.cpp | 3 --- Code/Legacy/CrySystem/XConsole.cpp | 5 ----- .../FontBuilderWorker/FontBuilderWorker.cpp | 4 ++-- .../Code/Tests/Builders/CopyDependencyBuilderTest.cpp | 2 -- .../LyShine/Code/Include}/LyShine/Bus/UiCursorBus.h | 0 .../LyShine/Code/Include}/LyShine/UiAssetTypes.h | 0 Gems/LyShine/Code/lyshine_static_files.cmake | 2 ++ 8 files changed, 4 insertions(+), 14 deletions(-) rename {Code/Legacy/CryCommon => Gems/LyShine/Code/Include}/LyShine/Bus/UiCursorBus.h (100%) rename {Code/Legacy/CryCommon => Gems/LyShine/Code/Include}/LyShine/UiAssetTypes.h (100%) diff --git a/Code/Legacy/CryCommon/crycommon_files.cmake b/Code/Legacy/CryCommon/crycommon_files.cmake index a4d87c207a..479f0ec879 100644 --- a/Code/Legacy/CryCommon/crycommon_files.cmake +++ b/Code/Legacy/CryCommon/crycommon_files.cmake @@ -100,8 +100,6 @@ set(FILES platform_impl.cpp Win32specific.h Win64specific.h - LyShine/UiAssetTypes.h - LyShine/Bus/UiCursorBus.h Maestro/Bus/EditorSequenceAgentComponentBus.h Maestro/Bus/EditorSequenceBus.h Maestro/Bus/EditorSequenceComponentBus.h diff --git a/Code/Legacy/CrySystem/System.cpp b/Code/Legacy/CrySystem/System.cpp index 7cf066f72e..0439b69efc 100644 --- a/Code/Legacy/CrySystem/System.cpp +++ b/Code/Legacy/CrySystem/System.cpp @@ -134,7 +134,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) #include -#include #include #include @@ -1374,7 +1373,6 @@ bool CSystem::HandleMessage([[maybe_unused]] HWND hWnd, UINT uMsg, WPARAM wParam // Fall through intended case WM_ENTERMENULOOP: { - UiCursorBus::Broadcast(&UiCursorInterface::IncrementVisibleCounter); return true; } case WM_CAPTURECHANGED: @@ -1392,7 +1390,6 @@ bool CSystem::HandleMessage([[maybe_unused]] HWND hWnd, UINT uMsg, WPARAM wParam // Fall through intended case WM_EXITMENULOOP: { - UiCursorBus::Broadcast(&UiCursorInterface::DecrementVisibleCounter); return (uMsg != WM_CAPTURECHANGED); } case WM_SYSKEYUP: diff --git a/Code/Legacy/CrySystem/XConsole.cpp b/Code/Legacy/CrySystem/XConsole.cpp index df82e34abe..e74b1e7c56 100644 --- a/Code/Legacy/CrySystem/XConsole.cpp +++ b/Code/Legacy/CrySystem/XConsole.cpp @@ -29,7 +29,6 @@ #include #include -#include //#define DEFENCE_CVAR_HASH_LOGGING // s should point to a buffer at least 65 chars long @@ -749,8 +748,6 @@ void CXConsole::ShowConsole(bool show, const int iRequestScrollMax) if (show && !m_bConsoleActive) { - UiCursorBus::Broadcast(&UiCursorBus::Events::IncrementVisibleCounter); - AzFramework::InputSystemCursorRequestBus::EventResult(m_previousSystemCursorState, AzFramework::InputDeviceMouse::Id, &AzFramework::InputSystemCursorRequests::GetSystemCursorState); @@ -760,8 +757,6 @@ void CXConsole::ShowConsole(bool show, const int iRequestScrollMax) } else if (!show && m_bConsoleActive) { - UiCursorBus::Broadcast(&UiCursorBus::Events::DecrementVisibleCounter); - AzFramework::InputSystemCursorRequestBus::Event(AzFramework::InputDeviceMouse::Id, &AzFramework::InputSystemCursorRequests::SetSystemCursorState, m_previousSystemCursorState); diff --git a/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/FontBuilderWorker/FontBuilderWorker.cpp b/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/FontBuilderWorker/FontBuilderWorker.cpp index 3fe399d05d..ccaa1700f9 100644 --- a/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/FontBuilderWorker/FontBuilderWorker.cpp +++ b/Gems/LmbrCentral/Code/Source/Builders/CopyDependencyBuilder/FontBuilderWorker/FontBuilderWorker.cpp @@ -9,7 +9,6 @@ #include "FontBuilderWorker.h" #include -#include #include #include @@ -52,7 +51,8 @@ namespace CopyDependencyBuilder if (fileExtension == "font" || fileExtension == "fontfamily") { - return azrtti_typeid(); + static AZ::Data::AssetType fontAssetType("{57767D37-0EBE-43BE-8F60-AB36D2056EF8}"); // form UiAssetTypes.h in the LyShine gem + return fontAssetType; } return AZ::Data::AssetType::CreateNull(); diff --git a/Gems/LmbrCentral/Code/Tests/Builders/CopyDependencyBuilderTest.cpp b/Gems/LmbrCentral/Code/Tests/Builders/CopyDependencyBuilderTest.cpp index 8b697f35f2..7767e4f239 100644 --- a/Gems/LmbrCentral/Code/Tests/Builders/CopyDependencyBuilderTest.cpp +++ b/Gems/LmbrCentral/Code/Tests/Builders/CopyDependencyBuilderTest.cpp @@ -19,8 +19,6 @@ #include #include -#include - #include #include #include diff --git a/Code/Legacy/CryCommon/LyShine/Bus/UiCursorBus.h b/Gems/LyShine/Code/Include/LyShine/Bus/UiCursorBus.h similarity index 100% rename from Code/Legacy/CryCommon/LyShine/Bus/UiCursorBus.h rename to Gems/LyShine/Code/Include/LyShine/Bus/UiCursorBus.h diff --git a/Code/Legacy/CryCommon/LyShine/UiAssetTypes.h b/Gems/LyShine/Code/Include/LyShine/UiAssetTypes.h similarity index 100% rename from Code/Legacy/CryCommon/LyShine/UiAssetTypes.h rename to Gems/LyShine/Code/Include/LyShine/UiAssetTypes.h diff --git a/Gems/LyShine/Code/lyshine_static_files.cmake b/Gems/LyShine/Code/lyshine_static_files.cmake index 925658e756..c1515f5978 100644 --- a/Gems/LyShine/Code/lyshine_static_files.cmake +++ b/Gems/LyShine/Code/lyshine_static_files.cmake @@ -11,6 +11,7 @@ set(FILES Include/LyShine/IRenderGraph.h Include/LyShine/ISprite.h Include/LyShine/ILyShine.h + Include/LyShine/UiAssetTypes.h Include/LyShine/UiBase.h Include/LyShine/UiLayoutCellBase.h Include/LyShine/UiSerializeHelpers.h @@ -26,6 +27,7 @@ set(FILES Include/LyShine/Bus/UiCanvasManagerBus.h Include/LyShine/Bus/UiCanvasUpdateNotificationBus.h Include/LyShine/Bus/UiCheckboxBus.h + Include/LyShine/Bus/UiCursorBus.h Include/LyShine/Bus/UiDraggableBus.h Include/LyShine/Bus/UiDropdownBus.h Include/LyShine/Bus/UiDropdownOptionBus.h From 66f0f1cf5a03c1196ef029f95cac99f58970d471 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Wed, 19 Jan 2022 17:55:05 -0800 Subject: [PATCH 036/136] Duplicate engine detection and help in Project Manager (#6984) Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../ProjectManager/Source/Application.cpp | 86 ++++++++ .../Tools/ProjectManager/Source/Application.h | 1 + Code/Tools/ProjectManager/Source/EngineInfo.h | 5 +- .../Source/EngineSettingsScreen.cpp | 5 +- .../Source/GemRepo/GemRepoScreen.cpp | 19 +- .../ProjectManager/Source/ProjectUtils.cpp | 19 ++ .../ProjectManager/Source/ProjectUtils.h | 9 + .../ProjectManager/Source/PythonBindings.cpp | 185 ++++++++++-------- .../ProjectManager/Source/PythonBindings.h | 12 +- .../Source/PythonBindingsInterface.h | 24 ++- scripts/o3de/o3de/engine_properties.py | 5 + scripts/o3de/o3de/manifest.py | 108 +++++----- 12 files changed, 324 insertions(+), 154 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/Application.cpp b/Code/Tools/ProjectManager/Source/Application.cpp index 29e0df3c3a..08a812999f 100644 --- a/Code/Tools/ProjectManager/Source/Application.cpp +++ b/Code/Tools/ProjectManager/Source/Application.cpp @@ -21,6 +21,7 @@ #include #include #include +#include namespace O3DE::ProjectManager { @@ -111,6 +112,11 @@ namespace O3DE::ProjectManager } } + if (!RegisterEngine(interactive)) + { + return false; + } + const AZ::CommandLine* commandLine = GetCommandLine(); AZ_Assert(commandLine, "Failed to get command line"); @@ -165,6 +171,86 @@ namespace O3DE::ProjectManager return m_entity != nullptr; } + bool Application::RegisterEngine(bool interactive) + { + // get this engine's info + auto engineInfoOutcome = m_pythonBindings->GetEngineInfo(); + if (!engineInfoOutcome) + { + if (interactive) + { + QMessageBox::critical(nullptr, + QObject::tr("Failed to get engine info"), + QObject::tr("A valid engine.json could not be found or loaded. " + "Please verify a valid engine.json file exists in %1") + .arg(GetEngineRoot())); + } + + AZ_Error("Project Manager", false, "Failed to get engine info"); + return false; + } + + EngineInfo engineInfo = engineInfoOutcome.GetValue(); + if (engineInfo.m_registered) + { + return true; + } + + bool forceRegistration = false; + + // check if an engine with this name is already registered + auto existingEngineResult = m_pythonBindings->GetEngineInfo(engineInfo.m_name); + if (existingEngineResult) + { + if (!interactive) + { + AZ_Error("Project Manager", false, "An engine with the name %s is already registered with the path %s", + engineInfo.m_name.toUtf8().constData(), engineInfo.m_path.toUtf8().constData()); + return false; + } + + // get the updated engine name unless the user wants to cancel + bool okPressed = false; + const EngineInfo& otherEngineInfo = existingEngineResult.GetValue(); + + engineInfo.m_name = QInputDialog::getText(nullptr, + QObject::tr("Engine '%1' already registered").arg(engineInfo.m_name), + QObject::tr("An engine named '%1' is already registered.

" + "Current path
%2

" + "New path
%3

" + "Press 'OK' to force registration, or provide a new engine name below.
" + "Alternatively, press `Cancel` to close the Project Manager and resolve the issue manually.") + .arg(engineInfo.m_name, otherEngineInfo.m_path, engineInfo.m_path), + QLineEdit::Normal, + engineInfo.m_name, + &okPressed); + + if (!okPressed) + { + // user elected not to change the name or force registration + return false; + } + + forceRegistration = true; + } + + auto registerOutcome = m_pythonBindings->SetEngineInfo(engineInfo, forceRegistration); + if (!registerOutcome) + { + if (interactive) + { + ProjectUtils::DisplayDetailedError(QObject::tr("Failed to register engine"), registerOutcome); + } + + AZ_Error("Project Manager", false, "Failed to register engine %s : %s", + engineInfo.m_path.toUtf8().constData(), registerOutcome.GetError().first.c_str()); + + return false; + } + + return true; + } + void Application::TearDown() { if (m_entity) diff --git a/Code/Tools/ProjectManager/Source/Application.h b/Code/Tools/ProjectManager/Source/Application.h index ad55694b18..8f633b28c4 100644 --- a/Code/Tools/ProjectManager/Source/Application.h +++ b/Code/Tools/ProjectManager/Source/Application.h @@ -34,6 +34,7 @@ namespace O3DE::ProjectManager private: bool InitLog(const char* logName); + bool RegisterEngine(bool interactive); AZStd::unique_ptr m_pythonBindings; QSharedPointer m_app; diff --git a/Code/Tools/ProjectManager/Source/EngineInfo.h b/Code/Tools/ProjectManager/Source/EngineInfo.h index 5fd3faf2ea..c28aede030 100644 --- a/Code/Tools/ProjectManager/Source/EngineInfo.h +++ b/Code/Tools/ProjectManager/Source/EngineInfo.h @@ -25,13 +25,16 @@ namespace O3DE::ProjectManager QString m_name; QString m_thirdPartyPath; - // from o3de_manifest.json QString m_path; + + // from o3de_manifest.json QString m_defaultProjectsFolder; QString m_defaultGemsFolder; QString m_defaultTemplatesFolder; QString m_defaultRestrictedFolder; + bool m_registered = false; + bool IsValid() const; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp index c7df00f423..26f5b8ae11 100644 --- a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -114,10 +115,10 @@ namespace O3DE::ProjectManager engineInfo.m_defaultGemsFolder = m_defaultGems->lineEdit()->text(); engineInfo.m_defaultTemplatesFolder = m_defaultProjectTemplates->lineEdit()->text(); - bool result = PythonBindingsInterface::Get()->SetEngineInfo(engineInfo); + auto result = PythonBindingsInterface::Get()->SetEngineInfo(engineInfo); if (!result) { - QMessageBox::critical(this, tr("Engine Settings"), tr("Failed to save engine settings.")); + ProjectUtils::DisplayDetailedError(tr("Failed to save engine settings"), result, this); } } else diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index f62c30c280..843538d9da 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -92,8 +93,7 @@ namespace O3DE::ProjectManager return; } - AZ::Outcome < void, - AZStd::pair> addGemRepoResult = PythonBindingsInterface::Get()->AddGemRepo(repoUri); + auto addGemRepoResult = PythonBindingsInterface::Get()->AddGemRepo(repoUri); if (addGemRepoResult.IsSuccess()) { Reinit(); @@ -102,20 +102,7 @@ namespace O3DE::ProjectManager else { QString failureMessage = tr("Failed to add gem repo: %1.").arg(repoUri); - if (!addGemRepoResult.GetError().second.empty()) - { - QMessageBox addRepoError; - addRepoError.setIcon(QMessageBox::Critical); - addRepoError.setWindowTitle(failureMessage); - addRepoError.setText(addGemRepoResult.GetError().first.c_str()); - addRepoError.setDetailedText(addGemRepoResult.GetError().second.c_str()); - addRepoError.exec(); - } - else - { - QMessageBox::critical(this, failureMessage, addGemRepoResult.GetError().first.c_str()); - } - + ProjectUtils::DisplayDetailedError(failureMessage, addGemRepoResult, this); AZ_Error("Project Manager", false, failureMessage.toUtf8()); } } diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp index b7748d8aa2..209140a004 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp @@ -659,5 +659,24 @@ namespace O3DE::ProjectManager return AZ::Success(QString(projectBuildPath.c_str())); } + void DisplayDetailedError(const QString& title, const AZ::Outcome>& outcome, QWidget* parent) + { + const AZStd::string& generalError = outcome.GetError().first; + const AZStd::string& detailedError = outcome.GetError().second; + + if (!detailedError.empty()) + { + QMessageBox errorDialog(parent); + errorDialog.setIcon(QMessageBox::Critical); + errorDialog.setWindowTitle(title); + errorDialog.setText(generalError.c_str()); + errorDialog.setDetailedText(detailedError.c_str()); + errorDialog.exec(); + } + else + { + QMessageBox::critical(parent, title, generalError.c_str()); + } + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.h b/Code/Tools/ProjectManager/Source/ProjectUtils.h index 713803c20b..8602ffa692 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.h +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.h @@ -98,5 +98,14 @@ namespace O3DE::ProjectManager */ AZ::IO::FixedMaxPath GetEditorExecutablePath(const AZ::IO::PathView& projectPath); + + /** + * Display a dialog with general and detailed sections for the given AZ::Outcome + * @param title Dialog title + * @param outcome The AZ::Outcome with general and detailed error messages + * @param parent Optional QWidget parent + */ + void DisplayDetailedError(const QString& title, const AZ::Outcome>& outcome, QWidget* parent = nullptr); + } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 12f97e6d2e..00ece7396d 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -312,6 +312,7 @@ namespace O3DE::ProjectManager m_register = pybind11::module::import("o3de.register"); m_manifest = pybind11::module::import("o3de.manifest"); m_engineTemplate = pybind11::module::import("o3de.engine_template"); + m_engineProperties = pybind11::module::import("o3de.engine_properties"); m_enableGemProject = pybind11::module::import("o3de.enable_gem"); m_disableGemProject = pybind11::module::import("o3de.disable_gem"); m_editProjectProperties = pybind11::module::import("o3de.project_properties"); @@ -319,9 +320,6 @@ namespace O3DE::ProjectManager m_repo = pybind11::module::import("o3de.repo"); m_pathlib = pybind11::module::import("pathlib"); - // make sure the engine is registered - RegisterThisEngine(); - m_pythonStarted = !PyErr_Occurred(); return m_pythonStarted; } @@ -346,36 +344,6 @@ namespace O3DE::ProjectManager return !PyErr_Occurred(); } - bool PythonBindings::RegisterThisEngine() - { - bool registrationResult = true; // already registered is considered successful - bool pythonResult = ExecuteWithLock( - [&] - { - // check current engine path against all other registered engines - // to see if we are already registered - auto allEngines = m_manifest.attr("get_engines")(); - if (pybind11::isinstance(allEngines)) - { - for (auto engine : allEngines) - { - AZ::IO::FixedMaxPath enginePath(Py_To_String(engine)); - if (enginePath.Compare(m_enginePath) == 0) - { - return; - } - } - } - - auto result = m_register.attr("register")(QString_To_Py_Path(QString(m_enginePath.c_str()))); - registrationResult = (result.cast() == 0); - }); - - bool finalResult = (registrationResult && pythonResult); - AZ_Assert(finalResult, "Registration of this engine failed!"); - return finalResult; - } - AZ::Outcome PythonBindings::ExecuteWithLockErrorHandling(AZStd::function executionCallback) { if (!Py_IsInitialized()) @@ -407,16 +375,22 @@ namespace O3DE::ProjectManager return ExecuteWithLockErrorHandling(executionCallback).IsSuccess(); } - AZ::Outcome PythonBindings::GetEngineInfo() + EngineInfo PythonBindings::EngineInfoFromPath(pybind11::handle enginePath) { EngineInfo engineInfo; - bool result = ExecuteWithLock([&] { - auto enginePath = m_manifest.attr("get_this_engine_path")(); + try + { + auto engineData = m_manifest.attr("get_engine_json_data")(pybind11::none(), enginePath); + if (pybind11::isinstance(engineData)) + { + engineInfo.m_version = Py_To_String_Optional(engineData, "O3DEVersion", "0.0.0.0"); + engineInfo.m_name = Py_To_String_Optional(engineData, "engine_name", "O3DE"); + engineInfo.m_path = Py_To_String(enginePath); + } auto o3deData = m_manifest.attr("load_o3de_manifest")(); if (pybind11::isinstance(o3deData)) { - engineInfo.m_path = Py_To_String(enginePath); auto defaultGemsFolder = m_manifest.attr("get_o3de_gems_folder")(); engineInfo.m_defaultGemsFolder = Py_To_String_Optional(o3deData, "default_gems_folder", Py_To_String(defaultGemsFolder)); @@ -433,19 +407,59 @@ namespace O3DE::ProjectManager engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData, "default_third_party_folder", Py_To_String(defaultThirdPartyFolder)); } - auto engineData = m_manifest.attr("get_engine_json_data")(pybind11::none(), enginePath); - if (pybind11::isinstance(engineData)) + // check if engine path is registered + auto allEngines = m_manifest.attr("get_engines")(); + if (pybind11::isinstance(allEngines)) { - try + const AZ::IO::FixedMaxPath enginePathFixed(Py_To_String(enginePath)); + for (auto engine : allEngines) { - engineInfo.m_version = Py_To_String_Optional(engineData, "O3DEVersion", "0.0.0.0"); - engineInfo.m_name = Py_To_String_Optional(engineData, "engine_name", "O3DE"); - } - catch ([[maybe_unused]] const std::exception& e) - { - AZ_Warning("PythonBindings", false, "Failed to get EngineInfo from %s", Py_To_String(enginePath)); + AZ::IO::FixedMaxPath otherEnginePath(Py_To_String(engine)); + if (otherEnginePath.Compare(enginePathFixed) == 0) + { + engineInfo.m_registered = true; + break; + } } } + } + catch ([[maybe_unused]] const std::exception& e) + { + AZ_Warning("PythonBindings", false, "Failed to get EngineInfo from %s", Py_To_String(enginePath)); + } + return engineInfo; + } + + AZ::Outcome PythonBindings::GetEngineInfo() + { + EngineInfo engineInfo; + + bool result = ExecuteWithLock([&] { + auto enginePath = m_manifest.attr("get_this_engine_path")(); + engineInfo = EngineInfoFromPath(enginePath); + }); + + if (!result || !engineInfo.IsValid()) + { + return AZ::Failure(); + } + else + { + return AZ::Success(AZStd::move(engineInfo)); + } + } + + AZ::Outcome PythonBindings::GetEngineInfo(const QString& engineName) + { + EngineInfo engineInfo; + bool result = ExecuteWithLock([&] { + auto enginePathResult = m_manifest.attr("get_registered")(QString_To_Py_String(engineName)); + + // if a valid registered object is not found None is returned + if (!pybind11::isinstance(enginePathResult)) + { + engineInfo = EngineInfoFromPath(enginePathResult); + } }); if (!result || !engineInfo.IsValid()) @@ -458,10 +472,32 @@ namespace O3DE::ProjectManager } } - bool PythonBindings::SetEngineInfo(const EngineInfo& engineInfo) + IPythonBindings::DetailedOutcome PythonBindings::SetEngineInfo(const EngineInfo& engineInfo, bool force) { - bool result = ExecuteWithLock([&] { - auto registrationResult = m_register.attr("register")( + bool registrationSuccess = false; + bool pythonSuccess = ExecuteWithLock([&] { + + EngineInfo currentEngine = EngineInfoFromPath(QString_To_Py_Path(engineInfo.m_path)); + + // be kind to source control and avoid needlessly updating engine.json + if (currentEngine.IsValid() && + (currentEngine.m_name.compare(engineInfo.m_name) != 0 || currentEngine.m_version.compare(engineInfo.m_version) != 0)) + { + auto enginePropsResult = m_engineProperties.attr("edit_engine_props")( + QString_To_Py_Path(engineInfo.m_path), + pybind11::none(), // existing engine_name + QString_To_Py_String(engineInfo.m_name), + QString_To_Py_String(engineInfo.m_version) + ); + + if (enginePropsResult.cast() != 0) + { + // do not proceed with registration + return; + } + } + + auto result = m_register.attr("register")( QString_To_Py_Path(engineInfo.m_path), pybind11::none(), // project_path pybind11::none(), // gem_path @@ -474,16 +510,22 @@ namespace O3DE::ProjectManager QString_To_Py_Path(engineInfo.m_defaultGemsFolder), QString_To_Py_Path(engineInfo.m_defaultTemplatesFolder), pybind11::none(), // default_restricted_folder - QString_To_Py_Path(engineInfo.m_thirdPartyPath) - ); + QString_To_Py_Path(engineInfo.m_thirdPartyPath), + pybind11::none(), // external_subdir_engine_path + pybind11::none(), // external_subdir_project_path + false, // remove + force + ); - if (registrationResult.cast() != 0) - { - result = false; - } + registrationSuccess = result.cast() == 0; }); - return result; + if (pythonSuccess && registrationSuccess) + { + return AZ::Success(); + } + + return AZ::Failure(GetErrorPair()); } AZ::Outcome PythonBindings::GetGemInfo(const QString& path, const QString& projectPath) @@ -1064,7 +1106,7 @@ namespace O3DE::ProjectManager return result && refreshResult; } - AZ::Outcome> PythonBindings::AddGemRepo(const QString& repoUri) + IPythonBindings::DetailedOutcome PythonBindings::AddGemRepo(const QString& repoUri) { bool registrationResult = false; bool result = ExecuteWithLock( @@ -1080,7 +1122,7 @@ namespace O3DE::ProjectManager if (!result || !registrationResult) { - return AZ::Failure>(GetSimpleDetailedErrorPair()); + return AZ::Failure(GetErrorPair()); } return AZ::Success(); @@ -1170,13 +1212,10 @@ namespace O3DE::ProjectManager return gemRepoInfo; } -//#define MOCK_GEM_REPO_INFO true - AZ::Outcome, AZStd::string> PythonBindings::GetAllGemRepoInfos() { QVector gemRepos; -#ifndef MOCK_GEM_REPO_INFO auto result = ExecuteWithLockErrorHandling( [&] { @@ -1189,18 +1228,6 @@ namespace O3DE::ProjectManager { return AZ::Failure(result.GetError().c_str()); } -#else - GemRepoInfo mockJohnRepo("JohnCreates", "John Smith", QDateTime(QDate(2021, 8, 31), QTime(11, 57)), true); - mockJohnRepo.m_summary = "John's Summary. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sollicitudin dapibus urna"; - mockJohnRepo.m_repoUri = "https://github.com/o3de/o3de"; - mockJohnRepo.m_additionalInfo = "John's additional info. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sollicitu."; - gemRepos.push_back(mockJohnRepo); - - GemRepoInfo mockJaneRepo("JanesGems", "Jane Doe", QDateTime(QDate(2021, 9, 10), QTime(18, 23)), false); - mockJaneRepo.m_summary = "Jane's Summary."; - mockJaneRepo.m_repoUri = "https://github.com/o3de/o3de.org"; - gemRepos.push_back(mockJaneRepo); -#endif // MOCK_GEM_REPO_INFO std::sort(gemRepos.begin(), gemRepos.end()); return AZ::Success(AZStd::move(gemRepos)); @@ -1261,7 +1288,7 @@ namespace O3DE::ProjectManager return AZ::Success(AZStd::move(gemInfos)); } - AZ::Outcome> PythonBindings::DownloadGem( + IPythonBindings::DetailedOutcome PythonBindings::DownloadGem( const QString& gemName, std::function gemProgressCallback, bool force) { // This process is currently limited to download a single gem at a time. @@ -1290,12 +1317,12 @@ namespace O3DE::ProjectManager if (!result.IsSuccess()) { - AZStd::pair pythonRunError(result.GetError(), result.GetError()); - return AZ::Failure>(AZStd::move(pythonRunError)); + IPythonBindings::ErrorPair pythonRunError(result.GetError(), result.GetError()); + return AZ::Failure(AZStd::move(pythonRunError)); } else if (!downloadSucceeded) { - return AZ::Failure>(GetSimpleDetailedErrorPair()); + return AZ::Failure(GetErrorPair()); } return AZ::Success(); @@ -1322,13 +1349,13 @@ namespace O3DE::ProjectManager return result && updateAvaliableResult; } - AZStd::pair PythonBindings::GetSimpleDetailedErrorPair() + IPythonBindings::ErrorPair PythonBindings::GetErrorPair() { AZStd::string detailedString = m_pythonErrorStrings.size() == 1 ? "" : AZStd::accumulate(m_pythonErrorStrings.begin(), m_pythonErrorStrings.end(), AZStd::string("")); - return AZStd::pair(m_pythonErrorStrings.front(), detailedString); + return IPythonBindings::ErrorPair(m_pythonErrorStrings.front(), detailedString); } void PythonBindings::AddErrorString(AZStd::string errorString) diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index 48841b6565..e2a8109128 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -35,7 +35,8 @@ namespace O3DE::ProjectManager // Engine AZ::Outcome GetEngineInfo() override; - bool SetEngineInfo(const EngineInfo& engineInfo) override; + AZ::Outcome GetEngineInfo(const QString& engineName) override; + DetailedOutcome SetEngineInfo(const EngineInfo& engineInfo, bool force = false) override; // Gem AZ::Outcome GetGemInfo(const QString& path, const QString& projectPath = {}) override; @@ -62,12 +63,12 @@ namespace O3DE::ProjectManager // Gem Repos AZ::Outcome RefreshGemRepo(const QString& repoUri) override; bool RefreshAllGemRepos() override; - AZ::Outcome> AddGemRepo(const QString& repoUri) override; + DetailedOutcome AddGemRepo(const QString& repoUri) override; bool RemoveGemRepo(const QString& repoUri) override; AZ::Outcome, AZStd::string> GetAllGemRepoInfos() override; AZ::Outcome, AZStd::string> GetGemInfosForRepo(const QString& repoUri) override; AZ::Outcome, AZStd::string> GetGemInfosForAllRepos() override; - AZ::Outcome> DownloadGem( + DetailedOutcome DownloadGem( const QString& gemName, std::function gemProgressCallback, bool force = false) override; void CancelDownload() override; bool IsGemUpdateAvaliable(const QString& gemName, const QString& lastUpdated) override; @@ -80,14 +81,14 @@ namespace O3DE::ProjectManager AZ::Outcome ExecuteWithLockErrorHandling(AZStd::function executionCallback); bool ExecuteWithLock(AZStd::function executionCallback); + EngineInfo EngineInfoFromPath(pybind11::handle enginePath); GemInfo GemInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath); GemRepoInfo GetGemRepoInfo(pybind11::handle repoUri); ProjectInfo ProjectInfoFromPath(pybind11::handle path); ProjectTemplateInfo ProjectTemplateInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath); AZ::Outcome GemRegistration(const QString& gemPath, const QString& projectPath, bool remove = false); - bool RegisterThisEngine(); bool StopPython(); - AZStd::pair GetSimpleDetailedErrorPair(); + IPythonBindings::ErrorPair GetErrorPair(); bool m_pythonStarted = false; @@ -96,6 +97,7 @@ namespace O3DE::ProjectManager AZStd::recursive_mutex m_lock; pybind11::handle m_engineTemplate; + pybind11::handle m_engineProperties; pybind11::handle m_cmake; pybind11::handle m_register; pybind11::handle m_manifest; diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h index c7c8af2ce1..a42ff310c3 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h +++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h @@ -31,6 +31,10 @@ namespace O3DE::ProjectManager IPythonBindings() = default; virtual ~IPythonBindings() = default; + //! First string in pair is general error, second is detailed + using ErrorPair = AZStd::pair; + using DetailedOutcome = AZ::Outcome; + /** * Get whether Python was started or not. All Python functionality will fail if Python * failed to start. @@ -49,17 +53,25 @@ namespace O3DE::ProjectManager // Engine /** - * Get info about the engine + * Get info about the current engine * @return an outcome with EngineInfo on success */ virtual AZ::Outcome GetEngineInfo() = 0; /** - * Set info about the engine - * @param engineInfo an EngineInfo object + * Get info about an engine by name + * @param engineName The name of the engine to get info about + * @return an outcome with EngineInfo on success */ - virtual bool SetEngineInfo(const EngineInfo& engineInfo) = 0; + virtual AZ::Outcome GetEngineInfo(const QString& engineName) = 0; + /** + * Set info about the engine + * @param force True to force registration even if an engine with the same name is already registered + * @param engineInfo an EngineInfo object + * @return a detailed error outcome on failure. + */ + virtual DetailedOutcome SetEngineInfo(const EngineInfo& engineInfo, bool force = false) = 0; // Gems @@ -202,7 +214,7 @@ namespace O3DE::ProjectManager * @param repoUri the absolute filesystem path or url to the gem repo. * @return an outcome with a pair of string error and detailed messages on failure. */ - virtual AZ::Outcome> AddGemRepo(const QString& repoUri) = 0; + virtual DetailedOutcome AddGemRepo(const QString& repoUri) = 0; /** * Unregisters this gem repo with the current engine. @@ -237,7 +249,7 @@ namespace O3DE::ProjectManager * @param force should we forcibly overwrite the old version of the gem. * @return an outcome with a pair of string error and detailed messages on failure. */ - virtual AZ::Outcome> DownloadGem( + virtual DetailedOutcome DownloadGem( const QString& gemName, std::function gemProgressCallback, bool force = false) = 0; /** diff --git a/scripts/o3de/o3de/engine_properties.py b/scripts/o3de/o3de/engine_properties.py index 92930dbb1c..56cb71f258 100644 --- a/scripts/o3de/o3de/engine_properties.py +++ b/scripts/o3de/o3de/engine_properties.py @@ -25,6 +25,11 @@ def edit_engine_props(engine_path: pathlib.Path = None, if not engine_path and not engine_name: logger.error(f'Either a engine path or a engine name must be supplied to lookup engine.json') return 1 + + if not new_name and not new_version: + logger.error('A new engine name or new version, or both must be supplied.') + return 1 + if not engine_path: engine_path = manifest.get_registered(engine_name=engine_name) diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index e46b819a7c..c06a4d12fc 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -599,75 +599,93 @@ def get_registered(engine_name: str = None, engine_path = pathlib.Path(engine).resolve() engine_json = engine_path / 'engine.json' - with engine_json.open('r') as f: - try: - engine_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warning(f'{engine_json} failed to load: {str(e)}') - else: - this_engines_name = engine_json_data['engine_name'] - if this_engines_name == engine_name: - return engine_path + if not pathlib.Path(engine_json).is_file(): + logger.warning(f'{engine_json} does not exist') + else: + with engine_json.open('r') as f: + try: + engine_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{engine_json} failed to load: {str(e)}') + else: + this_engines_name = engine_json_data['engine_name'] + if this_engines_name == engine_name: + return engine_path + engines_path = json_data.get('engines_path', {}) + if engine_name in engines_path: + return pathlib.Path(engines_path[engine_name]).resolve() elif isinstance(project_name, str): projects = get_all_projects() for project_path in projects: project_path = pathlib.Path(project_path).resolve() project_json = project_path / 'project.json' - with project_json.open('r') as f: - try: - project_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warning(f'{project_json} failed to load: {str(e)}') - else: - this_projects_name = project_json_data['project_name'] - if this_projects_name == project_name: - return project_path + if not pathlib.Path(project_json).is_file(): + logger.warning(f'{project_json} does not exist') + else: + with project_json.open('r') as f: + try: + project_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{project_json} failed to load: {str(e)}') + else: + this_projects_name = project_json_data['project_name'] + if this_projects_name == project_name: + return project_path elif isinstance(gem_name, str): gems = get_all_gems(project_path) for gem_path in gems: gem_path = pathlib.Path(gem_path).resolve() gem_json = gem_path / 'gem.json' - with gem_json.open('r') as f: - try: - gem_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warning(f'{gem_json} failed to load: {str(e)}') - else: - this_gems_name = gem_json_data['gem_name'] - if this_gems_name == gem_name: - return gem_path + if not pathlib.Path(gem_json).is_file(): + logger.warning(f'{gem_json} does not exist') + else: + with gem_json.open('r') as f: + try: + gem_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{gem_json} failed to load: {str(e)}') + else: + this_gems_name = gem_json_data['gem_name'] + if this_gems_name == gem_name: + return gem_path elif isinstance(template_name, str): templates = get_all_templates(project_path) for template_path in templates: template_path = pathlib.Path(template_path).resolve() template_json = template_path / 'template.json' - with template_json.open('r') as f: - try: - template_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warning(f'{template_path} failed to load: {str(e)}') - else: - this_templates_name = template_json_data['template_name'] - if this_templates_name == template_name: - return template_path + if not pathlib.Path(template_json).is_file(): + logger.warning(f'{template_json} does not exist') + else: + with template_json.open('r') as f: + try: + template_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{template_path} failed to load: {str(e)}') + else: + this_templates_name = template_json_data['template_name'] + if this_templates_name == template_name: + return template_path elif isinstance(restricted_name, str): restricted = get_all_restricted(project_path) for restricted_path in restricted: restricted_path = pathlib.Path(restricted_path).resolve() restricted_json = restricted_path / 'restricted.json' - with restricted_json.open('r') as f: - try: - restricted_json_data = json.load(f) - except json.JSONDecodeError as e: - logger.warning(f'{restricted_json} failed to load: {str(e)}') - else: - this_restricted_name = restricted_json_data['restricted_name'] - if this_restricted_name == restricted_name: - return restricted_path + if not pathlib.Path(restricted_json).is_file(): + logger.warning(f'{restricted_json} does not exist') + else: + with restricted_json.open('r') as f: + try: + restricted_json_data = json.load(f) + except json.JSONDecodeError as e: + logger.warning(f'{restricted_json} failed to load: {str(e)}') + else: + this_restricted_name = restricted_json_data['restricted_name'] + if this_restricted_name == restricted_name: + return restricted_path elif isinstance(default_folder, str): if default_folder == 'engines': From c27f73c66be8e8b86456f9601bab218c8be6ab31 Mon Sep 17 00:00:00 2001 From: dmcdiarmid-ly <63674186+dmcdiarmid-ly@users.noreply.github.com> Date: Wed, 19 Jan 2022 20:17:15 -0700 Subject: [PATCH 037/136] Added a NumRaysPerProbe DiffuseProbeGrid setting Added supervariants to the precompiled DiffuseProbeGrid shaders for the NumRaysPerProbe values Signed-off-by: dmcdiarmid-ly <63674186+dmcdiarmid-ly@users.noreply.github.com> --- ...seProbeGridBlendDistance.precompiledshader | 126 ++++++++++++++++++ ...ProbeGridBlendIrradiance.precompiledshader | 126 ++++++++++++++++++ ...eProbeGridClassification.precompiledshader | 126 ++++++++++++++++++ ...numraysperprobe1008_dx12_0.azshadervariant | Bin 0 -> 8338 bytes ...numraysperprobe1008_null_0.azshadervariant | Bin 0 -> 486 bytes ...mraysperprobe1008_vulkan_0.azshadervariant | Bin 0 -> 12618 bytes ...-numraysperprobe144_dx12_0.azshadervariant | Bin 0 -> 8306 bytes ...-numraysperprobe144_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe144_vulkan_0.azshadervariant | Bin 0 -> 12618 bytes ...-numraysperprobe288_dx12_0.azshadervariant | Bin 0 -> 8338 bytes ...-numraysperprobe288_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe288_vulkan_0.azshadervariant | Bin 0 -> 12618 bytes ...-numraysperprobe432_dx12_0.azshadervariant | Bin 0 -> 8338 bytes ...-numraysperprobe432_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe432_vulkan_0.azshadervariant | Bin 0 -> 12618 bytes ...-numraysperprobe576_dx12_0.azshadervariant | Bin 0 -> 8338 bytes ...-numraysperprobe576_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe576_vulkan_0.azshadervariant | Bin 0 -> 12618 bytes ...-numraysperprobe720_dx12_0.azshadervariant | Bin 0 -> 8338 bytes ...-numraysperprobe720_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe720_vulkan_0.azshadervariant | Bin 0 -> 12618 bytes ...-numraysperprobe864_dx12_0.azshadervariant | Bin 0 -> 8338 bytes ...-numraysperprobe864_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe864_vulkan_0.azshadervariant | Bin 0 -> 12618 bytes .../diffuseprobegridblenddistance.azshader | Bin 79451 -> 626455 bytes ...begridblenddistance_dx12_0.azshadervariant | Bin 8338 -> 8338 bytes ...begridblenddistance_null_0.azshadervariant | Bin 486 -> 486 bytes ...gridblenddistance_vulkan_0.azshadervariant | Bin 12618 -> 12618 bytes ...numraysperprobe1008_dx12_0.azshadervariant | Bin 0 -> 9310 bytes ...numraysperprobe1008_null_0.azshadervariant | Bin 0 -> 486 bytes ...mraysperprobe1008_vulkan_0.azshadervariant | Bin 0 -> 15030 bytes ...-numraysperprobe144_dx12_0.azshadervariant | Bin 0 -> 9314 bytes ...-numraysperprobe144_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe144_vulkan_0.azshadervariant | Bin 0 -> 15030 bytes ...-numraysperprobe288_dx12_0.azshadervariant | Bin 0 -> 9314 bytes ...-numraysperprobe288_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe288_vulkan_0.azshadervariant | Bin 0 -> 15030 bytes ...-numraysperprobe432_dx12_0.azshadervariant | Bin 0 -> 9310 bytes ...-numraysperprobe432_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe432_vulkan_0.azshadervariant | Bin 0 -> 15030 bytes ...-numraysperprobe576_dx12_0.azshadervariant | Bin 0 -> 9314 bytes ...-numraysperprobe576_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe576_vulkan_0.azshadervariant | Bin 0 -> 15030 bytes ...-numraysperprobe720_dx12_0.azshadervariant | Bin 0 -> 9310 bytes ...-numraysperprobe720_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe720_vulkan_0.azshadervariant | Bin 0 -> 15030 bytes ...-numraysperprobe864_dx12_0.azshadervariant | Bin 0 -> 9310 bytes ...-numraysperprobe864_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe864_vulkan_0.azshadervariant | Bin 0 -> 15030 bytes .../diffuseprobegridblendirradiance.azshader | Bin 79495 -> 626793 bytes ...gridblendirradiance_dx12_0.azshadervariant | Bin 9314 -> 9314 bytes ...gridblendirradiance_null_0.azshadervariant | Bin 486 -> 486 bytes ...idblendirradiance_vulkan_0.azshadervariant | Bin 15030 -> 15030 bytes ...iffuseprobegridborderupdatecolumn.azshader | Bin 27583 -> 27583 bytes ...dborderupdatecolumn_dx12_0.azshadervariant | Bin 4522 -> 4522 bytes ...dborderupdatecolumn_null_0.azshadervariant | Bin 486 -> 486 bytes ...orderupdatecolumn_vulkan_0.azshadervariant | Bin 2701 -> 2701 bytes .../diffuseprobegridborderupdaterow.azshader | Bin 27580 -> 27580 bytes ...gridborderupdaterow_dx12_0.azshadervariant | Bin 4338 -> 4338 bytes ...gridborderupdaterow_null_0.azshadervariant | Bin 486 -> 486 bytes ...idborderupdaterow_vulkan_0.azshadervariant | Bin 2222 -> 2222 bytes ...numraysperprobe1008_dx12_0.azshadervariant | Bin 0 -> 6994 bytes ...numraysperprobe1008_null_0.azshadervariant | Bin 0 -> 486 bytes ...mraysperprobe1008_vulkan_0.azshadervariant | Bin 0 -> 10274 bytes ...-numraysperprobe144_dx12_0.azshadervariant | Bin 0 -> 6994 bytes ...-numraysperprobe144_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe144_vulkan_0.azshadervariant | Bin 0 -> 10274 bytes ...-numraysperprobe288_dx12_0.azshadervariant | Bin 0 -> 6994 bytes ...-numraysperprobe288_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe288_vulkan_0.azshadervariant | Bin 0 -> 10274 bytes ...-numraysperprobe432_dx12_0.azshadervariant | Bin 0 -> 6994 bytes ...-numraysperprobe432_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe432_vulkan_0.azshadervariant | Bin 0 -> 10274 bytes ...-numraysperprobe576_dx12_0.azshadervariant | Bin 0 -> 6994 bytes ...-numraysperprobe576_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe576_vulkan_0.azshadervariant | Bin 0 -> 10274 bytes ...-numraysperprobe720_dx12_0.azshadervariant | Bin 0 -> 6994 bytes ...-numraysperprobe720_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe720_vulkan_0.azshadervariant | Bin 0 -> 10274 bytes ...-numraysperprobe864_dx12_0.azshadervariant | Bin 0 -> 6994 bytes ...-numraysperprobe864_null_0.azshadervariant | Bin 0 -> 486 bytes ...umraysperprobe864_vulkan_0.azshadervariant | Bin 0 -> 10274 bytes .../diffuseprobegridclassification.azshader | Bin 76956 -> 606488 bytes ...egridclassification_dx12_0.azshadervariant | Bin 6994 -> 6994 bytes ...egridclassification_null_0.azshadervariant | Bin 486 -> 486 bytes ...ridclassification_vulkan_0.azshadervariant | Bin 10274 -> 10274 bytes .../diffuseprobegridraytracing.azshader | Bin 141617 -> 141617 bytes ...probegridraytracing_dx12_0.azshadervariant | Bin 31886 -> 31886 bytes ...probegridraytracing_null_0.azshadervariant | Bin 486 -> 486 bytes ...obegridraytracing_vulkan_0.azshadervariant | Bin 36188 -> 36188 bytes ...fuseprobegridraytracingclosesthit.azshader | Bin 141627 -> 141627 bytes ...aytracingclosesthit_dx12_0.azshadervariant | Bin 13174 -> 13174 bytes ...aytracingclosesthit_null_0.azshadervariant | Bin 486 -> 486 bytes ...tracingclosesthit_vulkan_0.azshadervariant | Bin 5364 -> 5364 bytes .../diffuseprobegridraytracingmiss.azshader | Bin 141621 -> 141621 bytes ...egridraytracingmiss_dx12_0.azshadervariant | Bin 13314 -> 13314 bytes ...egridraytracingmiss_null_0.azshadervariant | Bin 486 -> 486 bytes ...ridraytracingmiss_vulkan_0.azshadervariant | Bin 6396 -> 6396 bytes .../diffuseprobegridrelocation.azshader | Bin 79904 -> 79904 bytes ...probegridrelocation_dx12_0.azshadervariant | Bin 7994 -> 7994 bytes ...probegridrelocation_null_0.azshadervariant | Bin 486 -> 486 bytes ...obegridrelocation_vulkan_0.azshadervariant | Bin 11362 -> 11362 bytes .../diffuseprobegridrender.azshader | Bin 219075 -> 219075 bytes ...fuseprobegridrender_dx12_0.azshadervariant | Bin 30575 -> 30575 bytes ...fuseprobegridrender_null_0.azshadervariant | Bin 589 -> 589 bytes ...seprobegridrender_vulkan_0.azshadervariant | Bin 24081 -> 24081 bytes ...iffuseProbeGridFeatureProcessorInterface.h | 37 +++++ .../DiffuseProbeGrid.cpp | 10 +- .../DiffuseProbeGrid.h | 8 +- .../DiffuseProbeGridBlendDistancePass.cpp | 54 ++++---- .../DiffuseProbeGridBlendDistancePass.h | 16 ++- .../DiffuseProbeGridBlendIrradiancePass.cpp | 54 ++++---- .../DiffuseProbeGridBlendIrradiancePass.h | 16 ++- .../DiffuseProbeGridClassificationPass.cpp | 54 ++++---- .../DiffuseProbeGridClassificationPass.h | 14 +- .../DiffuseProbeGridFeatureProcessor.cpp | 6 + .../DiffuseProbeGridFeatureProcessor.h | 1 + .../DiffuseProbeGridRayTracingPass.cpp | 2 +- .../Code/Include/Atom/RPI.Public/RPIUtils.h | 6 +- .../RPI/Code/Source/RPI.Public/RPIUtils.cpp | 12 +- .../DiffuseProbeGridComponentConstants.h | 1 + .../DiffuseProbeGridComponentController.cpp | 15 ++- .../DiffuseProbeGridComponentController.h | 2 + .../EditorDiffuseProbeGridComponent.cpp | 23 ++++ .../EditorDiffuseProbeGridComponent.h | 3 + 125 files changed, 613 insertions(+), 99 deletions(-) create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe1008_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe1008_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe1008_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe144_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe144_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe144_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe288_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe288_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe288_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe432_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe432_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe432_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe576_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe576_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe576_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe720_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe720_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe720_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe864_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe864_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe864_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe1008_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe1008_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe1008_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe144_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe144_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe144_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe288_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe288_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe288_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe432_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe432_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe432_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe576_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe576_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe576_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe720_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe720_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe720_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe864_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe864_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe864_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe1008_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe1008_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe1008_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe144_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe144_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe144_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe288_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe288_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe288_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe432_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe432_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe432_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe576_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe576_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe576_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe720_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe720_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe720_vulkan_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe864_dx12_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe864_null_0.azshadervariant create mode 100644 Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe864_vulkan_0.azshadervariant diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistance.precompiledshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistance.precompiledshader index 81d6bde5f0..98c327665e 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistance.precompiledshader +++ b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistance.precompiledshader @@ -29,6 +29,132 @@ "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance_null_0.azshadervariant" } ] + }, + { + "Name": "NumRaysPerProbe144", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe144_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe144_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe144_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe288", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe288_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe288_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe288_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe432", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe432_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe432_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe432_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe576", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe576_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe576_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe576_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe720", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe720_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe720_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe720_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe864", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe864_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe864_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe864_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe1008", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe1008_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe1008_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridblenddistance-numraysperprobe1008_null_0.azshadervariant" + } + ] } ] } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiance.precompiledshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiance.precompiledshader index 9fa8e27461..c4d2dac642 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiance.precompiledshader +++ b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiance.precompiledshader @@ -29,6 +29,132 @@ "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance_null_0.azshadervariant" } ] + }, + { + "Name": "NumRaysPerProbe144", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe144_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe144_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe144_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe288", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe288_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe288_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe288_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe432", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe432_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe432_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe432_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe576", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe576_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe576_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe576_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe720", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe720_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe720_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe720_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe864", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe864_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe864_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe864_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe1008", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe1008_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe1008_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridblendirradiance-numraysperprobe1008_null_0.azshadervariant" + } + ] } ] } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridClassification.precompiledshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridClassification.precompiledshader index 66671fd7bc..5a34cc5b15 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridClassification.precompiledshader +++ b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/DiffuseProbeGridClassification.precompiledshader @@ -29,6 +29,132 @@ "RootShaderVariantAssetFileName": "diffuseprobegridclassification_null_0.azshadervariant" } ] + }, + { + "Name": "NumRaysPerProbe144", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe144_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe144_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe144_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe288", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe288_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe288_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe288_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe432", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe432_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe432_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe432_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe576", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe576_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe576_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe576_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe720", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe720_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe720_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe720_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe864", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe864_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe864_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe864_null_0.azshadervariant" + } + ] + }, + { + "Name": "NumRaysPerProbe1008", + "RootShaderVariantAssets": + [ + { + "APIName": "dx12", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe1008_dx12_0.azshadervariant" + }, + { + "APIName": "vulkan", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe1008_vulkan_0.azshadervariant" + }, + { + "APIName": "null", + "RootShaderVariantAssetFileName": "diffuseprobegridclassification-numraysperprobe1008_null_0.azshadervariant" + } + ] } ] } diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe1008_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe1008_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..a66f166a0b39ae1bdf4bb4f050550388cd6394a4 GIT binary patch literal 8338 zcmeHMc~n!^x<5%yMlv!62yntABGp5{0D_nRLQs^Ts5tZ*Konb`!Kt9sW?(i-Kt&YW z22qQxwLvKrYi$M!5l~aL8kKrMBelH_h_=OE+xzwj=ySby*L!Qd_x^Zqt+!Xs$)3Jp z|GsbUZ+{5{K@g!DmvPSKCbWr}+EKq_|JbtnjOA*>vYEKg=e#Fy6DEY#JZmijw&T4ZUh_S0ii`x-nw?5i*Bk9;)nW{p!9dxGG#cj^1@n9=`y z8npZ`cOxF?`l{)l+Y|d63YH(2q-Hw<(LY^I^sq-<>ItW=ywlm=`q7K@xn&Zu=r1v! zT>kh@L*43>=1(_$nqD$>3H0CYwP0*<-Y4z}8~f({?aapSuTQ_ba_$6(*KN>u^IX&B zd~83tCL`+ip3-!Wto_%Pmqw&qNVjxxa-ZJO@1I49v2a7hE-?Yns;N;op8gXs31CHD zW((8!1GlPZG*i^bEk(C)`7&iICi=5KmcL#6?h?;^i_VJc>{D}n^OLd?5^FDawDsOy zL~raC_?jzOY8(JJ-xq>N;5!;T67XbUec*Y3wV4pKI5`!ifI8%OK~U=Al<>)_qbvR2 zw55xeqGe!uAV%{~%0ECMzSa+eI%aD8YkgQ1)9Ll{vW@ACJullB9rj>+UY5m~;>=72 z1m!?PXbHe6DJwM%4~Q^1aiBjT(QunjhoCet=A=R#^e$kGtPH3ZTi{d@TM*NLE2jq$ zDW1OYjvNJdE4a*s}d00_oSS0tcueLx!qWW1ra0wTR;O;f?QOx1SE}8 zNyXuy8U%u5pikgmO-0sJz%BuY%fahzd5hN7IZdN+D(_BXTa0uAipLEkk?tCp!zk;q?~t$c1@I=EG>8rG5 zMXj}ao678+oMK*YM)gxGGoj9F`uir|gt4xjp-XedcHBw^J|yB_O^nU|Ab?Wa;$tiB zuruKSjso*97uOAjs!g&gVSZI3g%czj}(qk2T!a= z_f$mj6f8=Db#$mn0Ll6wMJf{tW`C$wQLBx%CwWR9bx6zn}E zz|M=1rcK7XB+caJI&F+4v`^dJJb&9p!v5keoVdj)ws~89Xig~YK z&cDHiUCLVzAiQg&Y$TY{`-K>#({eYuloM{D2sK>HeWCEkv<(jK8N9LVmdC-t=B)jh zS-yK$*|KiHEsUd7Q+*+uzRsKzrpcx!U5RAPXw!FfP3=1MdFPDiuBdjwp^lg{=$Gv$ z8U6aC9+bV{O58!6X=LQ6{o=Ws=Z5UJyZfq5_f5jEZh>dFD00Em0xnW>0Es+gpobO| z70r9};O%)o=ik3jxNG{r&V_9k2acx|spR?IZ1WjNcPgP!MiW9gjEbX$qw5=VE-RB{a%{7(H2%b;Lc4ClYD*&Fly z7pWEZE-YX(1vXjW_R&9Z+)-S(1M82^bOy$Bp(i^4;DS#CX9b;IR8t1YTNCISp8*l# zb&j=;WL{6+BTVra5iU($Qn{>02qX>2)b(1^GMdalE^`<~J2rB^&)zq3c?9@`X93!< zcwCC3^A^fCypxl+AiHEyc4^Z3jhnKIa`V927(#AMXxXO_iRm|?NK{uRDs1V{1Nrqp z{$aQHWe}l?;c%ZND{g!sU11x9hox!&nA7Soh0;vJAklp<= z=GKJW)0z{vwoG2F=N1;ayR}&M6V6x&&tcIvg@UhZnyQv(8J8N^wp0So$xNqKU zURl4giM!JC20W|-Sl?m(HCAC1F&yq!{YF92^b28yVVda=FMMWsBTe&}1~}tY0C-JR zy01ZoIP?+D4F0XBN7%j8Js4>70BB=1FJsBj0;^tFLWt3;8fx|NaQ=tnX$>KqVWfY9rQ2n{yrXrcsKnaZZ^-tE-?_d~JG zZ~xu7zZF;+;guMsq%E8t_ISsmf)fvS>@3&?e8-MswWBdz9fBDDoDINJ^Yg&5mdMI) zYX7?8JFtOv&6d@V2ve|~Hm*oI;Qa$|$@>KVO?f4&3*O0IlXkyv^xVk(+xEV!t4F#p z0_IzU&CVh9&Y|tjg!vui^UuO*-Q{Tm@PbkCf>Gsy!6Y}K@GIfI$diJoGgHOV3i_pQ zPoxzAcnjx=BKhWx?M}I;z>)0C-E0|MHDWbc`s@d8Tl#EA;Z#pSoJZHmt}kbGwV&*o zs$5z_zf>`ubt24i;o;8dn1u?9YIUrCNUP|Vj(~%3I_u{*F6;#7qty9Lz^mu>&x2sQ zjvR%fa9AwJ05K|pqTqE8^VYiJW>+Uhmzy;S3UX-)d1F&CeFS1XWHX;Bm=W{@Uz5@2 zVhe9AN_0$9dk+w1TM}n$2(t%DG@In)Z4`2;q)IL)Z;9rfeUqf?Y+55%7TTARSrh z7a8|a`n@0D`McA;Z@$gTY4RoE*In~V-Fl?)$+I(O!vgT1&1v{L?&vr748c?(0k1U3 zh~wfRGUL*Zi=RKg^{46HJH`8(KD=UnRP0GPxcvRVpZ2ckx$?KMlNw6LpORn4n*MAg zGzZ$~6d1224*gqk>!Z{6R`uo~^0j}|A71vBXZq*;{Q`gM?*TXZbAMmSENGBLAZ!Z# zn!$BE^;q|_gT7np`b9%@uL9DiG6sGQAW!S>&)xd_L!h)(_e;vjeZ9}V3D+3jmX){ME8{AC{1;PopU9Q z$w@HE;allW+02U=E7rwLfB&}7Tg9dCdmOjD9lDYf*=_aZ;OKV{q0BC=1B5}D7~vew z^`yB;KS63BcWTzF9ym6JGwktYA^9@KEj=X(Qb&(l3RjvVFdZ@-dJ2INLBVnM5a9$14c1ol8=(=VvoDCd6^ev(ylKBdT;14t|Gvnl+? zZ4+72N4MH?f`Y#}U6=&syW*3Oa#M^-$7SC^EE2ouzn2e2Q+<-TitKXSd7K?xUmKD= z_7&50^|}`Bp@2YK+M9ch{aDjBO@&~Zf};1QsPrDB%dQzF`^SpF_WCEMrdeWkM&d36 zwu8*jg?6)lk*L9D8NcCXKbU+#vG!)$A;jPH^s|c`g~`=`;L-n8`4#NQuVhSUgh}=t z1F_&`LG7uESILpgatZ?3(L^z5r{M9T$p*-OVAwF(0J#>8;`oID>!^(Lcs-#KO#JqM zjc~^bL=&b54b=YRUsEQT#f2n#B^I^w3COF77VKvY2upxLKIQs)K9vGdrYikI%5%85 zkeUQu2-7PC3Yji4h+x$^DC7g2F58jzKv=BH0rdaHya%@LM-Zzc?~!zfxsJRCPP*yH zdqhX6310bdFeO*MfX#kOt&j6=tXSWehwyrp!Z5;>FtaFn7ojkVa&&pMQqCjaM3XK@ ziWTYtl_Jwyd*rRgJiUTp{6YzZ(3=pR3EXq^1-B{{w@~_ul-8+X7Yg&=QnAT47}qYO zXR}FWQVxy)5*62*9*s|Z6#e_KylFRj>l;lzcYoyWl~dLBCyyL?O}gU!zD z1>nZ;z+`*SXFm!j`v~Ip#dM%21zks@P6|4wiWgPVFU>ts@aVIJMaK(@<|&r=n>V)f ztEV|_*to6LsTJgt&CSl6up3O@;C=g;?)K%u`{3e{3(VlK$N%3w{^#x<2>??fO5DCE zG<^2QRX^Mnu%p$aW+N?2ZAkaJ=yGLjtm(t;Unvcqk@UE`{TXkHn%P?lQy~0Wp()3yYafI1uDBXBniDsFvG9R*146 zu#=>k5Dl@05;iqSIu~+t&A{Qz45NT#X5gpk#8l%&L777TXgJ%Xx};G34T`71Q5SsqUSqLivEo?4AH&@qA6yEIR2Gre=)Pwz-px` z9iqRP5G^O+xC4Ta`Do4%X1~Sr_n1RZi@lF0PU}bjpVVFVvaZ3xn!pe$ObH#3wH z45O#S01_EsH1t_gtUe)C6AT;kRY(?6t@|C(j}er~bT0@tB4=v0v=O(m@mqD|t-7l3 z%4Mgamf=b$*dS{hep~ekaj)J9nzm9#{R%?8dvNi=T0&VGN`BrXXO4v{c|*AgF@|;B z21vxFpVS+u#sPlyrD`Q+#x=PuE^4Z{tTF(<2|2f%^dmLRr*fR0g8Yn@U12=1GL7;i z6Vn{^!w~Z^J1gAM>ne^v1z!>oMbWDwq&PP7x`rDD+{rlN{stf3!48{rZ{yrl*qsf8 zYwH+wWoxNAC9Qnvhc-*7uPq^sA_6{RFZUb}N{B6CbA7z8fIYVo>UE2riNLE@PWsFr?S(cvW&8MSqj;i;V@NBNOS~sIBu}stm8GmjPSv!J(V<94_#uNEPrWt^1@wh{1t^ zfXQ9=r2745l{>+%Gs_dTerwTweW@`F7bV3F;Hzfc5)o0SgFhD#+zeszXpRJ?VNL1|$p={T(P69^J^`xt!Lt;}3-z49xs%qq zeo!lU4;+u!)@PICf`Bo8065FQVGqn^mYEShZ_@K7wxO2-K!8U*!%^V0YEAlI0`n{<|S-9r#Kl}xf_FAk?j^CJ1|$rI1tV>WfSlwZ%G?v;X%=K_l2JD86SSJzQf zz}aTcHSzsi+{c^r*ujPaEP}W2-Da-mxM#TWWxItfdzY(Ngq(^0DOZv{q+FBr>w=A5 oAc9Yptbg|ZGdA|m|5S%c-aHI<}jSt z*Hfs^cq=A3WL0B;cgOy|uZ>c>5@XJ^+(>o4H6gq9z0Zp26IvbFF8^!>nhOLTzV_dv z)HnV+)YIjDeSt|D=Pyoelgh3Mt5<5Cnj|UyB>wzNlXqugJGplXKr|qcmG$|D4G1e^ zh>Uw|{AR(a4xaT-oKH{6iCp91nJ5Ib`sF2O@h8UTj~Q}CKiYPB@%%sjt~DNx4sn*N zE-imFsXyL*_Ue+={uP>`3>1r=02#};E4Flc&VN_MEf)LMCilhvfCS?88w?k{M11U* zKiQNLX#VS1rN4N@%xjUA#_nhRPwW&-{`_deOe+qkzZn@~G|g{*#uAv!AQjjh%21ha R`cngok&Ja&o%6MU`T!nR#rXgL literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe1008_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe1008_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..ad037d61ed839c55427acbad0d479203306a748f GIT binary patch literal 12618 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 E0i-*z!TaHI<}jSt z*Hfs^cq=A3WL0B;cgOy|uZ>c>5@XJ^+(>o4H6gq9z0Zp26IvbFF8^!>nhOLTzV_dv z)HnV+)YIjDeSt|D=Pyoelgh3Mt5<5Cnj|UyB>wzNlXqugJGplXKr|qcmG$|D4G1e^ zh>Uw|{AR(a4xaT-oKH{6iCp91nJ5Ib`sF2O@h8UTj~Q}CKiYPB@%%sjt~DNx4sn*N zE-imFsXyL*_Ue+={uP>`3>1r=02#};E4Flc&VN_MEf)LMCilhvfCS?88w?k{M11U* zKiQNLX#VS1rN4N@%xjUA#_nhRPwW&-{`_deOe+qkzZn@~G|g{*#uAv!AQjjh%21ha R`cngok&Ja&o%6MU`T!nR#rXgL literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe144_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe144_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..3ecbe8fb8d13972a298135f044859ff74bab86ec GIT binary patch literal 12618 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 PpCX-q*7BPUX59Y(c**qV literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe288_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe288_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..c3925d31857fc8a0569df7cbefc7bac250293d8a GIT binary patch literal 8338 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 R`cngok&Ja&o%6MU`T!nR#rXgL literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe288_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe288_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..ec0413a6b7a8199aaaa80b83afafbd16f994533a GIT binary patch literal 12618 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⪙ra^4rb zh;dQJ{m|uXQM3Kg<$J-^5#JmSK$nkk{lSjovvu5oDDv5H2cgSb$Nlg<7;G&0r73p^ zSbiY(i&CxxU4Am$Whr+ky8NMV7o^+(bz~4+)blWOd0TLYr<`YLBFWWv0!VW{qc1Er^-e^>cNm=cXMKmG z%ZG35=?FOEXpj9H2{s39leh)eWfa&oX!ER_v-j7t8tb#SZm_CwT%Ju zNq$eJU+hz9%6G&z35okO7G9fkjia~5_VElq9^4&&=RW}%k8DWmHUX^N7=I<}iS*iS z?w$5Yh`e#d@vJEWJI-g6@Bb6QXVA-s&t$Oiedp*?4%SazAD;&mVEKE}oK6DE?T^i~ zbTZgxKH5$}Q<}`*mxF%!SXLB;Q&-g2b zckm3bxw}T=Ij{H5F@BF22c8e^Oz+8;f3>@jDeg zzW3C@Yl}Tzknx+I`nktv!fOk^`i$Rc8NUX2ZSg&z5$ss&9^687{bDZ`fo*YS&O*0# z_VN3;Ca|#_>;5&<+uT2GixD};iQ^7`A8hRoz&E~Eo}J<1JI^_A;j2A-&jni}$A|BE zsjr-N_c!LYkMCGZz<#%K9mY1Vc0hHdkJ_Kc>PVVdM0j!&_{`y-vl;>5_^3!SYCg>&)9pwJJ5UYea@@vZ>;h3o)i1{`Sb+v z@rXYc=rb<$nMnTuXT^7cazbjqH?`ZFk9)lV+?C!j_aXPEHotc~0QUK&?PsYi-X#yB z$2+G#KJhMj2wvL;*3=LFVX$%J{r>a_y>r;SFWS}RU7tAW@hI4OINtc~>CeIPaXuac zk3r0k?-?h?am$C3n?cb+>2m&{o*$DtfMyXfak`u;@QzB&ZB3<{Np^vd2?^$ zUG*~9vk=dLUxVciA!g+A3c7p=Ts)_KgYJAjCc4kgZU)2Gp^(Hi#q-etdA|Y-=~~( z?EMEQ`f7`JZmjDMaIUM8Rf=7Y{x+XO^Xa|I_Fs|Bk!CbyTmRmjpN}5sv+4a@v^n#(|IYxq=DNXO U9Ppigwoj4HJ!AO|2Qlt{09sP^)&Kwi literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe432_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe432_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..bfebe1ed5625c8bc5183744581d6c5d67a2acb55 GIT binary patch literal 8338 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 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe432_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe432_null_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..77ed6f870a18eb2b6af3df5fbc1e3822381271a1 GIT binary patch literal 486 zcmZQzU|?YGU<}-ML)7esBj1D%@+<$B#qTaHI<}jSt z*Hfs^cq=A3WL0B;cgOy|uZ>c>5@XJ^+(>o4H6gq9z0Zp26IvbFF8^!>nhOLTzV_dv z)HnV+)YIjDeSt|D=Pyoelgh3Mt5<5Cnj|UyB>wzNlXqugJGplXKr|qcmG$|D4G1e^ zh>Uw|{AR(a4xaT-oKH{6iCp91nJ5Ib`sF2O@h8UTj~Q}CKiYPB@%%sjt~DNx4sn*N zE-imFsXyL*_Ue+={uP>`3>1r=02#};E4Flc&VN_MEf)LMCilhvfCS?88w?k{M11U* zKiQNLX#VS1rN4N@%xjUA#_nhRPwW&-{`_deOe+qkzZn@~G|g{*#uAv!AQjjh%21ha R`cngok&Ja&o%6MU`T!nR#rXgL literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe432_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe432_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..7ec21da8d223cb477db7bb1dc7145d6cb32d4b76 GIT binary patch literal 12618 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 TgTC|6_9@bN^H$z)2;=?<46yYe literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe576_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe576_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..f75dc925c1504bba412fca78afbc543edb84d267 GIT binary patch literal 8338 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 R`cngok&Ja&o%6MU`T!nR#rXgL literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe576_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe576_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..b532faae4b4c3b6c491e91716b2f5b6d7654ea5f GIT binary patch literal 12618 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 Soqx7ZkuErU`Avr~?tcKQkM(Q- literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe720_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe720_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..c2b5d1bfafb48d6a0382d089f91deb50a9ac4397 GIT binary patch literal 8338 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 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe720_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe720_null_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..77ed6f870a18eb2b6af3df5fbc1e3822381271a1 GIT binary patch literal 486 zcmZQzU|?YGU<}-ML)7esBj1D%@+<$B#qTaHI<}jSt z*Hfs^cq=A3WL0B;cgOy|uZ>c>5@XJ^+(>o4H6gq9z0Zp26IvbFF8^!>nhOLTzV_dv z)HnV+)YIjDeSt|D=Pyoelgh3Mt5<5Cnj|UyB>wzNlXqugJGplXKr|qcmG$|D4G1e^ zh>Uw|{AR(a4xaT-oKH{6iCp91nJ5Ib`sF2O@h8UTj~Q}CKiYPB@%%sjt~DNx4sn*N zE-imFsXyL*_Ue+={uP>`3>1r=02#};E4Flc&VN_MEf)LMCilhvfCS?88w?k{M11U* zKiQNLX#VS1rN4N@%xjUA#_nhRPwW&-{`_deOe+qkzZn@~G|g{*#uAv!AQjjh%21ha R`cngok&Ja&o%6MU`T!nR#rXgL literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe720_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe720_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..12938b54606d6ed16483a0a6967fd947dd441876 GIT binary patch literal 12618 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 Q|7@QkoqNWL8~QWupFdLetpET3 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe864_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe864_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..5a33ba9798b3727f172ba4597371fb764ab8bde2 GIT binary patch literal 8338 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 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe864_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe864_null_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..77ed6f870a18eb2b6af3df5fbc1e3822381271a1 GIT binary patch literal 486 zcmZQzU|?YGU<}-ML)7esBj1D%@+<$B#qTaHI<}jSt z*Hfs^cq=A3WL0B;cgOy|uZ>c>5@XJ^+(>o4H6gq9z0Zp26IvbFF8^!>nhOLTzV_dv z)HnV+)YIjDeSt|D=Pyoelgh3Mt5<5Cnj|UyB>wzNlXqugJGplXKr|qcmG$|D4G1e^ zh>Uw|{AR(a4xaT-oKH{6iCp91nJ5Ib`sF2O@h8UTj~Q}CKiYPB@%%sjt~DNx4sn*N zE-imFsXyL*_Ue+={uP>`3>1r=02#};E4Flc&VN_MEf)LMCilhvfCS?88w?k{M11U* zKiQNLX#VS1rN4N@%xjUA#_nhRPwW&-{`_deOe+qkzZn@~G|g{*#uAv!AQjjh%21ha R`cngok&Ja&o%6MU`T!nR#rXgL literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe864_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance-numraysperprobe864_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..14f9f51d851deb8ac06c573c8bc7b2694e944add GIT binary patch literal 12618 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 S-}`6#6zRM(R@`_nvX&3Fv; zF|`h7s?OB`8u~(z(P6r-8KWjHvyCh)C@{MLuh}NXMiiKR0I%7m=4RxY{aldIaq`40 zEnGojZe&2d(M*o`!`s4)?6`a`$mEC=;DyYhBEsk?#lV2<=mZ%L4s-3zd$Vj{NqF=B zY-0^*$^)|1)i=lQKElko_CV$HAJ5v$8Mc2=VYC*UoPI$YS8$@HUL5A_(mh%pYVo5H zY912<{!m0swK&ZD7Jurs{(_Afa5Iqt4@)jXO|8V52@WxwxeGOw5@#kOBk_roI1`x& zlmVz|l2|j5LX(K3NUW*g@YJ5XH_Ku2l?#86i#+*Xtm>2h|M-R~c2bLje`4EzImL}< zKuIx85Pvc(p4@xU8PxRrhPYCcY{QX)5@*6B+i+r1D0zlk3oeCCNSfwZL*ZGJh zb6kt#>D#hwK9+<(n;-6bAvk$rme%y|No-Ej+sv5%KoxHX8l$eh9cTm(%w&+zYb}nY zb>|nSeaq6{?)ZV(7OZ(YP_rFO71;jm32!-A)u%hW;rNDZIY{`V7ROB%ZrMXtUlg}b S3}mwwoIc?Mn>H&02mk=|-&5)U diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_dx12_0.azshadervariant index ec72a557113911ff0807d16732437376516ba3b7..c3925d31857fc8a0569df7cbefc7bac250293d8a 100644 GIT binary patch delta 16 XcmbQ_ILUECmjXv!R_A#<2*C!8 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 Jf&Uxg-vB^}Tgw0d literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe1008_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe1008_null_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..c2c98c19dc4be5541d870eac0dc4c879231d54af GIT binary patch literal 486 zcmZQzU|?YGU<}-ML)7esBj1D%@+<$B#qTaHI<}jSt z*Hfs^cq=A3WL0B;cgOy|uZ>c>5@XJ^+(>o4H6gq9z0Zp26IvbFF8^!>nhOLTzV_dv z)HnV+)YIjDeSt|D=Pyoelgh3Mt5<5Cnj|UyB>wzNlXqugJGplXKr|qcmG$|D4G1e^ zh>Uw|{AR(a4xaT-oKH{6iCp91nJ5Ib`sF2O@h8UTj~Q}CKiYPB@%%sjt~DNx4sn*N zE-imFsXyL*_Ue+={uP>`3>1r=02#};E4Flc&VN_MEf)LMCilhvfCS?88w?k{M11U* zKiQNLX#VS1rN4N@%xjUA#_nhRPwW&-{`_deOe+qkzZn@~G|g{*#uAv!AQjjh%21ha R`cngok&Ja&owvAw`T!pO#uNYm literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe1008_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe1008_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..e870a155090cef47037921890149bf31cbfa7533 GIT binary patch literal 15030 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 NhT{)E{WV{V{{dt;;CcW6 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe144_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe144_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..f77e677928db09d4d2cdcc6b82ce773a8edb5bf7 GIT binary patch literal 9314 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 I#6Keb8Q3gf{{R30 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe144_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe144_null_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..c2c98c19dc4be5541d870eac0dc4c879231d54af GIT binary patch literal 486 zcmZQzU|?YGU<}-ML)7esBj1D%@+<$B#qTaHI<}jSt z*Hfs^cq=A3WL0B;cgOy|uZ>c>5@XJ^+(>o4H6gq9z0Zp26IvbFF8^!>nhOLTzV_dv z)HnV+)YIjDeSt|D=Pyoelgh3Mt5<5Cnj|UyB>wzNlXqugJGplXKr|qcmG$|D4G1e^ zh>Uw|{AR(a4xaT-oKH{6iCp91nJ5Ib`sF2O@h8UTj~Q}CKiYPB@%%sjt~DNx4sn*N zE-imFsXyL*_Ue+={uP>`3>1r=02#};E4Flc&VN_MEf)LMCilhvfCS?88w?k{M11U* zKiQNLX#VS1rN4N@%xjUA#_nhRPwW&-{`_deOe+qkzZn@~G|g{*#uAv!AQjjh%21ha R`cngok&Ja&owvAw`T!pO#uNYm literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe144_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe144_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..c12043e8fe681c7e05c7dee8165797600d07cafe GIT binary patch literal 15030 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 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe288_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe288_null_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..c2c98c19dc4be5541d870eac0dc4c879231d54af GIT binary patch literal 486 zcmZQzU|?YGU<}-ML)7esBj1D%@+<$B#qTaHI<}jSt z*Hfs^cq=A3WL0B;cgOy|uZ>c>5@XJ^+(>o4H6gq9z0Zp26IvbFF8^!>nhOLTzV_dv z)HnV+)YIjDeSt|D=Pyoelgh3Mt5<5Cnj|UyB>wzNlXqugJGplXKr|qcmG$|D4G1e^ zh>Uw|{AR(a4xaT-oKH{6iCp91nJ5Ib`sF2O@h8UTj~Q}CKiYPB@%%sjt~DNx4sn*N zE-imFsXyL*_Ue+={uP>`3>1r=02#};E4Flc&VN_MEf)LMCilhvfCS?88w?k{M11U* zKiQNLX#VS1rN4N@%xjUA#_nhRPwW&-{`_deOe+qkzZn@~G|g{*#uAv!AQjjh%21ha R`cngok&Ja&owvAw`T!pO#uNYm literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe288_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe288_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..70bbd8fbb0f4e82f23b0932016cfa56c71c6e7ab GIT binary patch literal 15030 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%0Aw=Z^7OdKeyrzeTOdJA1>;`uw)Is z-Qm{)&NoO~oWYi0h9+lFyRqVPxD~peiTcDly%E^jC^kE&roC*9qK{*J8>V1u1CF<0 z0J?X?v)UG3n|f>XcHp-3@%^|xy4-R&Tg+i&IBkk8<`DJ{@Xlj;(cEN@`Eae}8drV$NG& z)82f}?z`{Fme^dkezC`$!Sc4?x}=20o4+fIm_>lDYEw=>xJ48qs9$@%p~cW&C^?DPYBcC$5{nIuak#qmV@x5$s zu=(5*>t`3=zx#A$9b^M?P!%iO}cAz$qL RqyI#b!*I$mOV|2h{0~&j-ZKCI literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe432_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe432_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..7ed95335cac633ec61abb778c0f182a3e303437c GIT binary patch literal 9310 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 R`cngok&Ja&owvAw`T!pO#uNYm literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe432_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe432_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..a545c832254f62e7e6d91e40b0b6790be9bee3a6 GIT binary patch literal 15030 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 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe576_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe576_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..4ed0fcb4f368749f630aa3a882c0ec624e2f7766 GIT binary patch literal 9314 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 J6Z=QRzX89FVa5Oe literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe576_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe576_null_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..c2c98c19dc4be5541d870eac0dc4c879231d54af GIT binary patch literal 486 zcmZQzU|?YGU<}-ML)7esBj1D%@+<$B#qTaHI<}jSt z*Hfs^cq=A3WL0B;cgOy|uZ>c>5@XJ^+(>o4H6gq9z0Zp26IvbFF8^!>nhOLTzV_dv z)HnV+)YIjDeSt|D=Pyoelgh3Mt5<5Cnj|UyB>wzNlXqugJGplXKr|qcmG$|D4G1e^ zh>Uw|{AR(a4xaT-oKH{6iCp91nJ5Ib`sF2O@h8UTj~Q}CKiYPB@%%sjt~DNx4sn*N zE-imFsXyL*_Ue+={uP>`3>1r=02#};E4Flc&VN_MEf)LMCilhvfCS?88w?k{M11U* zKiQNLX#VS1rN4N@%xjUA#_nhRPwW&-{`_deOe+qkzZn@~G|g{*#uAv!AQjjh%21ha R`cngok&Ja&owvAw`T!pO#uNYm literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe576_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe576_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..9c65b7c6825a9fe37d94e6d08e93535d00ca01eb GIT binary patch literal 15030 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 Gi}61+>)qG@ literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe720_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe720_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..bec463559262dd32eff6bca8a10125439cf6e84a GIT binary patch literal 9310 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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 R`cngok&Ja&owvAw`T!pO#uNYm literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe720_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe720_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..0e33c58e47e955762994355197edfd6e0ed0d2f6 GIT binary patch literal 15030 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 J`MNL0{{Zm1;EezP literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe864_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe864_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..0801a8caa896c3cf6345443a5e26cfb993d4eebd GIT binary patch literal 9310 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 R`cngok&Ja&owvAw`T!pO#uNYm literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe864_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance-numraysperprobe864_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..a573e2511d6729f514dbdbb06c3d05b2c0ae52a8 GIT binary patch literal 15030 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 delta 196 zcmaF4K&|~P%LXMD*4jDU$8T&_X9;3tbIBA=@>IduKZ`= zGc(JXwqN|n_*`)Ef-LRnH@~ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_dx12_0.azshadervariant index 816469ec2d30517153e6ed2b9838254c959f637d..74ce89a020c11e99ed1d19badbd86a070febb2b2 100644 GIT binary patch delta 16 XcmaFl@yKIClnO^(R_85l1_lNIKC}hl delta 16 XcmaFl@yKIClnO`fobKZ{7#J7;LhA<3 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_null_0.azshadervariant index f352a375d0032b1648ccbac3e12313e2527f8a71..c2c98c19dc4be5541d870eac0dc4c879231d54af 100644 GIT binary patch delta 16 XcmaFH{ET_SJw}eYtj=593=9kaJMIO* delta 16 YcmaFH{ET_SJw}e&Io-!^FfcFx06--MtpET3 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_vulkan_0.azshadervariant index 8e4364d56b6791a5d27fb4429e0c97112a8a6a9c..70bbd8fbb0f4e82f23b0932016cfa56c71c6e7ab 100644 GIT binary patch delta 16 Xcmdm1x~+7>IxCL4tj=593=9kaLhuGn delta 16 Ycmdm1x~+7>IxCLaIo-!^FfcFx07oYWIsgCw diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn.azshader index f733a5613775353a67c84b00a4d43d806d9ab42e..c191496dd250e01dc5ba833b78e9bdeead9ba2b0 100644 GIT binary patch delta 176 zcmdmgopJwl#to`0taVwP8+tcuu>>))WjUvoyXH(T)K}g-m*+6+|>$00kCua7d`cdwpvzJG=RusEy#}Fwabw pG}x9ifk#;M8sVjDUXWZsd@) delta 16 YcmZ3byh?e)B0-MYIo)6GFfcFx06UrndH?_b diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_null_0.azshadervariant index a8cf6ac19e10dac397979abeec1a6d8306747ff4..e1a4be7db5aae2b3e71ba3f156454d6ef37615a2 100644 GIT binary patch delta 16 XcmaFH{ET_SJw}eYtj-O+3=9kaJtPJg delta 16 YcmaFH{ET_SJw}e&Io)6GFfcFx06`W8-T(jq diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_vulkan_0.azshadervariant index 6e7324191f5b2c28d9c13d4f7ea093aab6ad8607..fcd71ca437ea652b560f1810ae069ecdd2c9e4d5 100644 GIT binary patch delta 16 XcmeAb?G@e7%EeKa)w!XUfq?-4F*OA` delta 16 XcmeAb?G@e7%EeJTr~Att1_lNIH75oD diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow.azshader index 9e2e426ff43495e9c54687bbd4408d30484c7900..492150e17cfce8c8cbf42849378154219ecf4c1c 100644 GIT binary patch delta 170 zcmdmUopH}~#tlj=taVwPTdr?bX9;3t^9qmja`N3=&-#fC!G6ZNIaX*l6Gzi_xycta zo%U{45DgH9N>8q5Ro*;P<2+0`lz$kah116OO8;>eW)p_Zfl=0in}a&-PKEVJ0 delta 170 zcmdmUopH}~#tlj=thIBxU&n1$X9;3tE6EQGc5>NV&-#fC!G6ZNIaX*l6UV%zkINn0 z*1z4XAQ~VHm7ZMBs=Rro#(9`>DE}}-3upG`H^$pl6gM$!4vexE+#Kwg39|#N@MPdo d*2${^z9AcSGO&SzL&_@8c$HEd6Hr^WAOL*zKI;Gg diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_dx12_0.azshadervariant index 3c65d8d4c95fbc4067198366c4bbd2702157e4bb..cb64cf494543f75daffcaab7293231b4fb66443e 100644 GIT binary patch delta 16 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 S`cngok&Ja&oe$;%^#K4OY{sqt literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe1008_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe1008_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..a2d1bcd5e37b653bfe2dfda4c7f0f0f719d33c11 GIT binary patch literal 10274 zcmbuF33Qaz6~`xpeF-2-*bD=RvM92JO(6*hBp^#j0|@ zNL`gO;mHH71{}yqTmMDJZQn1RxqIIm8!pXEc_3?f-&O;L_gH=O&Ww)Jrrs9V_vG4z z7p5GXURtt!Md2l@p1Seaigvq0(_gywKsfi{`uWR0A9K&f_1ERpef{_~imOpDHtVaY z=k5CUvuoGnzrDGCd4m%TdiJkgvwp|6?k{d=n|@^GE1UX%_R?jm8$I4E>EQdj`pWoo zz5lyeV9JaS`+c(c#Z`?TIFh@6Lv+f$1*1Y|DfP#%<)$C$_sZTr4W=D_WdD{sz8ybe zSwT+rjKSMq+j@Azx|#X6?x@-^eo6OoW{*>#F`n*t8NV+t6yO_E0SY=fxRyBN4d3iX| z%iHjpkaFMrgecyv)kI4@jTnqN3k7^^_X zh$kX*A~CSK9>$sz@v2Z&BrY_W2U~h$t19||zMkhtA1mUE!xiCJRf+nesUjwI^w;w( zUJxpc#O5S*$$a$F)8)n&#i}Z6eCVf#k6TosMph<$8hW|trRhc`5}~q4C{`LS2`>pp zom~UZj=q{*UWCq`w6fY*n`cu{U0D@QgexP|P~Y=!Xu7eXC91(f)YRC>^yA`*icoZT zBy_U=#-^JT319AM=tr`yCZ@B9BbF?P$J99Cbpy#YrkRazfpb;f+<3H1sv5hdW;a|L zIkzenuBm6&0am%w&Ds0nc`LsC0h0POvYc)u+cO zX)`tw8<~j5s<5;5NM}84VRpr(iFhR`TG*TWp%`Um;ZOkrNZ*DXkN(l094Cmnt zcQScfJ)7D;cw6%IvT!drCmlr0xeLtCc5}{oXAuKE^G@C@Ip?hV^~}+8PqC*azn(dI z?kjq75tIEd@ZI|^nllU|9+=;b7+^t>*|8ol9#_Ly6Ig#A#=Qp1_F>ckHpYjs9*gJ#=lrtsw z;!JT*srx)})&WM{-Nf;sZuH&7Q$*m*d$>6^E#%o#ypycY7e}_WULZLrVy(TzsX2+& z4qPai_XM1ry~SA{bujNEPJHI%>?@8vF_`xgPwJBM{%%eT^qFpM_5<9UeqJO!d&L{a zusQJ=%;^bl7CD&H1NxET=JbGb$-KKXoVkG_J3E6UFCCasbCw2ct}&F_hDabT>$6^6 zB$>Nq^NS_d5n(@69DB}$>4!S7b2KN0>4!^Z{Wi~)%w0{|G$>`0$ zNHQ_Nm#H4=FBXB{uN<6#5)o?xrw0?o87E|qZjuO$J|G_#r%%kmnP2MW@MG!;wNDn& z2W+N@rix5AO|t2xJKZi<&t;mUZzcLtHOz2&F|Q`{GezLkfXv#+IZMP^3Kgrjct}L7 zSt5GG`J64{9O2VPyi|l;j!@2dnaKLf8OM*lg`JKbl}l#WIhiAwTHxE=I_65ohxZcm4axV1b({m<-qe~I_a}t9&Ya$lhucx+SdabFuQbg^nk$B|gGZmj4^{TIUm1v}h zy&9&vnd3+AiLpoo_L%GKVuulDoBGyF{BjX^3lV4QD%pZ__Be~^sgZL?&2Y2f43ZmP zY&gf*aK`LxEs;E0#5w6FUM*@UA{TETwFbqPiqP?1kpD*xqlbnqa~SWG-PPriu|>DW z`CcKJyy)!yUMU%TrL(z8@~Ji}gn@Gp`iNgG!Vf&II_c>(BKmTjY?xo`u)*T2G1JqX zTw`0!Z9lGey4~{4ki1faKRD-Zl{kZQhiqg1+i(cD)tdq>XF|7CNC1Z<@I)dUq5rOB4 z7-qXcvc)vpp9%xVhrPFbzDY7M$!|6NOfvrH%>QP|;KbpauqOk=H;U}srAww4UBz#4 zI_!o@-Xt(MKYMJm2-2Kh<)cQQ^T)B^oz61{BDO)+ttE? z;#)=RaVL@a-Q#fc+om}_;5WKh+a-f{7G2}89g@j`&fea8CDSu{eUIwO5Wi0Z&Yiel zoWY#{e?SDr`9vPCZ?n|CQ^X!Yj1&?3f0J@I7T+bp2IBmJJt)GSyJ7eFA%~-*ZtNZw zffK{l_iM?l2c6}3#9`#Hc#ld3?;WH zkxY&LxO+6m2c5-zLNc+@aks5^aK2ZN=SdNT&QZ)?t8 zq2qkmp1|#V9B?+A8SI}IVf&6a`vj&+jpHql1Ga0=gs3@{z-I5WZ!QNJFJa3XYNCB2C>l{5rGjKnKh7~IXG|Z zQ1L&D8j4s)j);6|;(rmL!>+&hUqxm&Trzge#6NO6d$T|G+2uOB*5ZE?p|dyp?+!~B zr~XgG8TNhoQ_0i{zuWcnGs#;-_~P@qID<8#`$7bUA2RPcHU2|ndtu)N|0&G&2))@J zmCTyhH?#ehWNg9E(@V<(xASmJGQQM|4>g$XOUcxLj@;;o&sq6OME&IGD6;QgUrWZ% z=Eo(I!`{UclCc>iYOGkClW#=a1@;QP*?udzsR+Gc-%0KwA_ngp{{I$%HxaFJ*!ONu ze)A;>w&?7$BSjc~=*+H`WN^srQYB-DuCYGT$Xgp5@tz{|ZN#y$b=7ft`h%_Ebsf%` zWsR1%o^W*dnQeV%OI*Kg1L5efEmR-7O5ad2G0;&v=dF=AgY(9oHP#%A^M*_we49wt zkN0m1#NoVfzOlpJ-mo;u+%t%QPc6}vicg%T0d2C|-~OC|-y!^w$_Kj-D0LcgBgU(_OlVUmf7j=RQtktNycw|kW>44icumLr*c0ki%Om#iP}-#gL!`=6^h zaj>ymd6I2i7I%a&aMo|wNXg^^vt0R-_2cD2@6T1BIdQPDT%#o0dM)l~Vc_(|uuCM9 z3(Rtjk*pst7kYoLv6>SH8#`CyB(q-XK>x6M%V+d>hjZrmEGX2R!Dj)w2_i7wcw~M@ zXHSYGcMvBogZIMh;Pze=OU8yb1RrA9-7S%fUOzSUOwY0R6gL=?iDgvV(WUFVg zWa_ba)MIvVt7nR2Y^V_*Vpu&>C8OtFTYsi$4sP{Km&~9ZbeD<1s0Z2VnIV~aEFSfk z9o*`fDH$7T#D^GG&n(I48HR-%25i`Dhb7;m)?eA8hRGl=*bzz}DW9u;fGX z+2hVfx#nQ_a6aaUGgv>mxgs#uk4&68(nloM6Sv=Y=4lRgHO?CJiO=f!!ssn}KL5=> zsyY6piiV6IwhVgtfjBwI&HOz#huiOT{O)p4#Jh%#{jP&A{pb8w$e-_C=mv^d1M7^r zT&xqD0_niW3AZ}qlKtykpgGv7>s%;|?`P=!>r7~F>qN#6TLv|gmz?nLw4;OA)yZf2 ze_X2Z;g0)O7OuGA&R#PLd+(eVUi#_bI^WO0Hg)@stm*kv%WvQF=83Tn6~EyAmzEdj fR2`Ym{GZ$c)$z>Z-A?=OXgX+D%v*iv4*C5DY#YYx literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe144_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe144_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..cfd9468e32abe403d1de23d24eda737e4e772e0f GIT binary patch literal 6994 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 S`cngok&Ja&oe$;%^#K4OY{sqt literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe144_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe144_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..a2d1bcd5e37b653bfe2dfda4c7f0f0f719d33c11 GIT binary patch literal 10274 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 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe288_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe288_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..cfd9468e32abe403d1de23d24eda737e4e772e0f GIT binary patch literal 6994 zcmeHMdstJ~mOpu&JjnwPP6+CW$U~%hKm-)TgaCqo2BkJAtqCB4@`kaZRPzD?1q~<| z#cB}sQmeiAs2Zzn0u&>l0@@apI-rQO*D6J8(dqQgJ^_2Zy?%GTZ)X0uf6V@J_Svts z)?UB8_TFpdKoA6xbcFaX`lbZ*iP`$m=^y`f)7lHxn>FvuC;WNw2Yyom!o16$HcXqo zX7zr^`bA~lT*B?7l!Rj{X^ig69Y3pFE+~?^w0-L&xAhx8coN&RM_(d_Z@ka|z92=# zE&gS-=gHq%Dl3+JYxGZ}zogIhFRIXg^6{*W8ou+;+UtA$A9uZ5&NOi+2wuyJw&%2B z|NSs1@xA-=9vM4ytUnJ)I%_f$k4Hr-?1AX-dnL|8^RBo1(%0NO+u3;V*X0q#QDV`1 z3y$^v>0ZswwM*(hDg0#l=2>q;|LayO&Xyqf^g%#f$I`!CDERu@IrrB@On~@pAJntd zF?R8vhEAo%2fl1CTJ9{{`%Pleyd_tcTTQ%_r}vuoE~K%t&cFQk$MfQ$q*;Ntp1uK0 z641z{)ylSfhm>WHCWz{gB5d2Hb4#}1qEGy1;>Nu9-{$XGaZ$W;XjTf}D_j;P$)&Fy zKd|RSeF0%~yXT#aT?7EG7axLP@D2h`6nJFdNe53qct%(dv@$Xpqk%GH%OEIv;}i;g9NK{($>Ob7~-nC}Wf|2PoBRHHUo4xo>!a;p|w$t0wO`>0InicL~ODv9mR_zl<+m2JdPI$dMFx%+aehWQ z4^Zl1GxfQYeP6_Rf^v%G>_?;QK@letf(r+z@&T$BEeeT5lnaO$cvZN1v3DKS*?WBX z7tv4u=2RhE7-nz28Nug~DGJ939A7*|#yftMr$FO)?y=h#QT77<;?LFlZ$vqC$Jz%+ z?8X`(lMiKPc~#}Xcg5E-4%5?*R(UgKgo(pCXd*hYp+o9OSrlluXR(4Kd@);iqHW0e zTonU?l*v0F;r9my$2=biXD%l1QwXKl6nF2YLtYh!yqdh3E2RM5@+(WS1-yuO$C7czF?6(Pg5kkCP08*aU!Knj2Rt0Z ze45nl3)Ds=K{zEMdRSz3C3pes9rMj)h4Qk1^s=IK5-8h!DrIMNv$ud8;%vdF`9^91 zO3l)<^IjD;8>ySS;qSTBO-5>-9Pa`H@R6WVPAxQ2H;JfOayIDN0>*U1!@o0;vq9Gu zFs2)RthDvoc;YR_ry?5PZ$&uS$bt-hko*S-Dh;vw+rh^wnl@pq_+lVq38Gh<5WQmsv{Ne!=S~ zlMJEY?KjPU@OiQNO1j6AcCutClZ$ax9X!apqLEx7CmWHahqzS6VOB?jl5yOTaRMSS z8ZZ*W-zX(90*tvNMvzfYVk|T^lNce!ZW1HZI7(tjjTnWIV3blAtBguYM}TpJl5QZN zsj#w!53NXp()SWj1*}wqbEybuxDgnm3n^9~NpuLGkEAdQf=MT5@2Zd4T0q*HXCjCj zn8Ed1tG$!G8T-6n?lY;1d}9ijDKWRWWCtyAAL`fxD^L$w$r&-mVx$x}Xp?VaDBV|# zj3}KG`uh8K_uqQwj`RNhdfDCt*|gfEKG`jD18YA$Oq|7Kt#3{CsZ_ASZ}@XOo0?6g zS*Fu}K07za6nN6_5O$&2uCqD39plE`2oaE@_MtwT%`ETC?ChnFA8lOvL;A?otQ~W@ zs+Kif>pC8rt(GPTxSC_ElxC%!KTMImBs%e>A z7S_krT3`!TW7qn;%0d>NBrTIF3JO-{uV0(BHa9;fdEJuyj8uWHjkPdEBmc-kCVWhC z$;r=HpOG!747US}bk<8fB|S$jnX)kZfRTXfLbB&C9;-a2)Or3K=^VM|`EY>P>y%yO zJ@`ApX7=8*fuEl`>le82SjhQP^st6FZbg=+x=rj!z3Zx1?b_-vyI#!{#1sVAqmKQs z+sB$~?2s}h4%@BnH6IDS>nAsi0F=*JqDGCKq~#o|`O2m8+67;K7G3h-DqxnQsU8)7 zOFb}+tHGHS9NQREvy15#!z>WYZuD-Qol*}N%bP7xzZprC<(zcOBsuTM)t(YlRc(Cj zVC_kq5!NT4d8oTe{U>Viz|h^c4*l5hNXJmeaPKe>k7QysD@I~11wl6Y`6Yuu{3{lK z*cT8tbsteb9JQ%buw~aqW{Sg7CN4Y`2w&BZLbj&jvFvf&@k%dzU9*lKr*R%%J<(MKmeyc_-O5XrIfaxVI3$TR`;(Bw)rLDV{*--5 zw_I-v1i+|*G;jPTIfb7OEI4DsLEF;)O;<~MM^iTd zqx){36~N&F;COGO*ivAafa8dXf8~;?XKzVW?Q5XS2cQgemuMbJ)wXqZ*|jw#Wvk!3 z`q_;*E|~zA_69fVa*mgc3yx?>PYM6hmCs6g0Hy(ee7O4~O(6BSZ6Y;8LoL?cmj3pR z%DY3iTX3rofO!;-+_cn_R@;xhaOz`Rk>0!g75y!3eH}n0iYs9C{>XquK(kFIuIkFAlPB#?)|OlWQwai78SB2P z3C!$1K0lolWYh%rkrvY^D}pF*r&DAG${H)>y>UvO7qw7EeP2i2VnDs#Z&pPeyVi%w zerXo^`ulm2{G&8mnyJMGG^iDpx5^*2hGx>n6|LBaWN~*oBc?#GZy$PCd|I(tqv#VM zXaiMvvZ1?dJLFd_cl7XduKVSy=K)Ub&)w^myc4j*D|Xo&pC=#wnB`OXRYaM^Uj{bE|}+QtQ3W>4IlK#g7w3WjejbJEHm@xx%*kKp z^Fwd{$Z$Z^OflPCY|s|idsW+epS1Vsu`d{~|1O66c39gV`AuPK!Cnc|ZT7B>Tin3Dv!A)nI+_HG=I#$e?H$8M z$uf69djT8+XyCcP3)ls~!ZeE*`b;v_FJuomAxt4n=llaNm}aS>3IQ+v)=vr=!GT{TC|y3V8~+)L!2ME>}N{$JXYAW7R%IY z4X$Yz#WqYM=prq$N)}a;7Ikf|EX<{DrBREb%5rn5TXIR8Hkak1W&AE4`;i{^fU+^p z{ZaO)ls%8zHubL1wNE&;MKLW6D-XV?3GS9GI714#s0q=Mg1bf?H_546)2V^!W%(di zmgVZpa^=)bUerzF6u|aSrpVWebhgX>U(YnLtW zSGaZvUE5SsI~4FYddUK-WP!n!pKlG?EeX<*f_Jyh1wwyS2j3(GH@C9dgw*0((iX3> zP0BKUkAyuw01u(;hXe3)E_)34aeB@ZDd!ocQCSJo`$f2*7R6M&fcs#1;1XU6-cyWJ z)pY-mgUcU0%=r)Io-e;zmu#2@6W4z;J$lQLx}Tn1xai|XJh8auQpnLSADBJp0VJZz zEGLYM2dH+}AFh1y;?8d^4|4JnU9PQsFqp@u?N8i3^ZVM>?Kl21cB+zg=C`QlV}{@A zNcA)OSTr(G6CgK0y}8Hfsk6}N%+y~WG4hwW#fj!+CB$>9r;1u11n-=V+Hn=z^6s2% zw%hY0n`uTY!fRF@|Yo zBdZnT`jT>Qr6zf^&g zs_ITb8b6jsfxuyL!b%G^GE3u&I8JFp06&)IXk%&T!R9i3adu-xt)Y16EYFwKD%EX} z!l!n)OfWQ6d9O+y`|wVrR)Itco5g&udN*1{1IvnKw%L(cZrt|RRE+(I%YF(rD#|=3 zVm?rEo=G`lQg*(GQ7q>?z}U}5!5*Lvo7qpmabSk!BI-5>-lkOVG%K_g5T%s5B5#UP z_Kts`31YX(5nK}mavx)nivCHIV!ZgKC`A?h5X1sAb>bf!A>eBM%ftlO5FN~BGRdtH z=ylJYKom{(0MDL8HcwU{$pI=&`KnSH!sFUPWW0e@O-J|os0 zrW0Kf9JGYnN}q(&J`zeM?YJEod)G`BLjjPWG~z}8`A(_A8srkE$jFwgbkO=6J!q0M z3JAZ>eGc+qK}8n{^OY;wpF2ffet6>QTXv7DKJBVvr?TFP-O-bo%e1d1ezNCtqSmWgXxf3ZazUc+oW>QS#)Be z5=C+|^}g$K;S?-c51}+TNs!KVF%tNd2m;a61O@dSm#*+8i?OmrXCZ*$vU~`Z2r50u z=5#ezhU(=0DsC(-9P3w-Q?X8NxWz|>Nqvjq1!U5c)-;0zOU}jFelzVb!2xchTd;oa z2m$HxV})bM-FQ!@R}*0fF1Zh955U>jJ}&DtxjmOuO_gJvQUuJA1cdq=?S@ynqVcY6 zV%IiHdKkCM9wAMI{Xm?;T{HD)sI1gZCqk5iG@;uU%+h8fLAB@zq!}z7;F#rggIr>x z5AUXvERXn+!a!M%9^`3AkQlQjHE_%jC(?na2uh}DbLxa*bs}+Hn~@;mvg+21YW%n* ztz1ex_#tsLWe-`1#35Q9i3(`b3kiQauv&Nc zcBvQXuj^De*x|!^hKf>*PIn6zhdPZCijQ;HFJlAAhxC11>t&Hpx09kOj&)RzPpp=h z%sI!MEIM*dzbek;oNkt(*7a>>2xvBAi?O7g7#4b(6)UMiT)`rX1334jj8T9+)JPA* z_F=R}dYk-=sO|Cwm2T%PA`bvY0ZJQQDyG6hL~E`H3w5IXbkbbClU`Mv**r8axfx%{ z8&PeNXG!#Y*(h`Dq#Sg9Sez*vO0h!ICGa@nXTBU764U|~&3wea- z;N|t|nvIlWnvzzf1_#1>ymnV!qBvavFSuC^fUf(u=W9avpmA*|@-lIjE z(dz5zEvQUsUGLw3_yqlqMUpl`Vec_$&_-7xJ^*A(xO1{NuD8J6(|2M=Tz^*^VYCk* zKjZt#fQ4wjpVJZM&aRb~FL9sLtc7{nJZGc3v3A0SH0$Sf%*dq+h%YBOo^j3?w4YOb zUK=BFgPA}%?5C2|x%JQO=kg{N*7DRjgJ;#+5k4q&v)@bm;``G5QuUxtk%c<5FV{aHI<}jSt z*Hfs^cq=A3WL0B;cgOy|uZ>c>5@XJ^+(>o4H6gq9z0Zp26IvbFF8^!>nhOLTzV_dv z)HnV+)YIjDeSt|D=Pyoelgh3Mt5<5Cnj|UyB>wzNlXqugJGplXKr|qcmG$|D4G1e^ zh>Uw|{AR(a4xaT-oKH{6iCp91nJ5Ib`sF2O@h8UTj~Q}CKiYPB@%%sjt~DNx4sn*N zE-imFsXyL*_Ue+={uP>`3>1r=02#};E4Flc&VN_MEf)LMCilhvfCS?88w?k{M11U* zKiQNLX#VS1rN4N@%xjUA#_nhRPwW&-{`_deOe+qkzZn@~G|g{*#uAv!AQjjh%21ha S`cngok&Ja&oe$;%^#K4OY{sqt literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe288_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe288_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..a2d1bcd5e37b653bfe2dfda4c7f0f0f719d33c11 GIT binary patch literal 10274 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 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe432_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe432_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..cfd9468e32abe403d1de23d24eda737e4e772e0f GIT binary patch literal 6994 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 S`cngok&Ja&oe$;%^#K4OY{sqt literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe432_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe432_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..a2d1bcd5e37b653bfe2dfda4c7f0f0f719d33c11 GIT binary patch literal 10274 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 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe576_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe576_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..cfd9468e32abe403d1de23d24eda737e4e772e0f GIT binary patch literal 6994 zcmeHMdstJ~mOpu&JjnwPP6+CW$U~%hKm-)TgaCqo2BkJAtqCB4@`kaZRPzD?1q~<| z#cB}sQmeiAs2Zzn0u&>l0@@apI-rQO*D6J8(dqQgJ^_2Zy?%GTZ)X0uf6V@J_Svts z)?UB8_TFpdKoA6xbcFaX`lbZ*iP`$m=^y`f)7lHxn>FvuC;WNw2Yyom!o16$HcXqo zX7zr^`bA~lT*B?7l!Rj{X^ig69Y3pFE+~?^w0-L&xAhx8coN&RM_(d_Z@ka|z92=# zE&gS-=gHq%Dl3+JYxGZ}zogIhFRIXg^6{*W8ou+;+UtA$A9uZ5&NOi+2wuyJw&%2B z|NSs1@xA-=9vM4ytUnJ)I%_f$k4Hr-?1AX-dnL|8^RBo1(%0NO+u3;V*X0q#QDV`1 z3y$^v>0ZswwM*(hDg0#l=2>q;|LayO&Xyqf^g%#f$I`!CDERu@IrrB@On~@pAJntd zF?R8vhEAo%2fl1CTJ9{{`%Pleyd_tcTTQ%_r}vuoE~K%t&cFQk$MfQ$q*;Ntp1uK0 z641z{)ylSfhm>WHCWz{gB5d2Hb4#}1qEGy1;>Nu9-{$XGaZ$W;XjTf}D_j;P$)&Fy zKd|RSeF0%~yXT#aT?7EG7axLP@D2h`6nJFdNe53qct%(dv@$Xpqk%GH%OEIv;}i;g9NK{($>Ob7~-nC}Wf|2PoBRHHUo4xo>!a;p|w$t0wO`>0InicL~ODv9mR_zl<+m2JdPI$dMFx%+aehWQ z4^Zl1GxfQYeP6_Rf^v%G>_?;QK@letf(r+z@&T$BEeeT5lnaO$cvZN1v3DKS*?WBX z7tv4u=2RhE7-nz28Nug~DGJ939A7*|#yftMr$FO)?y=h#QT77<;?LFlZ$vqC$Jz%+ z?8X`(lMiKPc~#}Xcg5E-4%5?*R(UgKgo(pCXd*hYp+o9OSrlluXR(4Kd@);iqHW0e zTonU?l*v0F;r9my$2=biXD%l1QwXKl6nF2YLtYh!yqdh3E2RM5@+(WS1-yuO$C7czF?6(Pg5kkCP08*aU!Knj2Rt0Z ze45nl3)Ds=K{zEMdRSz3C3pes9rMj)h4Qk1^s=IK5-8h!DrIMNv$ud8;%vdF`9^91 zO3l)<^IjD;8>ySS;qSTBO-5>-9Pa`H@R6WVPAxQ2H;JfOayIDN0>*U1!@o0;vq9Gu zFs2)RthDvoc;YR_ry?5PZ$&uS$bt-hko*S-Dh;vw+rh^wnl@pq_+lVq38Gh<5WQmsv{Ne!=S~ zlMJEY?KjPU@OiQNO1j6AcCutClZ$ax9X!apqLEx7CmWHahqzS6VOB?jl5yOTaRMSS z8ZZ*W-zX(90*tvNMvzfYVk|T^lNce!ZW1HZI7(tjjTnWIV3blAtBguYM}TpJl5QZN zsj#w!53NXp()SWj1*}wqbEybuxDgnm3n^9~NpuLGkEAdQf=MT5@2Zd4T0q*HXCjCj zn8Ed1tG$!G8T-6n?lY;1d}9ijDKWRWWCtyAAL`fxD^L$w$r&-mVx$x}Xp?VaDBV|# zj3}KG`uh8K_uqQwj`RNhdfDCt*|gfEKG`jD18YA$Oq|7Kt#3{CsZ_ASZ}@XOo0?6g zS*Fu}K07za6nN6_5O$&2uCqD39plE`2oaE@_MtwT%`ETC?ChnFA8lOvL;A?otQ~W@ zs+Kif>pC8rt(GPTxSC_ElxC%!KTMImBs%e>A z7S_krT3`!TW7qn;%0d>NBrTIF3JO-{uV0(BHa9;fdEJuyj8uWHjkPdEBmc-kCVWhC z$;r=HpOG!747US}bk<8fB|S$jnX)kZfRTXfLbB&C9;-a2)Or3K=^VM|`EY>P>y%yO zJ@`ApX7=8*fuEl`>le82SjhQP^st6FZbg=+x=rj!z3Zx1?b_-vyI#!{#1sVAqmKQs z+sB$~?2s}h4%@BnH6IDS>nAsi0F=*JqDGCKq~#o|`O2m8+67;K7G3h-DqxnQsU8)7 zOFb}+tHGHS9NQREvy15#!z>WYZuD-Qol*}N%bP7xzZprC<(zcOBsuTM)t(YlRc(Cj zVC_kq5!NT4d8oTe{U>Viz|h^c4*l5hNXJmeaPKe>k7QysD@I~11wl6Y`6Yuu{3{lK z*cT8tbsteb9JQ%buw~aqW{Sg7CN4Y`2w&BZLbj&jvFvf&@k%dzU9*lKr*R%%J<(MKmeyc_-O5XrIfaxVI3$TR`;(Bw)rLDV{*--5 zw_I-v1i+|*G;jPTIfb7OEI4DsLEF;)O;<~MM^iTd zqx){36~N&F;COGO*ivAafa8dXf8~;?XKzVW?Q5XS2cQgemuMbJ)wXqZ*|jw#Wvk!3 z`q_;*E|~zA_69fVa*mgc3yx?>PYM6hmCs6g0Hy(ee7O4~O(6BSZ6Y;8LoL?cmj3pR z%DY3iTX3rofO!;-+_cn_R@;xhaOz`Rk>0!g75y!3eH}n0iYs9C{>XquK(kFIuIkFAlPB#?)|OlWQwai78SB2P z3C!$1K0lolWYh%rkrvY^D}pF*r&DAG${H)>y>UvO7qw7EeP2i2VnDs#Z&pPeyVi%w zerXo^`ulm2{G&8mnyJMGG^iDpx5^*2hGx>n6|LBaWN~*oBc?#GZy$PCd|I(tqv#VM zXaiMvvZ1?dJLFd_cl7XduKVSy=K)Ub&)w^myc4j*D|Xo&pC=#wnB`OXRYaM^Uj{bE|}+QtQ3W>4IlK#g7w3WjejbJEHm@xx%*kKp z^Fwd{$Z$Z^OflPCY|s|idsW+epS1Vsu`d{~|1O66c39gV`AuPK!Cnc|ZT7B>Tin3Dv!A)nI+_HG=I#$e?H$8M z$uf69djT8+XyCcP3)ls~!ZeE*`b;v_FJuomAxt4n=llaNm}aS>3IQ+v)=vr=!GT{TC|y3V8~+)L!2ME>}N{$JXYAW7R%IY z4X$Yz#WqYM=prq$N)}a;7Ikf|EX<{DrBREb%5rn5TXIR8Hkak1W&AE4`;i{^fU+^p z{ZaO)ls%8zHubL1wNE&;MKLW6D-XV?3GS9GI714#s0q=Mg1bf?H_546)2V^!W%(di zmgVZpa^=)bUerzF6u|aSrpVWebhgX>U(YnLtW zSGaZvUE5SsI~4FYddUK-WP!n!pKlG?EeX<*f_Jyh1wwyS2j3(GH@C9dgw*0((iX3> zP0BKUkAyuw01u(;hXe3)E_)34aeB@ZDd!ocQCSJo`$f2*7R6M&fcs#1;1XU6-cyWJ z)pY-mgUcU0%=r)Io-e;zmu#2@6W4z;J$lQLx}Tn1xai|XJh8auQpnLSADBJp0VJZz zEGLYM2dH+}AFh1y;?8d^4|4JnU9PQsFqp@u?N8i3^ZVM>?Kl21cB+zg=C`QlV}{@A zNcA)OSTr(G6CgK0y}8Hfsk6}N%+y~WG4hwW#fj!+CB$>9r;1u11n-=V+Hn=z^6s2% zw%hY0n`uTY!fRF@|Yo zBdZnT`jT>Qr6zf^&g zs_ITb8b6jsfxuyL!b%G^GE3u&I8JFp06&)IXk%&T!R9i3adu-xt)Y16EYFwKD%EX} z!l!n)OfWQ6d9O+y`|wVrR)Itco5g&udN*1{1IvnKw%L(cZrt|RRE+(I%YF(rD#|=3 zVm?rEo=G`lQg*(GQ7q>?z}U}5!5*Lvo7qpmabSk!BI-5>-lkOVG%K_g5T%s5B5#UP z_Kts`31YX(5nK}mavx)nivCHIV!ZgKC`A?h5X1sAb>bf!A>eBM%ftlO5FN~BGRdtH z=ylJYKom{(0MDL8HcwU{$pI=&`KnSH!sFUPWW0e@O-J|os0 zrW0Kf9JGYnN}q(&J`zeM?YJEod)G`BLjjPWG~z}8`A(_A8srkE$jFwgbkO=6J!q0M z3JAZ>eGc+qK}8n{^OY;wpF2ffet6>QTXv7DKJBVvr?TFP-O-bo%e1d1ezNCtqSmWgXxf3ZazUc+oW>QS#)Be z5=C+|^}g$K;S?-c51}+TNs!KVF%tNd2m;a61O@dSm#*+8i?OmrXCZ*$vU~`Z2r50u z=5#ezhU(=0DsC(-9P3w-Q?X8NxWz|>Nqvjq1!U5c)-;0zOU}jFelzVb!2xchTd;oa z2m$HxV})bM-FQ!@R}*0fF1Zh955U>jJ}&DtxjmOuO_gJvQUuJA1cdq=?S@ynqVcY6 zV%IiHdKkCM9wAMI{Xm?;T{HD)sI1gZCqk5iG@;uU%+h8fLAB@zq!}z7;F#rggIr>x z5AUXvERXn+!a!M%9^`3AkQlQjHE_%jC(?na2uh}DbLxa*bs}+Hn~@;mvg+21YW%n* ztz1ex_#tsLWe-`1#35Q9i3(`b3kiQauv&Nc zcBvQXuj^De*x|!^hKf>*PIn6zhdPZCijQ;HFJlAAhxC11>t&Hpx09kOj&)RzPpp=h z%sI!MEIM*dzbek;oNkt(*7a>>2xvBAi?O7g7#4b(6)UMiT)`rX1334jj8T9+)JPA* z_F=R}dYk-=sO|Cwm2T%PA`bvY0ZJQQDyG6hL~E`H3w5IXbkbbClU`Mv**r8axfx%{ z8&PeNXG!#Y*(h`Dq#Sg9Sez*vO0h!ICGa@nXTBU764U|~&3wea- z;N|t|nvIlWnvzzf1_#1>ymnV!qBvavFSuC^fUf(u=W9avpmA*|@-lIjE z(dz5zEvQUsUGLw3_yqlqMUpl`Vec_$&_-7xJ^*A(xO1{NuD8J6(|2M=Tz^*^VYCk* zKjZt#fQ4wjpVJZM&aRb~FL9sLtc7{nJZGc3v3A0SH0$Sf%*dq+h%YBOo^j3?w4YOb zUK=BFgPA}%?5C2|x%JQO=kg{N*7DRjgJ;#+5k4q&v)@bm;``G5QuUxtk%c<5FV{aHI<}jSt z*Hfs^cq=A3WL0B;cgOy|uZ>c>5@XJ^+(>o4H6gq9z0Zp26IvbFF8^!>nhOLTzV_dv z)HnV+)YIjDeSt|D=Pyoelgh3Mt5<5Cnj|UyB>wzNlXqugJGplXKr|qcmG$|D4G1e^ zh>Uw|{AR(a4xaT-oKH{6iCp91nJ5Ib`sF2O@h8UTj~Q}CKiYPB@%%sjt~DNx4sn*N zE-imFsXyL*_Ue+={uP>`3>1r=02#};E4Flc&VN_MEf)LMCilhvfCS?88w?k{M11U* zKiQNLX#VS1rN4N@%xjUA#_nhRPwW&-{`_deOe+qkzZn@~G|g{*#uAv!AQjjh%21ha S`cngok&Ja&oe$;%^#K4OY{sqt literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe576_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe576_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..a2d1bcd5e37b653bfe2dfda4c7f0f0f719d33c11 GIT binary patch literal 10274 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 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe720_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe720_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..cfd9468e32abe403d1de23d24eda737e4e772e0f GIT binary patch literal 6994 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 S`cngok&Ja&oe$;%^#K4OY{sqt literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe720_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe720_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..a2d1bcd5e37b653bfe2dfda4c7f0f0f719d33c11 GIT binary patch literal 10274 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 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe864_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe864_dx12_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..cfd9468e32abe403d1de23d24eda737e4e772e0f GIT binary patch literal 6994 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 S`cngok&Ja&oe$;%^#K4OY{sqt literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe864_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification-numraysperprobe864_vulkan_0.azshadervariant new file mode 100644 index 0000000000000000000000000000000000000000..a2d1bcd5e37b653bfe2dfda4c7f0f0f719d33c11 GIT binary patch literal 10274 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 literal 0 HcmV?d00001 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification.azshader index cd78a9526010f77721f32d19761b691e67687164..c12fd72c89af982806675d2b3fe47b4c22e454e4 100644 GIT binary patch delta 2125 zcmbPplVwJe>IOv?*1D|D2lF?pu>>))RRxD7W#>*lkfFM{UT3N5YnwU(UeX4kJd4@Bp z0mK>nLXgp6dY%rWCNA@hEG#HAzX7lLCdNh-ntuSV`KIP(l$ifqkkN5^t`4IXuJAE8 zGN8Yj2W9DRCHZyVVwa;@Hwi`+_S_@8oaZ(#s&|)TS9A=(1Rny#hPtgQwCKChx z5XDT=#F~o~kXW)JW>O~BTyW^&%z~Inm^gD88A(jJ#2L#(pv1sTu*8~+6ud;HQ({d9 z2e9_!x^#!hp{M>J7nC)p=fYCyWKfA*b9%Yz_SfQ!cFY{BHh-4dQmz>WN~vjr_*3aN zBF%g`*In}Uj)pfNGi`_~d&x8!DKK%SRWgkxCb^Phw6!2(BN0iKJfoQ!9q?8ZkYr1) Q*+`*{C+U)FIyk`f0BFiqs{jB1 delta 208 zcmbQyq&nv&%LYXj*4jDU_i8q)u>>))`Iq_!Ic838{KBfbxn5_f>Sl*N9(2*i8XV{R zDqr$Tzs%p96)Ge&{f8c#)AV*3=08yF+kx6oscv7elo_rUB*dY~!PMAbd_Cx>_4bLf zY&L?^H`Xz0ZwKnOL$PA}0XEL%s?$H*WB-Qi9+2=;4UX6iYwc#m%oW-$V8miAI6ZJ8 Kn>H&02mkeB diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_dx12_0.azshadervariant index 7ff0c32b5960274a3c2f9e080ddcb033ee856a23..cfd9468e32abe403d1de23d24eda737e4e772e0f 100644 GIT binary patch delta 16 Xcmca)cFAmmmo!IRR_BBH3=9kaJU|8> delta 16 Xcmca)cFAmmmo!K1obG!y3=9kaJq!jc diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_null_0.azshadervariant index 109a56fce3321885a4189e112adede955efc7857..6684ed1cf9359a2a2b8363db5c6d22dc41e80f79 100644 GIT binary patch delta 16 XcmaFH{ET_SJw}eYtj-7X85kGf*B|1U#k)5;6wSWfQ+jvudi1w+Nct=trQC)vvez aVF8@B2o$yI7f&5KB(`D!UJ#c7DFQGQf diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_dx12_0.azshadervariant index 8b926d86c8cf3e85ac3e0d8622e83ec71be4cd05..ed96d10db3f182421b5f8f395c62292140eee1b9 100644 GIT binary patch delta 18 ZcmeDC$=LUkaYI`TM_pFut49nB3;CHyvQIe delta 73 zcmV-P0Ji_T(g?fK2(T*z1$~^0=W4Ss1U#k)!eA<{#WCgAvvjJBw+OQgqhS&7e@wGa ft6vbeXmSBPrU-4t;N?vf;99d#t6mV73n>CH;{_mc diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_dx12_0.azshadervariant index 5e8c9a32c15bf1e5414d8d4112842d1167ed4954..1b8c4ec22bea501f9f8480887e017573682aac2d 100644 GIT binary patch delta 16 XcmeyC_APBgo-s#VR_9qK1_lNIMqvh$ delta 16 XcmeyC_APBgo-s%5obKmY3=9kaNaY6y diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_null_0.azshadervariant index 32d658041832894d9e6cbad1eab0e3ccb5c25a5b..68527221c71d16ffba95b1cf55dc3bba4c976f29 100644 GIT binary patch delta 16 XcmaFH{ET_SJw}eYtj@De3=9kaJc$MB delta 16 XcmaFH{ET_SJw}e&Io;2*7#J7;KMe+7 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_vulkan_0.azshadervariant index 87de50f6207a230e57020fdc12f352cd2a3cb420..c2fd622048cdd9aad836a2e4e30d6bba5c629c03 100644 GIT binary patch delta 16 XcmeyO`9*WX8xfAWtj@De3=9kaL#+mL delta 16 XcmeyO`9*WX8xfA$Io;2*7#J7;MllBH diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss.azshader index 85c5e34a7dce0789452bb0b43f1cc29beae1712a..5739d6828cb5fa3a10f61296cc50921501d59428 100644 GIT binary patch delta 73 zcmV-P0Ji_N(g?NE2(Tpt1%7IY&PlT>1U#k)XyhigwczGGvu>)5w+JpmyzEJ<|FyG8 ft6vbeVsZgJrU;!k$L>6pft9mLt6mV71t|hB?bRU> delta 73 zcmV-P0Ji_N(g?NE2(Tpt1$~^0$-1*D1U#k)OCpd4)`N+Hvu>)5w+K5LlnY|{3&XQX ft6vbeVsZgJrU@RU zU2#mbZO6;ac98+XP$ipVrfyT8Y@jPWId#fMgxD7?4%Nx#8!pc~R=D|Pq>bR_DHk(Q pY`O7!y87hZzrG>cbmR9`Esp+hwn9!`hLp{(BCQ3de=uh>004!pN|XQq delta 177 zcmZ4Rfn~u5mJPBjthIBx&%N5L#1h2F<`EU?mRvPCW~$=m*{lmSQ2A5UH~$E=W9E?C zsC8IC@b0J0c98+XP$ipVrfyT8Y@jPWId#fMgxD7?j`JbkCMVvxle_t4q>bR_DHk(Q pY`O7!y87hZzrG>cbmR9`Ee=zT!_sYLt}i#ginJD-{=uBl003@VOU?iQ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_dx12_0.azshadervariant index c1f11491d4945899420937490d984dd9035d9f4a..7cfce8e245c4b59a679c543b62c7c7a645698d98 100644 GIT binary patch delta 16 XcmdmGx65vWkvvCTR_B|$3=9kaI-~|P delta 16 XcmdmGx65vWkvvE3obGe47#J7;JER6y diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_null_0.azshadervariant index 01a6693151c388924df5ab7d43b77e055b724bd6..3fa87b4e79cf833cd9d576cd4f6ae62b1a69d6c8 100644 GIT binary patch delta 16 XcmaFH{ET_SJw}eYtj;%g85kGri#sB~S diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_vulkan_0.azshadervariant index 1e56c4df52d4c196318c38b826b4034e33371636..9b831386eb42d39438926b3da6fc67f6460a1d3e 100644 GIT binary patch delta 16 XcmaD9@hD&N diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender.azshader index 1f045706254b0b0c859f4bc976030ea3b50a5844..4676c42e8da1743b54f491e17ccc3347aa0fb277 100644 GIT binary patch delta 342 zcmX@Sp7-#2-VItTELok8Pi@v?sdQsYDU66JtK7WSYZV8K9UCm)0AsK9;^5fab^8Pp zOdvK`QfK=gHKt?C9B=YvC$Guq{{g;C3Y&rU@`_OnW(*8W)9=)U?klaxQNkMrVVigCqvg%t>piHfehPi z+?c}!w=3B&O@Mi8@>(z1=>=lUD%f*^md^1Kke{*?UPcbks0033Z2lD^` delta 17 YcmaF=j`96F#tj+e?7CT9Ul1_l5tvIMsP diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_vulkan_0.azshadervariant index 4cbb76954dbaef688dfb2961b893a2156f11785a..5caf3084766a8bd2be7d63394f0257af6e304dd6 100644 GIT binary patch delta 17 ZcmbQZhjHQ_#tmF?>{*?UPcbks002NV23!CD delta 17 YcmbQZhjHQ_#tmF??7CT9Ul(DiffuseProbeGridNumRaysPerProbe::NumRaysPerProbe_##numRaysPerProbe) } + + static const DiffuseProbeGridNumRaysPerProbeEntry DiffuseProbeGridNumRaysPerProbeArray[aznumeric_cast(DiffuseProbeGridNumRaysPerProbe::Count)] = + { + DECLARE_DiffuseProbeGridNumRaysPerProbeEntry(144), + DECLARE_DiffuseProbeGridNumRaysPerProbeEntry(288), + DECLARE_DiffuseProbeGridNumRaysPerProbeEntry(432), + DECLARE_DiffuseProbeGridNumRaysPerProbeEntry(576), + DECLARE_DiffuseProbeGridNumRaysPerProbeEntry(720), + DECLARE_DiffuseProbeGridNumRaysPerProbeEntry(864), + DECLARE_DiffuseProbeGridNumRaysPerProbeEntry(1008) + }; + static const uint32_t DiffuseProbeGridNumRaysPerProbeArraySize = RHI::ArraySize(DiffuseProbeGridNumRaysPerProbeArray); + static const char* DiffuseProbeGridIrradianceFileName = "Irradiance_lutrgba16f.dds"; static const char* DiffuseProbeGridDistanceFileName = "Distance_lutrg32f.dds"; static const char* DiffuseProbeGridProbeDataFileName = "ProbeData_lutrgba16f.dds"; @@ -82,6 +118,7 @@ namespace AZ virtual void SetProbeSpacing(const DiffuseProbeGridHandle& probeGrid, const AZ::Vector3& probeSpacing) = 0; virtual void SetViewBias(const DiffuseProbeGridHandle& probeGrid, float viewBias) = 0; virtual void SetNormalBias(const DiffuseProbeGridHandle& probeGrid, float normalBias) = 0; + virtual void SetNumRaysPerProbe(const DiffuseProbeGridHandle& probeGrid, const DiffuseProbeGridNumRaysPerProbe& numRaysPerProbe) = 0; virtual void SetAmbientMultiplier(const DiffuseProbeGridHandle& probeGrid, float ambientMultiplier) = 0; virtual void Enable(const DiffuseProbeGridHandle& probeGrid, bool enable) = 0; virtual void SetGIShadows(const DiffuseProbeGridHandle& probeGrid, bool giShadows) = 0; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp index a72d90fc94..798ebc502b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp @@ -134,6 +134,12 @@ namespace AZ m_updateRenderObjectSrg = true; } + void DiffuseProbeGrid::SetNumRaysPerProbe(const DiffuseProbeGridNumRaysPerProbe& numRaysPerProbe) + { + m_numRaysPerProbe = numRaysPerProbe; + m_updateTextures = true; + } + void DiffuseProbeGrid::SetTransform(const AZ::Transform& transform) { m_transform = transform; @@ -280,7 +286,7 @@ namespace AZ // probe raytrace { - uint32_t width = m_numRaysPerProbe; + uint32_t width = GetNumRaysPerProbe().m_rayCount; uint32_t height = GetTotalProbeCount(); m_rayTraceImage[m_currentImageIndex] = RHI::Factory::Get().CreateImage(); @@ -422,7 +428,7 @@ namespace AZ srg->SetConstantRaw(constantIndex, &probeGridCounts[0], sizeof(probeGridCounts)); constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_probeGrid.probeNumRays")); - srg->SetConstant(constantIndex, m_numRaysPerProbe); + srg->SetConstant(constantIndex, GetNumRaysPerProbe().m_rayCount); constantIndex = srgLayout->FindShaderInputConstantIndex(AZ::Name("m_probeGrid.probeNumIrradianceTexels")); srg->SetConstant(constantIndex, DefaultNumIrradianceTexels); diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h index a828fe4b96..8c8470cdad 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h @@ -81,6 +81,9 @@ namespace AZ float GetViewBias() const { return m_viewBias; } void SetViewBias(float viewBias); + const DiffuseProbeGridNumRaysPerProbeEntry& GetNumRaysPerProbe() const { return DiffuseProbeGridNumRaysPerProbeArray[aznumeric_cast(m_numRaysPerProbe)]; } + void SetNumRaysPerProbe(const DiffuseProbeGridNumRaysPerProbe& numRaysPerProbe); + float GetAmbientMultiplier() const { return m_ambientMultiplier; } void SetAmbientMultiplier(float ambientMultiplier); @@ -95,8 +98,6 @@ namespace AZ DiffuseProbeGridMode GetMode() const { return m_mode; } void SetMode(DiffuseProbeGridMode mode); - uint32_t GetNumRaysPerProbe() const { return m_numRaysPerProbe; } - uint32_t GetRemainingRelocationIterations() const { return aznumeric_cast(m_remainingRelocationIterations); } void DecrementRemainingRelocationIterations() { m_remainingRelocationIterations = AZStd::max(0, m_remainingRelocationIterations - 1); } void ResetRemainingRelocationIterations() { m_remainingRelocationIterations = DefaultNumRelocationIterations; } @@ -201,7 +202,6 @@ namespace AZ bool m_enabled = true; float m_normalBias = 0.6f; float m_viewBias = 0.01f; - uint32_t m_numRaysPerProbe = 288; float m_probeMaxRayDistance = 30.0f; float m_probeDistanceExponent = 50.0f; float m_probeHysteresis = 0.95f; @@ -214,6 +214,8 @@ namespace AZ bool m_giShadows = true; bool m_useDiffuseIbl = true; + DiffuseProbeGridNumRaysPerProbe m_numRaysPerProbe = DiffuseProbeGridNumRaysPerProbe::NumRaysPerProbe_288; + // rotation transform applied to probe rays AZ::Quaternion m_probeRayRotation; AZ::SimpleLcgRandom m_random; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp index 702e784c86..a5da79a482 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -44,29 +43,35 @@ namespace AZ void DiffuseProbeGridBlendDistancePass::LoadShader() { - // load shader - // Note: the shader may not be available on all platforms - AZStd::string shaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistance.azshader"; - m_shader = RPI::LoadCriticalShader(shaderFilePath); - if (m_shader == nullptr) + // load shaders, each supervariant handles a different number of rays per probe + // Note: the raytracing shaders may not be available on all platforms + m_shaders.reserve(DiffuseProbeGridNumRaysPerProbeArraySize); + for (uint32_t index = 0; index < DiffuseProbeGridNumRaysPerProbeArraySize; ++index) { - return; - } + AZStd::string shaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistance.azshader"; + Data::Instance shader = RPI::LoadCriticalShader(shaderFilePath, DiffuseProbeGridNumRaysPerProbeArray[index].m_supervariant); + if (shader == nullptr) + { + return; + } - // load pipeline state - RHI::PipelineStateDescriptorForDispatch pipelineStateDescriptor; - const auto& shaderVariant = m_shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId); - shaderVariant.ConfigurePipelineState(pipelineStateDescriptor); - m_pipelineState = m_shader->AcquirePipelineState(pipelineStateDescriptor); + RHI::PipelineStateDescriptorForDispatch pipelineStateDescriptor; + const auto& shaderVariant = shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId); + shaderVariant.ConfigurePipelineState(pipelineStateDescriptor); + const RHI::PipelineState* pipelineState = shader->AcquirePipelineState(pipelineStateDescriptor); + AZ_Assert(pipelineState, "Failed to acquire pipeline state"); - // load Pass Srg asset - m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); + RHI::Ptr srgLayout = shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); + AZ_Assert(srgLayout.get(), "Failed to find Srg layout"); - // retrieve the number of threads per thread group from the shader - const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs); - if (!outcome.IsSuccess()) - { - AZ_Error("PassSystem", false, "[DiffuseProbeGridBlendDistancePass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); + RHI::DispatchDirect dispatchArgs; + const auto outcome = RPI::GetComputeShaderNumThreads(shader->GetAsset(), dispatchArgs); + if (!outcome.IsSuccess()) + { + AZ_Error("PassSystem", false, "[DiffuseProbeBlendIrradiancePass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); + } + + m_shaders.push_back({ shader, pipelineState, srgLayout, dispatchArgs }); } } @@ -142,7 +147,8 @@ namespace AZ { // the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs // (see ValidateSetImageView() in ShaderResourceGroupData.cpp) - diffuseProbeGrid->UpdateBlendDistanceSrg(m_shader, m_srgLayout); + DiffuseProbeGridShader& shader = m_shaders[diffuseProbeGrid->GetNumRaysPerProbe().m_index]; + diffuseProbeGrid->UpdateBlendDistanceSrg(shader.m_shader, shader.m_srgLayout); diffuseProbeGrid->GetBlendDistanceSrg()->Compile(); } @@ -157,6 +163,8 @@ namespace AZ // submit the DispatchItem for each DiffuseProbeGrid for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { + DiffuseProbeGridShader& shader = m_shaders[diffuseProbeGrid->GetNumRaysPerProbe().m_index]; + const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetBlendDistanceSrg()->GetRHIShaderResourceGroup(); commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup); @@ -165,8 +173,8 @@ namespace AZ diffuseProbeGrid->GetTexture2DProbeCount(probeCountX, probeCountY); RHI::DispatchItem dispatchItem; - dispatchItem.m_arguments = m_dispatchArgs; - dispatchItem.m_pipelineState = m_pipelineState; + dispatchItem.m_arguments = shader.m_dispatchArgs; + dispatchItem.m_pipelineState = shader.m_pipelineState; dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsX = probeCountX * dispatchItem.m_arguments.m_direct.m_threadsPerGroupX; dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsY = probeCountY * dispatchItem.m_arguments.m_direct.m_threadsPerGroupY; dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsZ = 1; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.h index b85e54d25f..942f90eb10 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace AZ { @@ -47,11 +48,16 @@ namespace AZ void CompileResources(const RHI::FrameGraphCompileContext& context) override; void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override; - // shader - Data::Instance m_shader; - const RHI::PipelineState* m_pipelineState = nullptr; - RHI::Ptr m_srgLayout; - RHI::DispatchDirect m_dispatchArgs; + // shaders + struct DiffuseProbeGridShader + { + Data::Instance m_shader; + const RHI::PipelineState* m_pipelineState = nullptr; + RHI::Ptr m_srgLayout; + RHI::DispatchDirect m_dispatchArgs; + }; + + AZStd::vector m_shaders; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp index 7609e27b66..7a12fc5415 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -44,29 +43,35 @@ namespace AZ void DiffuseProbeGridBlendIrradiancePass::LoadShader() { - // load shader - // Note: the shader may not be available on all platforms - AZStd::string shaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiance.azshader"; - m_shader = RPI::LoadCriticalShader(shaderFilePath); - if (m_shader == nullptr) + // load shaders, each supervariant handles a different number of rays per probe + // Note: the raytracing shaders may not be available on all platforms + m_shaders.reserve(DiffuseProbeGridNumRaysPerProbeArraySize); + for (uint32_t index = 0; index < DiffuseProbeGridNumRaysPerProbeArraySize; ++index) { - return; - } + AZStd::string shaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiance.azshader"; + Data::Instance shader = RPI::LoadCriticalShader(shaderFilePath, DiffuseProbeGridNumRaysPerProbeArray[index].m_supervariant); + if (shader == nullptr) + { + return; + } - // load pipeline state - RHI::PipelineStateDescriptorForDispatch pipelineStateDescriptor; - const auto& shaderVariant = m_shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId); - shaderVariant.ConfigurePipelineState(pipelineStateDescriptor); - m_pipelineState = m_shader->AcquirePipelineState(pipelineStateDescriptor); + RHI::PipelineStateDescriptorForDispatch pipelineStateDescriptor; + const auto& shaderVariant = shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId); + shaderVariant.ConfigurePipelineState(pipelineStateDescriptor); + const RHI::PipelineState* pipelineState = shader->AcquirePipelineState(pipelineStateDescriptor); + AZ_Assert(pipelineState, "Failed to acquire pipeline state"); - // load Pass Srg asset - m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); + RHI::Ptr srgLayout = shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); + AZ_Assert(srgLayout.get(), "Failed to find Srg layout"); - // retrieve the number of threads per thread group from the shader - const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs); - if (!outcome.IsSuccess()) - { - AZ_Error("PassSystem", false, "[DiffuseProbeBlendIrradiancePass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); + RHI::DispatchDirect dispatchArgs; + const auto outcome = RPI::GetComputeShaderNumThreads(shader->GetAsset(), dispatchArgs); + if (!outcome.IsSuccess()) + { + AZ_Error("PassSystem", false, "[DiffuseProbeBlendIrradiancePass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); + } + + m_shaders.push_back({ shader, pipelineState, srgLayout, dispatchArgs }); } } @@ -132,7 +137,8 @@ namespace AZ { // the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs // (see ValidateSetImageView() in ShaderResourceGroupData.cpp) - diffuseProbeGrid->UpdateBlendIrradianceSrg(m_shader, m_srgLayout); + DiffuseProbeGridShader& shader = m_shaders[diffuseProbeGrid->GetNumRaysPerProbe().m_index]; + diffuseProbeGrid->UpdateBlendIrradianceSrg(shader.m_shader, shader.m_srgLayout); diffuseProbeGrid->GetBlendIrradianceSrg()->Compile(); } @@ -147,6 +153,8 @@ namespace AZ // submit the DispatchItem for each DiffuseProbeGrid for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { + DiffuseProbeGridShader& shader = m_shaders[diffuseProbeGrid->GetNumRaysPerProbe().m_index]; + const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetBlendIrradianceSrg()->GetRHIShaderResourceGroup(); commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup); @@ -155,8 +163,8 @@ namespace AZ diffuseProbeGrid->GetTexture2DProbeCount(probeCountX, probeCountY); RHI::DispatchItem dispatchItem; - dispatchItem.m_arguments = m_dispatchArgs; - dispatchItem.m_pipelineState = m_pipelineState; + dispatchItem.m_arguments = shader.m_dispatchArgs; + dispatchItem.m_pipelineState = shader.m_pipelineState; dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsX = probeCountX * dispatchItem.m_arguments.m_direct.m_threadsPerGroupX; dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsY = probeCountY * dispatchItem.m_arguments.m_direct.m_threadsPerGroupY; dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsZ = 1; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.h index 3c5691a4b4..77dba9745c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace AZ { @@ -47,11 +48,16 @@ namespace AZ void CompileResources(const RHI::FrameGraphCompileContext& context) override; void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override; - // shader - Data::Instance m_shader; - const RHI::PipelineState* m_pipelineState = nullptr; - RHI::Ptr m_srgLayout; - RHI::DispatchDirect m_dispatchArgs; + // shaders + struct DiffuseProbeGridShader + { + Data::Instance m_shader; + const RHI::PipelineState* m_pipelineState = nullptr; + RHI::Ptr m_srgLayout; + RHI::DispatchDirect m_dispatchArgs; + }; + + AZStd::vector m_shaders; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp index 7394b1ccfb..1d1e6f745f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -48,29 +47,35 @@ namespace AZ void DiffuseProbeGridClassificationPass::LoadShader() { - // load shader - // Note: the shader may not be available on all platforms - AZStd::string shaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridClassification.azshader"; - m_shader = RPI::LoadCriticalShader(shaderFilePath); - if (m_shader == nullptr) + // load shaders, each supervariant handles a different number of rays per probe + // Note: the raytracing shaders may not be available on all platforms + m_shaders.reserve(DiffuseProbeGridNumRaysPerProbeArraySize); + for (uint32_t index = 0; index < DiffuseProbeGridNumRaysPerProbeArraySize; ++index) { - return; - } + AZStd::string shaderFilePath = "Shaders/DiffuseGlobalIllumination/DiffuseProbeGridClassification.azshader"; + Data::Instance shader = RPI::LoadCriticalShader(shaderFilePath, DiffuseProbeGridNumRaysPerProbeArray[index].m_supervariant); + if (shader == nullptr) + { + return; + } - // load pipeline state - RHI::PipelineStateDescriptorForDispatch pipelineStateDescriptor; - const auto& shaderVariant = m_shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId); - shaderVariant.ConfigurePipelineState(pipelineStateDescriptor); - m_pipelineState = m_shader->AcquirePipelineState(pipelineStateDescriptor); + RHI::PipelineStateDescriptorForDispatch pipelineStateDescriptor; + const auto& shaderVariant = shader->GetVariant(RPI::ShaderAsset::RootShaderVariantStableId); + shaderVariant.ConfigurePipelineState(pipelineStateDescriptor); + const RHI::PipelineState* pipelineState = shader->AcquirePipelineState(pipelineStateDescriptor); + AZ_Assert(pipelineState, "Failed to acquire pipeline state"); - // load Pass Srg asset - m_srgLayout = m_shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); + RHI::Ptr srgLayout = shader->FindShaderResourceGroupLayout(RPI::SrgBindingSlot::Pass); + AZ_Assert(srgLayout.get(), "Failed to find Srg layout"); - // retrieve the number of threads per thread group from the shader - const auto outcome = RPI::GetComputeShaderNumThreads(m_shader->GetAsset(), m_dispatchArgs); - if (!outcome.IsSuccess()) - { - AZ_Error("PassSystem", false, "[DiffuseProbeClassificationPass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); + RHI::DispatchDirect dispatchArgs; + const auto outcome = RPI::GetComputeShaderNumThreads(shader->GetAsset(), dispatchArgs); + if (!outcome.IsSuccess()) + { + AZ_Error("PassSystem", false, "[DiffuseProbeBlendIrradiancePass '%s']: Shader '%s' contains invalid numthreads arguments:\n%s", GetPathName().GetCStr(), shaderFilePath.c_str(), outcome.GetError().c_str()); + } + + m_shaders.push_back({ shader, pipelineState, srgLayout, dispatchArgs }); } } @@ -135,7 +140,8 @@ namespace AZ { // the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs // (see ValidateSetImageView() in ShaderResourceGroupData.cpp) - diffuseProbeGrid->UpdateClassificationSrg(m_shader, m_srgLayout); + DiffuseProbeGridShader& shader = m_shaders[diffuseProbeGrid->GetNumRaysPerProbe().m_index]; + diffuseProbeGrid->UpdateClassificationSrg(shader.m_shader, shader.m_srgLayout); diffuseProbeGrid->GetClassificationSrg()->Compile(); } } @@ -149,6 +155,8 @@ namespace AZ // submit the DispatchItems for each DiffuseProbeGrid for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { + DiffuseProbeGridShader& shader = m_shaders[diffuseProbeGrid->GetNumRaysPerProbe().m_index]; + const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetClassificationSrg()->GetRHIShaderResourceGroup(); commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup); @@ -157,8 +165,8 @@ namespace AZ diffuseProbeGrid->GetTexture2DProbeCount(probeCountX, probeCountY); RHI::DispatchItem dispatchItem; - dispatchItem.m_arguments = m_dispatchArgs; - dispatchItem.m_pipelineState = m_pipelineState; + dispatchItem.m_arguments = shader.m_dispatchArgs; + dispatchItem.m_pipelineState = shader.m_pipelineState; dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsX = probeCountX; dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsY = probeCountY; dispatchItem.m_arguments.m_direct.m_totalNumberOfThreadsZ = 1; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.h index 271cb3d146..3ec76fd0f0 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.h @@ -18,6 +18,7 @@ #include #include #include +#include namespace AZ { @@ -49,10 +50,15 @@ namespace AZ void BuildCommandListInternal(const RHI::FrameGraphExecuteContext& context) override; // shader - Data::Instance m_shader; - const RHI::PipelineState* m_pipelineState = nullptr; - RHI::Ptr m_srgLayout; - RHI::DispatchDirect m_dispatchArgs; + struct DiffuseProbeGridShader + { + Data::Instance m_shader; + const RHI::PipelineState* m_pipelineState = nullptr; + RHI::Ptr m_srgLayout; + RHI::DispatchDirect m_dispatchArgs; + }; + + AZStd::vector m_shaders; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp index 281255f1b4..ea02a8e0a2 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp @@ -295,6 +295,12 @@ namespace AZ probeGrid->SetNormalBias(normalBias); } + void DiffuseProbeGridFeatureProcessor::SetNumRaysPerProbe(const DiffuseProbeGridHandle& probeGrid, const DiffuseProbeGridNumRaysPerProbe& numRaysPerProbe) + { + AZ_Assert(probeGrid.get(), "SetNumRaysPerProbe called with an invalid handle"); + probeGrid->SetNumRaysPerProbe(numRaysPerProbe); + } + void DiffuseProbeGridFeatureProcessor::SetAmbientMultiplier(const DiffuseProbeGridHandle& probeGrid, float ambientMultiplier) { AZ_Assert(probeGrid.get(), "SetAmbientMultiplier called with an invalid handle"); diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h index 16dfbd517a..d0df7dfbfe 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h @@ -39,6 +39,7 @@ namespace AZ void SetProbeSpacing(const DiffuseProbeGridHandle& probeGrid, const AZ::Vector3& probeSpacing) override; void SetViewBias(const DiffuseProbeGridHandle& probeGrid, float viewBias) override; void SetNormalBias(const DiffuseProbeGridHandle& probeGrid, float normalBias) override; + void SetNumRaysPerProbe(const DiffuseProbeGridHandle& probeGrid, const DiffuseProbeGridNumRaysPerProbe& numRaysPerProbe) override; void SetAmbientMultiplier(const DiffuseProbeGridHandle& probeGrid, float ambientMultiplier) override; void Enable(const DiffuseProbeGridHandle& probeGrid, bool enable) override; void SetGIShadows(const DiffuseProbeGridHandle& probeGrid, bool giShadows) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp index df551e7f42..7af6f4c8ec 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp @@ -299,7 +299,7 @@ namespace AZ }; RHI::DispatchRaysItem dispatchRaysItem; - dispatchRaysItem.m_width = diffuseProbeGrid->GetNumRaysPerProbe(); + dispatchRaysItem.m_width = diffuseProbeGrid->GetNumRaysPerProbe().m_rayCount; dispatchRaysItem.m_height = diffuseProbeGrid->GetTotalProbeCount(); dispatchRaysItem.m_depth = 1; dispatchRaysItem.m_rayTracingPipelineState = m_rayTracingPipelineState.get(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPIUtils.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPIUtils.h index 3e92542429..70754777c7 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPIUtils.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RPIUtils.h @@ -33,11 +33,11 @@ namespace AZ Data::Asset FindCriticalShaderAsset(const AZStd::string& shaderFilePath); //! Loads a shader for the given shader asset ID. Optional shaderFilePath param for debugging. - Data::Instance LoadShader(Data::AssetId shaderAssetId, const AZStd::string& shaderFilePath = ""); + Data::Instance LoadShader(Data::AssetId shaderAssetId, const AZStd::string& shaderFilePath = "", const AZStd::string& supervariantName = ""); //! Loads a shader for the given shader file path - Data::Instance LoadShader(const AZStd::string& shaderFilePath); - Data::Instance LoadCriticalShader(const AZStd::string& shaderFilePath); + Data::Instance LoadShader(const AZStd::string& shaderFilePath, const AZStd::string& supervariantName = ""); + Data::Instance LoadCriticalShader(const AZStd::string& shaderFilePath, const AZStd::string& supervariantName = ""); //! Loads a streaming image asset for the given file path Data::Instance LoadStreamingTexture(AZStd::string_view path); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp index fda8f967da..7285273c3e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPIUtils.cpp @@ -74,7 +74,7 @@ namespace AZ return shaderAsset; } - Data::Instance LoadShader(Data::AssetId shaderAssetId, const AZStd::string& shaderFilePath) + Data::Instance LoadShader(Data::AssetId shaderAssetId, const AZStd::string& shaderFilePath, const AZStd::string& supervariantName) { auto shaderAsset = FindShaderAsset(shaderAssetId, shaderFilePath); if (!shaderAsset) @@ -82,7 +82,7 @@ namespace AZ return nullptr; } - Data::Instance shader = Shader::FindOrCreate(shaderAsset); + Data::Instance shader = Shader::FindOrCreate(shaderAsset, AZ::Name(supervariantName)); if (!shader) { AZ_Error("RPI Utils", false, "Failed to find or create a shader instance from shader asset [%s] with asset ID [%s]", shaderFilePath.c_str(), shaderAssetId.ToString().c_str()); @@ -103,15 +103,15 @@ namespace AZ return FindShaderAsset(GetShaderAssetId(shaderFilePath, isCritical), shaderFilePath); } - Data::Instance LoadShader(const AZStd::string& shaderFilePath) + Data::Instance LoadShader(const AZStd::string& shaderFilePath, const AZStd::string& supervariantName) { - return LoadShader(GetShaderAssetId(shaderFilePath), shaderFilePath); + return LoadShader(GetShaderAssetId(shaderFilePath), shaderFilePath, supervariantName); } - Data::Instance LoadCriticalShader(const AZStd::string& shaderFilePath) + Data::Instance LoadCriticalShader(const AZStd::string& shaderFilePath, const AZStd::string& supervariantName) { const bool isCritical = true; - return LoadShader(GetShaderAssetId(shaderFilePath, isCritical), shaderFilePath); + return LoadShader(GetShaderAssetId(shaderFilePath, isCritical), shaderFilePath, supervariantName); } AZ::Data::Instance LoadStreamingTexture(AZStd::string_view path) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentConstants.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentConstants.h index 64669eceab..91c4e2bcf4 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentConstants.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentConstants.h @@ -19,5 +19,6 @@ namespace AZ static constexpr float DefaultDiffuseProbeGridAmbientMultiplier = 1.0f; static constexpr float DefaultDiffuseProbeGridViewBias = 0.2f; static constexpr float DefaultDiffuseProbeGridNormalBias = 0.1f; + static constexpr DiffuseProbeGridNumRaysPerProbe DefaultDiffuseProbeGridNumRaysPerProbe = DiffuseProbeGridNumRaysPerProbe::NumRaysPerProbe_288; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp index 397f22c4ff..b7dbbdbcf5 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp @@ -34,12 +34,13 @@ namespace AZ if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(1) + ->Version(2) // ATOM-17127 ->Field("ProbeSpacing", &DiffuseProbeGridComponentConfig::m_probeSpacing) ->Field("Extents", &DiffuseProbeGridComponentConfig::m_extents) ->Field("AmbientMultiplier", &DiffuseProbeGridComponentConfig::m_ambientMultiplier) ->Field("ViewBias", &DiffuseProbeGridComponentConfig::m_viewBias) ->Field("NormalBias", &DiffuseProbeGridComponentConfig::m_normalBias) + ->Field("NumRaysPerProbe", &DiffuseProbeGridComponentConfig::m_numRaysPerProbe) ->Field("EditorMode", &DiffuseProbeGridComponentConfig::m_editorMode) ->Field("RuntimeMode", &DiffuseProbeGridComponentConfig::m_runtimeMode) ->Field("BakedIrradianceTextureRelativePath", &DiffuseProbeGridComponentConfig::m_bakedIrradianceTextureRelativePath) @@ -138,6 +139,7 @@ namespace AZ m_featureProcessor->SetAmbientMultiplier(m_handle, m_configuration.m_ambientMultiplier); m_featureProcessor->SetViewBias(m_handle, m_configuration.m_viewBias); m_featureProcessor->SetNormalBias(m_handle, m_configuration.m_normalBias); + m_featureProcessor->SetNumRaysPerProbe(m_handle, m_configuration.m_numRaysPerProbe); // load the baked texture assets, but only if they are all valid if (m_configuration.m_bakedIrradianceTextureAsset.GetId().IsValid() && @@ -320,6 +322,17 @@ namespace AZ m_featureProcessor->SetNormalBias(m_handle, m_configuration.m_normalBias); } + void DiffuseProbeGridComponentController::SetNumRaysPerProbe(const DiffuseProbeGridNumRaysPerProbe& numRaysPerProbe) + { + if (!m_featureProcessor) + { + return; + } + + m_configuration.m_numRaysPerProbe = numRaysPerProbe; + m_featureProcessor->SetNumRaysPerProbe(m_handle, m_configuration.m_numRaysPerProbe); + } + void DiffuseProbeGridComponentController::SetEditorMode(DiffuseProbeGridMode editorMode) { if (!m_featureProcessor) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.h index d3dd0efc0c..8f84954b2c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.h @@ -35,6 +35,7 @@ namespace AZ float m_ambientMultiplier = DefaultDiffuseProbeGridAmbientMultiplier; float m_viewBias = DefaultDiffuseProbeGridViewBias; float m_normalBias = DefaultDiffuseProbeGridNormalBias; + DiffuseProbeGridNumRaysPerProbe m_numRaysPerProbe = DefaultDiffuseProbeGridNumRaysPerProbe; DiffuseProbeGridMode m_editorMode = DiffuseProbeGridMode::RealTime; DiffuseProbeGridMode m_runtimeMode = DiffuseProbeGridMode::RealTime; @@ -98,6 +99,7 @@ namespace AZ void SetAmbientMultiplier(float ambientMultiplier); void SetViewBias(float viewBias); void SetNormalBias(float normalBias); + void SetNumRaysPerProbe(const DiffuseProbeGridNumRaysPerProbe& numRaysPerProbe); void SetEditorMode(DiffuseProbeGridMode editorMode); void SetRuntimeMode(DiffuseProbeGridMode runtimeMode); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp index 19b3f4459c..6588b18636 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.cpp @@ -40,6 +40,7 @@ namespace AZ ->Field("ambientMultiplier", &EditorDiffuseProbeGridComponent::m_ambientMultiplier) ->Field("viewBias", &EditorDiffuseProbeGridComponent::m_viewBias) ->Field("normalBias", &EditorDiffuseProbeGridComponent::m_normalBias) + ->Field("numRaysPerProbe", &EditorDiffuseProbeGridComponent::m_numRaysPerProbe) ->Field("editorMode", &EditorDiffuseProbeGridComponent::m_editorMode) ->Field("runtimeMode", &EditorDiffuseProbeGridComponent::m_runtimeMode) ; @@ -93,6 +94,9 @@ namespace AZ ->Attribute(Edit::Attributes::Step, 0.1f) ->Attribute(Edit::Attributes::Min, 0.0f) ->Attribute(Edit::Attributes::Max, 1.0f) + ->DataElement(AZ::Edit::UIHandlers::ComboBox, &EditorDiffuseProbeGridComponent::m_numRaysPerProbe, "Number of Rays Per Probe", "Number of rays cast by each probe to detect lighting in its surroundings") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorDiffuseProbeGridComponent::OnNumRaysPerProbeChanged) + ->Attribute(AZ::Edit::Attributes::EnumValues, &EditorDiffuseProbeGridComponent::GetNumRaysPerProbeEnumList) ->ClassElement(AZ::Edit::ClassElements::EditorData, "Grid mode") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(Edit::UIHandlers::ComboBox, &EditorDiffuseProbeGridComponent::m_editorMode, "Editor Mode", "Controls whether the editor uses RealTime or Baked diffuse GI. RealTime requires a ray-tracing capable GPU. Auto-Select will fallback to Baked if ray-tracing is not available") @@ -216,6 +220,19 @@ namespace AZ } } + AZStd::vector> EditorDiffuseProbeGridComponent::GetNumRaysPerProbeEnumList() const + { + AZStd::vector> enumList; + + for (uint32_t index = 0; index < DiffuseProbeGridNumRaysPerProbeArraySize; ++index) + { + const DiffuseProbeGridNumRaysPerProbeEntry& entry = DiffuseProbeGridNumRaysPerProbeArray[index]; + enumList.push_back(Edit::EnumConstant(entry.m_enum, AZStd::to_string(entry.m_rayCount).c_str())); + } + + return enumList; + } + AZ::Aabb EditorDiffuseProbeGridComponent::GetEditorSelectionBoundsViewport([[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo) { return m_controller.GetAabb(); @@ -313,6 +330,12 @@ namespace AZ return AZ::Edit::PropertyRefreshLevels::None; } + AZ::u32 EditorDiffuseProbeGridComponent::OnNumRaysPerProbeChanged() + { + m_controller.SetNumRaysPerProbe(m_numRaysPerProbe); + return AZ::Edit::PropertyRefreshLevels::None; + } + AZ::u32 EditorDiffuseProbeGridComponent::OnEditorModeChanged() { // this will update the configuration and also change the DiffuseProbeGrid mode diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.h index ba5693b022..c7832902a8 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/EditorDiffuseProbeGridComponent.h @@ -56,6 +56,7 @@ namespace AZ AZStd::string ValidateOrCreateNewTexturePath(const AZStd::string& relativePath, const char* fileSuffix); void CheckoutSourceTextureFile(const AZStd::string& fullPath); void CheckTextureAssetNotification(const AZStd::string& relativePath, Data::Asset& configurationAsset); + AZStd::vector> GetNumRaysPerProbeEnumList() const; // property change notifications AZ::Outcome OnProbeSpacingValidateX(void* newValue, const AZ::Uuid& valueType); @@ -65,6 +66,7 @@ namespace AZ AZ::u32 OnAmbientMultiplierChanged(); AZ::u32 OnViewBiasChanged(); AZ::u32 OnNormalBiasChanged(); + AZ::u32 OnNumRaysPerProbeChanged(); AZ::u32 OnEditorModeChanged(); AZ::u32 OnRuntimeModeChanged(); AZ::Outcome OnModeChangeValidate(void* newValue, const AZ::Uuid& valueType); @@ -80,6 +82,7 @@ namespace AZ float m_ambientMultiplier = DefaultDiffuseProbeGridAmbientMultiplier; float m_viewBias = DefaultDiffuseProbeGridViewBias; float m_normalBias = DefaultDiffuseProbeGridNormalBias; + DiffuseProbeGridNumRaysPerProbe m_numRaysPerProbe = DefaultDiffuseProbeGridNumRaysPerProbe; DiffuseProbeGridMode m_editorMode = DiffuseProbeGridMode::RealTime; DiffuseProbeGridMode m_runtimeMode = DiffuseProbeGridMode::RealTime; From b3d996ea230ce78293eef87959cebd349d84e6d2 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Thu, 20 Jan 2022 08:32:02 -0800 Subject: [PATCH 038/136] Adding automated test to ensure scripts attached to net-level-entities are started on the server Signed-off-by: Gene Walters --- ...TestLevelEntityComponent.AutoComponent.xml | 15 + ...tworkTestPlayerComponent.AutoComponent.xml | 2 - .../Gem/Code/automatedtesting_files.cmake | 1 + .../Multiplayer/TestSuite_Sandbox.py | 4 + .../Multiplayer_SimpleNetworkLevelEntity.py | 79 +++ .../SimpleNetworkLevelEntity/Player.prefab | 151 +++++ .../SimpleNetworkLevelEntity.prefab | 580 ++++++++++++++++++ .../SimpleNetworkLevelEntity.scriptcanvas | 228 +++++++ .../SimpleNetworkLevelEntity/tags.txt | 12 + 9 files changed, 1070 insertions(+), 2 deletions(-) create mode 100644 AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml create mode 100644 AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py create mode 100644 AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/Player.prefab create mode 100644 AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.prefab create mode 100644 AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.scriptcanvas create mode 100644 AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/tags.txt diff --git a/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml new file mode 100644 index 0000000000..2fd196a2f6 --- /dev/null +++ b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml index 251d2b25af..b4dd35d741 100644 --- a/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml +++ b/AutomatedTesting/Gem/Code/Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml @@ -29,8 +29,6 @@
- - diff --git a/AutomatedTesting/Gem/Code/automatedtesting_files.cmake b/AutomatedTesting/Gem/Code/automatedtesting_files.cmake index eb619104a4..1f6dbbd772 100644 --- a/AutomatedTesting/Gem/Code/automatedtesting_files.cmake +++ b/AutomatedTesting/Gem/Code/automatedtesting_files.cmake @@ -12,4 +12,5 @@ set(FILES Source/AutomatedTestingSystemComponent.cpp Source/AutomatedTestingSystemComponent.h Source/AutoGen/NetworkTestPlayerComponent.AutoComponent.xml + Source/AutoGen/NetworkTestLevelEntityComponent.AutoComponent.xml ) diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Sandbox.py b/AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Sandbox.py index 8c5f33993d..56c2608762 100644 --- a/AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Sandbox.py +++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/TestSuite_Sandbox.py @@ -35,3 +35,7 @@ class TestAutomation(TestAutomationBase): def test_Multiplayer_AutoComponent_RPC(self, request, workspace, editor, launcher_platform): from .tests import Multiplayer_AutoComponent_RPC as test_module self._run_prefab_test(request, workspace, editor, test_module) + + def test_Multiplayer_SimpleNetworkLevelEntity(self, request, workspace, editor, launcher_platform): + from .tests import Multiplayer_SimpleNetworkLevelEntity as test_module + self._run_prefab_test(request, workspace, editor, test_module) diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py new file mode 100644 index 0000000000..da332f9085 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py @@ -0,0 +1,79 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + + +# Test Case Title : Check that level entities with network bindings are properly replicated. +# Note: This test should be ran on a fresh editor run; some bugs with spawnables occur only on the first editor play-mode. + + +# fmt: off +class TestSuccessFailTuples(): + enter_game_mode = ("Entered game mode", "Failed to enter game mode") + exit_game_mode = ("Exited game mode", "Couldn't exit game mode") + find_network_player = ("Found network player", "Couldn't find network player") +# fmt: on + + +def Multiplayer_SimpleNetworkLevelEntity(): + r""" + Summary: + Runs a test to make sure that network entities in a level function and are replicated to clients as expecte + + Level Description: + - Static + 1. NetLevelEntity. This is a networked entity which has a script attached to ensure it's replicated. + + + Expected Outcome: + We should see logs stating that the net-sync'd level entity exists on both server and client. + + :return: + """ + import azlmbr.legacy.general as general + from editor_python_test_tools.utils import Report + from editor_python_test_tools.utils import Tracer + + from editor_python_test_tools.utils import TestHelper as helper + from ly_remote_console.remote_console_commands import RemoteConsole as RemoteConsole + + level_name = "SimpleNetworkLevelEntity" + player_prefab_name = "Player" + player_prefab_path = f"levels/multiplayer/{level_name}/{player_prefab_name}.network.spawnable" + + helper.init_idle() + + # 1) Open Level + helper.open_level("Multiplayer", level_name) + + with Tracer() as section_tracer: + # 2) Enter game mode + helper.multiplayer_enter_game_mode(TestSuccessFailTuples.enter_game_mode, player_prefab_path.lower()) + + # 3) Make sure the network player was spawned + player_id = general.find_game_entity(player_prefab_name) + Report.critical_result(TestSuccessFailTuples.find_network_player, player_id.IsValid()) + + # 4) Check the editor logs for network spawnable errors + ATTEMPTING_INVALID_NETSPAWN_WAIT_TIME_SECONDS = 1.0 # The editor will try to net-spawn its networked level entity before it's even a client. Make sure this doesn't happen. + helper.fail_if_log_line_found('NetworkEntityManager', "RequestNetSpawnableInstantiation: Requested spawnable Root.network.spawnable doesn't exist in the NetworkSpawnableLibrary. Please make sure it is a network spawnable", section_tracer.errors, ATTEMPTING_INVALID_NETSPAWN_WAIT_TIME_SECONDS) + + # 5) Ensure the script graph attached to the level entity is running on both client and server + SCRIPTGRAPH_ENABLED_WAIT_TIME_SECONDS = 0.25 + # Check Server + helper.succeed_if_log_line_found('EditorServer', "Script: SimpleNetworkLevelEntity: On Graph Start", section_tracer.prints, SCRIPTGRAPH_ENABLED_WAIT_TIME_SECONDS) + # Check Editor/Client (Uncomment once script asset preload is working properly LYN-9136) + # helper.succeed_if_log_line_found('Script', "SimpleNetworkLevelEntity: On Graph Start", section_tracer.prints, SCRIPTGRAPH_ENABLED_WAIT_TIME_SECONDS) # Client + + + # Exit game mode + helper.exit_game_mode(TestSuccessFailTuples.exit_game_mode) + + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + Report.start_test(Multiplayer_SimpleNetworkLevelEntity) diff --git a/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/Player.prefab b/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/Player.prefab new file mode 100644 index 0000000000..975319a516 --- /dev/null +++ b/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/Player.prefab @@ -0,0 +1,151 @@ +{ + "ContainerEntity": { + "Id": "ContainerEntity", + "Name": "Player", + "Components": { + "Component_[10626669441604518614]": { + "$type": "EditorPrefabComponent", + "Id": 10626669441604518614 + }, + "Component_[15284109105474306026]": { + "$type": "EditorVisibilityComponent", + "Id": 15284109105474306026 + }, + "Component_[1884250773831675865]": { + "$type": "SelectionComponent", + "Id": 1884250773831675865 + }, + "Component_[3027124663594865592]": { + "$type": "EditorInspectorComponent", + "Id": 3027124663594865592 + }, + "Component_[3314300526416851038]": { + "$type": "EditorEntitySortComponent", + "Id": 3314300526416851038, + "Child Entity Order": [ + "Entity_[1340484004600]" + ] + }, + "Component_[5583377204116393478]": { + "$type": "EditorEntityIconComponent", + "Id": 5583377204116393478 + }, + "Component_[5897955848881060165]": { + "$type": "EditorLockComponent", + "Id": 5897955848881060165 + }, + "Component_[6405389103180201977]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 6405389103180201977, + "Parent Entity": "" + }, + "Component_[7695912346724202125]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 7695912346724202125 + }, + "Component_[775363990560391238]": { + "$type": "EditorOnlyEntityComponent", + "Id": 775363990560391238 + }, + "Component_[904355854135646057]": { + "$type": "EditorPendingCompositionComponent", + "Id": 904355854135646057 + } + } + }, + "Entities": { + "Entity_[1340484004600]": { + "Id": "Entity_[1340484004600]", + "Name": "Player", + "Components": { + "Component_[12294726333564087591]": { + "$type": "SelectionComponent", + "Id": 12294726333564087591 + }, + "Component_[13587084088242540786]": { + "$type": "EditorInspectorComponent", + "Id": 13587084088242540786, + "ComponentOrderEntryArray": [ + { + "ComponentId": 6819443882832501114 + }, + { + "ComponentId": 4337571454344109612, + "SortIndex": 1 + }, + { + "ComponentId": 16457408099527309065, + "SortIndex": 2 + }, + { + "ComponentId": 5577505593558922067, + "SortIndex": 3 + } + ] + }, + "Component_[14335168881008289852]": { + "$type": "EditorEntitySortComponent", + "Id": 14335168881008289852 + }, + "Component_[16308902899170829847]": { + "$type": "EditorVisibilityComponent", + "Id": 16308902899170829847 + }, + "Component_[16457408099527309065]": { + "$type": "GenericComponentWrapper", + "Id": 16457408099527309065, + "m_template": { + "$type": "Multiplayer::NetworkTransformComponent" + } + }, + "Component_[16541569566865026527]": { + "$type": "EditorOnlyEntityComponent", + "Id": 16541569566865026527 + }, + "Component_[2002761223483048905]": { + "$type": "EditorPendingCompositionComponent", + "Id": 2002761223483048905 + }, + "Component_[4337571454344109612]": { + "$type": "GenericComponentWrapper", + "Id": 4337571454344109612, + "m_template": { + "$type": "NetBindComponent" + } + }, + "Component_[477591477979440744]": { + "$type": "EditorLockComponent", + "Id": 477591477979440744 + }, + "Component_[5577505593558922067]": { + "$type": "AZ::Render::EditorMeshComponent", + "Id": 5577505593558922067, + "Controller": { + "Configuration": { + "ModelAsset": { + "assetId": { + "guid": "{6DE0E9A8-A1C7-5D0F-9407-4E627C1F223C}", + "subId": 284780167 + }, + "assetHint": "models/sphere.azmodel" + } + } + } + }, + "Component_[5828214869455694702]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 5828214869455694702 + }, + "Component_[6819443882832501114]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 6819443882832501114, + "Parent Entity": "ContainerEntity" + }, + "Component_[8838623765985560328]": { + "$type": "EditorEntityIconComponent", + "Id": 8838623765985560328 + } + } + } + } +} \ No newline at end of file diff --git a/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.prefab b/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.prefab new file mode 100644 index 0000000000..abe458246a --- /dev/null +++ b/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.prefab @@ -0,0 +1,580 @@ +{ + "ContainerEntity": { + "Id": "Entity_[1146574390643]", + "Name": "Level", + "Components": { + "Component_[10641544592923449938]": { + "$type": "EditorInspectorComponent", + "Id": 10641544592923449938 + }, + "Component_[12039882709170782873]": { + "$type": "EditorOnlyEntityComponent", + "Id": 12039882709170782873 + }, + "Component_[12265484671603697631]": { + "$type": "EditorPendingCompositionComponent", + "Id": 12265484671603697631 + }, + "Component_[14126657869720434043]": { + "$type": "EditorEntitySortComponent", + "Id": 14126657869720434043, + "Child Entity Order": [ + "Entity_[1176639161715]", + "Entity_[806656324666]" + ] + }, + "Component_[15230859088967841193]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 15230859088967841193, + "Parent Entity": "" + }, + "Component_[16239496886950819870]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 16239496886950819870 + }, + "Component_[5688118765544765547]": { + "$type": "EditorEntityIconComponent", + "Id": 5688118765544765547 + }, + "Component_[6545738857812235305]": { + "$type": "SelectionComponent", + "Id": 6545738857812235305 + }, + "Component_[7247035804068349658]": { + "$type": "EditorPrefabComponent", + "Id": 7247035804068349658 + }, + "Component_[9307224322037797205]": { + "$type": "EditorLockComponent", + "Id": 9307224322037797205 + }, + "Component_[9562516168917670048]": { + "$type": "EditorVisibilityComponent", + "Id": 9562516168917670048 + } + } + }, + "Entities": { + "Entity_[1155164325235]": { + "Id": "Entity_[1155164325235]", + "Name": "Sun", + "Components": { + "Component_[10440557478882592717]": { + "$type": "SelectionComponent", + "Id": 10440557478882592717 + }, + "Component_[13620450453324765907]": { + "$type": "EditorLockComponent", + "Id": 13620450453324765907 + }, + "Component_[2134313378593666258]": { + "$type": "EditorInspectorComponent", + "Id": 2134313378593666258 + }, + "Component_[234010807770404186]": { + "$type": "EditorVisibilityComponent", + "Id": 234010807770404186 + }, + "Component_[2970359110423865725]": { + "$type": "EditorEntityIconComponent", + "Id": 2970359110423865725 + }, + "Component_[3722854130373041803]": { + "$type": "EditorOnlyEntityComponent", + "Id": 3722854130373041803 + }, + "Component_[5992533738676323195]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 5992533738676323195 + }, + "Component_[7378860763541895402]": { + "$type": "AZ::Render::EditorDirectionalLightComponent", + "Id": 7378860763541895402, + "Controller": { + "Configuration": { + "Intensity": 1.0, + "CameraEntityId": "", + "ShadowFilterMethod": 1 + } + } + }, + "Component_[7892834440890947578]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 7892834440890947578, + "Parent Entity": "Entity_[1176639161715]", + "Transform Data": { + "Translate": [ + 0.0, + 0.0, + 13.487043380737305 + ], + "Rotate": [ + -76.13099670410156, + -0.847000002861023, + -15.8100004196167 + ] + } + }, + "Component_[8599729549570828259]": { + "$type": "EditorEntitySortComponent", + "Id": 8599729549570828259 + }, + "Component_[952797371922080273]": { + "$type": "EditorPendingCompositionComponent", + "Id": 952797371922080273 + } + } + }, + "Entity_[1159459292531]": { + "Id": "Entity_[1159459292531]", + "Name": "Ground", + "Components": { + "Component_[11701138785793981042]": { + "$type": "SelectionComponent", + "Id": 11701138785793981042 + }, + "Component_[12260880513256986252]": { + "$type": "EditorEntityIconComponent", + "Id": 12260880513256986252 + }, + "Component_[13711420870643673468]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 13711420870643673468 + }, + "Component_[138002849734991713]": { + "$type": "EditorOnlyEntityComponent", + "Id": 138002849734991713 + }, + "Component_[16578565737331764849]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 16578565737331764849, + "Parent Entity": "Entity_[1176639161715]" + }, + "Component_[16919232076966545697]": { + "$type": "EditorInspectorComponent", + "Id": 16919232076966545697 + }, + "Component_[5182430712893438093]": { + "$type": "EditorMaterialComponent", + "Id": 5182430712893438093 + }, + "Component_[5675108321710651991]": { + "$type": "AZ::Render::EditorMeshComponent", + "Id": 5675108321710651991, + "Controller": { + "Configuration": { + "ModelAsset": { + "assetId": { + "guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}", + "subId": 277889906 + }, + "assetHint": "objects/groudplane/groundplane_512x512m.azmodel" + } + } + } + }, + "Component_[5681893399601237518]": { + "$type": "EditorEntitySortComponent", + "Id": 5681893399601237518 + }, + "Component_[592692962543397545]": { + "$type": "EditorPendingCompositionComponent", + "Id": 592692962543397545 + }, + "Component_[7090012899106946164]": { + "$type": "EditorLockComponent", + "Id": 7090012899106946164 + }, + "Component_[9410832619875640998]": { + "$type": "EditorVisibilityComponent", + "Id": 9410832619875640998 + } + } + }, + "Entity_[1163754259827]": { + "Id": "Entity_[1163754259827]", + "Name": "Camera", + "Components": { + "Component_[11895140916889160460]": { + "$type": "EditorEntityIconComponent", + "Id": 11895140916889160460 + }, + "Component_[16880285896855930892]": { + "$type": "{CA11DA46-29FF-4083-B5F6-E02C3A8C3A3D} EditorCameraComponent", + "Id": 16880285896855930892, + "Controller": { + "Configuration": { + "Field of View": 55.0, + "EditorEntityId": 9021008456353177945 + } + } + }, + "Component_[17187464423780271193]": { + "$type": "EditorLockComponent", + "Id": 17187464423780271193 + }, + "Component_[17495696818315413311]": { + "$type": "EditorEntitySortComponent", + "Id": 17495696818315413311 + }, + "Component_[18086214374043522055]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 18086214374043522055, + "Parent Entity": "Entity_[1176639161715]", + "Transform Data": { + "Translate": [ + -2.3000001907348633, + -3.9368600845336914, + 1.0 + ], + "Rotate": [ + -2.050307512283325, + 1.9552897214889526, + -43.623355865478516 + ] + } + }, + "Component_[18387556550380114975]": { + "$type": "SelectionComponent", + "Id": 18387556550380114975 + }, + "Component_[2654521436129313160]": { + "$type": "EditorVisibilityComponent", + "Id": 2654521436129313160 + }, + "Component_[5265045084611556958]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 5265045084611556958 + }, + "Component_[7169798125182238623]": { + "$type": "EditorPendingCompositionComponent", + "Id": 7169798125182238623 + }, + "Component_[7255796294953281766]": { + "$type": "GenericComponentWrapper", + "Id": 7255796294953281766, + "m_template": { + "$type": "FlyCameraInputComponent" + } + }, + "Component_[8866210352157164042]": { + "$type": "EditorInspectorComponent", + "Id": 8866210352157164042 + }, + "Component_[9129253381063760879]": { + "$type": "EditorOnlyEntityComponent", + "Id": 9129253381063760879 + } + } + }, + "Entity_[1168049227123]": { + "Id": "Entity_[1168049227123]", + "Name": "Grid", + "Components": { + "Component_[11443347433215807130]": { + "$type": "EditorEntityIconComponent", + "Id": 11443347433215807130 + }, + "Component_[11779275529534764488]": { + "$type": "SelectionComponent", + "Id": 11779275529534764488 + }, + "Component_[14249419413039427459]": { + "$type": "EditorInspectorComponent", + "Id": 14249419413039427459 + }, + "Component_[15448581635946161318]": { + "$type": "AZ::Render::EditorGridComponent", + "Id": 15448581635946161318, + "Controller": { + "Configuration": { + "primarySpacing": 4.0, + "primaryColor": [ + 0.501960813999176, + 0.501960813999176, + 0.501960813999176 + ], + "secondarySpacing": 0.5, + "secondaryColor": [ + 0.250980406999588, + 0.250980406999588, + 0.250980406999588 + ] + } + } + }, + "Component_[1843303322527297409]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 1843303322527297409 + }, + "Component_[380249072065273654]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 380249072065273654, + "Parent Entity": "Entity_[1176639161715]" + }, + "Component_[7476660583684339787]": { + "$type": "EditorPendingCompositionComponent", + "Id": 7476660583684339787 + }, + "Component_[7557626501215118375]": { + "$type": "EditorEntitySortComponent", + "Id": 7557626501215118375 + }, + "Component_[7984048488947365511]": { + "$type": "EditorVisibilityComponent", + "Id": 7984048488947365511 + }, + "Component_[8118181039276487398]": { + "$type": "EditorOnlyEntityComponent", + "Id": 8118181039276487398 + }, + "Component_[9189909764215270515]": { + "$type": "EditorLockComponent", + "Id": 9189909764215270515 + } + } + }, + "Entity_[1176639161715]": { + "Id": "Entity_[1176639161715]", + "Name": "Atom Default Environment", + "Components": { + "Component_[10757302973393310045]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 10757302973393310045, + "Parent Entity": "Entity_[1146574390643]" + }, + "Component_[14505817420424255464]": { + "$type": "EditorInspectorComponent", + "Id": 14505817420424255464, + "ComponentOrderEntryArray": [ + { + "ComponentId": 10757302973393310045 + } + ] + }, + "Component_[14988041764659020032]": { + "$type": "EditorLockComponent", + "Id": 14988041764659020032 + }, + "Component_[15808690248755038124]": { + "$type": "SelectionComponent", + "Id": 15808690248755038124 + }, + "Component_[15900837685796817138]": { + "$type": "EditorVisibilityComponent", + "Id": 15900837685796817138 + }, + "Component_[3298767348226484884]": { + "$type": "EditorOnlyEntityComponent", + "Id": 3298767348226484884 + }, + "Component_[4076975109609220594]": { + "$type": "EditorPendingCompositionComponent", + "Id": 4076975109609220594 + }, + "Component_[5679760548946028854]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 5679760548946028854 + }, + "Component_[5855590796136709437]": { + "$type": "EditorEntitySortComponent", + "Id": 5855590796136709437, + "Child Entity Order": [ + "Entity_[1155164325235]", + "Entity_[1180934129011]", + "Entity_[1168049227123]", + "Entity_[1163754259827]", + "Entity_[1159459292531]" + ] + }, + "Component_[9277695270015777859]": { + "$type": "EditorEntityIconComponent", + "Id": 9277695270015777859 + } + } + }, + "Entity_[1180934129011]": { + "Id": "Entity_[1180934129011]", + "Name": "Global Sky", + "Components": { + "Component_[11231930600558681245]": { + "$type": "AZ::Render::EditorHDRiSkyboxComponent", + "Id": 11231930600558681245, + "Controller": { + "Configuration": { + "CubemapAsset": { + "assetId": { + "guid": "{215E47FD-D181-5832-B1AB-91673ABF6399}", + "subId": 1000 + }, + "assetHint": "lightingpresets/highcontrast/goegap_4k_skyboxcm.exr.streamingimage" + } + } + } + }, + "Component_[11980494120202836095]": { + "$type": "SelectionComponent", + "Id": 11980494120202836095 + }, + "Component_[1428633914413949476]": { + "$type": "EditorLockComponent", + "Id": 1428633914413949476 + }, + "Component_[14936200426671614999]": { + "$type": "AZ::Render::EditorImageBasedLightComponent", + "Id": 14936200426671614999, + "Controller": { + "Configuration": { + "diffuseImageAsset": { + "assetId": { + "guid": "{3FD09945-D0F2-55C8-B9AF-B2FD421FE3BE}", + "subId": 3000 + }, + "assetHint": "lightingpresets/highcontrast/goegap_4k_iblglobalcm_ibldiffuse.exr.streamingimage" + }, + "specularImageAsset": { + "assetId": { + "guid": "{3FD09945-D0F2-55C8-B9AF-B2FD421FE3BE}", + "subId": 2000 + }, + "assetHint": "lightingpresets/highcontrast/goegap_4k_iblglobalcm_iblspecular.exr.streamingimage" + } + } + } + }, + "Component_[14994774102579326069]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 14994774102579326069 + }, + "Component_[15417479889044493340]": { + "$type": "EditorPendingCompositionComponent", + "Id": 15417479889044493340 + }, + "Component_[15826613364991382688]": { + "$type": "EditorEntitySortComponent", + "Id": 15826613364991382688 + }, + "Component_[1665003113283562343]": { + "$type": "EditorOnlyEntityComponent", + "Id": 1665003113283562343 + }, + "Component_[3704934735944502280]": { + "$type": "EditorEntityIconComponent", + "Id": 3704934735944502280 + }, + "Component_[5698542331457326479]": { + "$type": "EditorVisibilityComponent", + "Id": 5698542331457326479 + }, + "Component_[6644513399057217122]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 6644513399057217122, + "Parent Entity": "Entity_[1176639161715]" + }, + "Component_[931091830724002070]": { + "$type": "EditorInspectorComponent", + "Id": 931091830724002070 + } + } + }, + "Entity_[806656324666]": { + "Id": "Entity_[806656324666]", + "Name": "NetEntity", + "Components": { + "Component_[10272449525230713408]": { + "$type": "EditorScriptCanvasComponent", + "Id": 10272449525230713408, + "m_name": "SimpleNetworkLevelEntity.scriptcanvas", + "runtimeDataIsValid": true, + "runtimeDataOverrides": { + "source": { + "id": "{C8F17F94-1225-5FFB-A89F-7C5546FF9DD2}", + "path": "C:/prj/o3de/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.scriptcanvas" + } + }, + "sourceHandle": { + "id": "{C8F17F94-1225-5FFB-A89F-7C5546FF9DD2}", + "path": "C:/prj/o3de/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.scriptcanvas" + } + }, + "Component_[12604265186664827718]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 12604265186664827718 + }, + "Component_[12971088454284742740]": { + "$type": "EditorInspectorComponent", + "Id": 12971088454284742740 + }, + "Component_[13637345797899267673]": { + "$type": "EditorPendingCompositionComponent", + "Id": 13637345797899267673 + }, + "Component_[14691827217729577086]": { + "$type": "EditorVisibilityComponent", + "Id": 14691827217729577086 + }, + "Component_[17587769654029626028]": { + "$type": "AZ::Render::EditorMeshComponent", + "Id": 17587769654029626028, + "Controller": { + "Configuration": { + "ModelAsset": { + "assetId": { + "guid": "{6DE0E9A8-A1C7-5D0F-9407-4E627C1F223C}", + "subId": 284780167 + }, + "assetHint": "models/sphere.azmodel" + } + } + } + }, + "Component_[3583806849894952953]": { + "$type": "EditorOnlyEntityComponent", + "Id": 3583806849894952953 + }, + "Component_[3992057042487734240]": { + "$type": "EditorLockComponent", + "Id": 3992057042487734240 + }, + "Component_[4205899043279271481]": { + "$type": "GenericComponentWrapper", + "Id": 4205899043279271481, + "m_template": { + "$type": "Multiplayer::NetworkTransformComponent" + } + }, + "Component_[4416976521140638764]": { + "$type": "EditorEntityIconComponent", + "Id": 4416976521140638764 + }, + "Component_[4951162661196722987]": { + "$type": "EditorEntitySortComponent", + "Id": 4951162661196722987 + }, + "Component_[57491843687005111]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 57491843687005111, + "Parent Entity": "Entity_[1146574390643]", + "Transform Data": { + "Translate": [ + -0.010266244411468506, + 0.09999752044677734, + 0.4922151565551758 + ] + } + }, + "Component_[7427201282284088219]": { + "$type": "SelectionComponent", + "Id": 7427201282284088219 + }, + "Component_[9767802049284917261]": { + "$type": "GenericComponentWrapper", + "Id": 9767802049284917261, + "m_template": { + "$type": "NetBindComponent" + } + } + } + } + } +} \ No newline at end of file diff --git a/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.scriptcanvas b/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.scriptcanvas new file mode 100644 index 0000000000..7f41ed9af2 --- /dev/null +++ b/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/SimpleNetworkLevelEntity.scriptcanvas @@ -0,0 +1,228 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "ScriptCanvasData", + "ClassData": { + "m_scriptCanvas": { + "Id": { + "id": 5227099818161821361 + }, + "Name": "Script Canvas Graph", + "Components": { + "Component_[14745706451564425001]": { + "$type": "EditorGraphVariableManagerComponent", + "Id": 14745706451564425001 + }, + "Component_[6188351434280490877]": { + "$type": "EditorGraph", + "Id": 6188351434280490877, + "m_graphData": { + "m_nodes": [ + { + "Id": { + "id": 1181151842701 + }, + "Name": "SC-Node(Print)", + "Components": { + "Component_[11204048151736284490]": { + "$type": "Print", + "Id": 11204048151736284490, + "Slots": [ + { + "id": { + "m_id": "{A417FF98-493E-4DE6-AD3A-E7A1848661E4}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "In", + "toolTip": "Input signal", + "Descriptor": { + "ConnectionType": 1, + "SlotType": 1 + } + }, + { + "id": { + "m_id": "{38BC2AB1-7654-407E-9903-4B5D77EDB6F3}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + } + ], + "m_format": "SimpleNetworkLevelEntity: On Graph Start\n", + "m_unresolvedString": [ + "SimpleNetworkLevelEntity: On Graph Start\n" + ] + } + } + }, + { + "Id": { + "id": 811784655245 + }, + "Name": "SC-Node(Start)", + "Components": { + "Component_[2986280341871382503]": { + "$type": "Start", + "Id": 2986280341871382503, + "Slots": [ + { + "id": { + "m_id": "{61FBEFC6-23BA-4A53-89BF-D0D0E834608C}" + }, + "contracts": [ + { + "$type": "SlotTypeContract" + } + ], + "slotName": "Out", + "toolTip": "Signaled when the entity that owns this graph is fully activated.", + "Descriptor": { + "ConnectionType": 2, + "SlotType": 1 + } + } + ] + } + } + } + ], + "m_connections": [ + { + "Id": { + "id": 2521181639053 + }, + "Name": "srcEndpoint=(On Graph Start: Out), destEndpoint=(Print: In)", + "Components": { + "Component_[16295428600276205051]": { + "$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection", + "Id": 16295428600276205051, + "sourceEndpoint": { + "nodeId": { + "id": 811784655245 + }, + "slotId": { + "m_id": "{61FBEFC6-23BA-4A53-89BF-D0D0E834608C}" + } + }, + "targetEndpoint": { + "nodeId": { + "id": 1181151842701 + }, + "slotId": { + "m_id": "{A417FF98-493E-4DE6-AD3A-E7A1848661E4}" + } + } + } + } + } + ] + }, + "m_assetType": "{00000000-0000-0000-D033-B2489A010000}", + "versionData": { + "_grammarVersion": 1, + "_runtimeVersion": 1, + "_fileVersion": 1 + }, + "GraphCanvasData": [ + { + "Key": { + "id": 811784655245 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "TimeNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 340.0, + 180.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{6045F7F7-02B0-442A-96C7-A0CBCEFF7275}" + } + } + } + }, + { + "Key": { + "id": 1181151842701 + }, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "StringNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 580.0, + 180.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{589F773E-D82A-4EDD-AEBD-3ADC07FC67CE}" + } + } + } + }, + { + "Key": { + "id": 5227099818161821361 + }, + "Value": { + "ComponentData": { + "{5F84B500-8C45-40D1-8EFC-A5306B241444}": { + "$type": "SceneComponentSaveData" + } + } + } + } + ], + "StatisticsHelper": { + "InstanceCounter": [ + { + "Key": 4199610336680704683, + "Value": 1 + }, + { + "Key": 10684225535275896474, + "Value": 1 + } + ] + } + } + } + } + } +} \ No newline at end of file diff --git a/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/tags.txt b/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/tags.txt new file mode 100644 index 0000000000..0d6c1880e7 --- /dev/null +++ b/AutomatedTesting/Levels/Multiplayer/SimpleNetworkLevelEntity/tags.txt @@ -0,0 +1,12 @@ +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 From 3c879d59676d513da30b40df9fb8c3abeab0f2e6 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Thu, 20 Jan 2022 08:45:35 -0800 Subject: [PATCH 039/136] fix pytest typos Signed-off-by: Gene Walters --- .../Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py index da332f9085..aadf12d7e3 100644 --- a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py +++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py @@ -21,11 +21,11 @@ class TestSuccessFailTuples(): def Multiplayer_SimpleNetworkLevelEntity(): r""" Summary: - Runs a test to make sure that network entities in a level function and are replicated to clients as expecte + Test to make sure that network entities in a level function and are replicated to clients as expected Level Description: - Static - 1. NetLevelEntity. This is a networked entity which has a script attached to ensure it's replicated. + 1. NetLevelEntity. This is a networked entity which has a script attached which prints logs to ensure it's replicated. Expected Outcome: From c31e3c020898816b1a2eee355af202e7c952c56c Mon Sep 17 00:00:00 2001 From: Sergey Pereslavtsev Date: Thu, 20 Jan 2022 19:36:33 +0000 Subject: [PATCH 040/136] LYN-7640 Terrain Physics Materials hooked up all the way down to PhysX Signed-off-by: Sergey Pereslavtsev --- .../EditorHeightfieldColliderComponent.cpp | 3 + .../Source/HeightfieldColliderComponent.cpp | 4 + Gems/PhysX/Code/Source/Utils.cpp | 132 ++++++----- Gems/PhysX/Code/Source/Utils.h | 7 + ...ditorHeightfieldColliderComponentTests.cpp | 208 ++++++++++++++++-- Gems/PhysX/Code/Tests/EditorTestUtilities.cpp | 18 ++ Gems/PhysX/Code/Tests/EditorTestUtilities.h | 3 + 7 files changed, 302 insertions(+), 73 deletions(-) diff --git a/Gems/PhysX/Code/Source/EditorHeightfieldColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorHeightfieldColliderComponent.cpp index fb0a38fa18..c6def5f0ab 100644 --- a/Gems/PhysX/Code/Source/EditorHeightfieldColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorHeightfieldColliderComponent.cpp @@ -189,6 +189,9 @@ namespace PhysX configuration.m_entityId = GetEntityId(); configuration.m_debugName = GetEntity()->GetName(); + // Update material selection from the mapping + Utils::SetMaterialsFromHeightfieldProvider(GetEntityId(), m_colliderConfig.m_materialSelection); + AzPhysics::ShapeColliderPairList colliderShapePairs; colliderShapePairs.emplace_back(AZStd::make_shared(m_colliderConfig), m_shapeConfig); configuration.m_colliderAndShapeData = colliderShapePairs; diff --git a/Gems/PhysX/Code/Source/HeightfieldColliderComponent.cpp b/Gems/PhysX/Code/Source/HeightfieldColliderComponent.cpp index c1fa09f21f..b219253b6f 100644 --- a/Gems/PhysX/Code/Source/HeightfieldColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/HeightfieldColliderComponent.cpp @@ -140,6 +140,10 @@ namespace PhysX Physics::HeightfieldShapeConfiguration& configuration = static_cast(*m_shapeConfig.second); configuration = Utils::CreateHeightfieldShapeConfiguration(GetEntityId()); + + // Update material selection from the mapping + Physics::ColliderConfiguration* colliderConfig = m_shapeConfig.first.get(); + Utils::SetMaterialsFromHeightfieldProvider(GetEntityId(), colliderConfig->m_materialSelection); } void HeightfieldColliderComponent::RefreshHeightfield() diff --git a/Gems/PhysX/Code/Source/Utils.cpp b/Gems/PhysX/Code/Source/Utils.cpp index fecea57d9c..a988f6791c 100644 --- a/Gems/PhysX/Code/Source/Utils.cpp +++ b/Gems/PhysX/Code/Source/Utils.cpp @@ -66,6 +66,67 @@ namespace PhysX } } + AZStd::pair GetPhysXMaterialIndicesFromHeightfieldSamples( + const AZStd::vector& samples, + const int32_t row, const int32_t col, + const int32_t numRows, const int32_t numCols) + { + + uint8_t materialIndex0 = 0; + uint8_t materialIndex1 = 0; + + const bool lastRowIndex = (row == (numRows - 1)); + const bool lastColumnIndex = (col == (numCols - 1)); + + // In PhysX, the material indices refer to the quad down and to the right of the sample. + // If we're in the last row or last column, there aren't any quads down or to the right, + // so just clear these out. + + if (!lastRowIndex && !lastColumnIndex) + { + auto GetIndex = [numCols](int32_t row, int32_t col) + { + return (row * numCols) + col; + }; + + // Our source data is providing one material index per vertex, but PhysX wants one material index + // per triangle. The heuristic that we'll go with for selecting the material index is to choose + // the material for the vertex that's not on the diagonal of each triangle. + // Ex: A *---* B + // | / | For this, we'll use A for index0 and D for index1. + // C *---* D + // + // Ex: A *---* B + // | \ | For this, we'll use C for index0 and B for index1. + // C *---* D + // + // This is a pretty arbitrary choice, so the heuristic might need to be revisited over time if this + // causes incorrect or unpredictable physics material mappings. + + const Physics::HeightMaterialPoint& currentSample = samples[GetIndex(row, col)]; + + switch (currentSample.m_quadMeshType) + { + case Physics::QuadMeshType::SubdivideUpperLeftToBottomRight: + materialIndex0 = samples[GetIndex(row + 1, col)].m_materialIndex; + materialIndex1 = samples[GetIndex(row, col + 1)].m_materialIndex; + break; + case Physics::QuadMeshType::SubdivideBottomLeftToUpperRight: + materialIndex0 = currentSample.m_materialIndex; + materialIndex1 = samples[GetIndex(row + 1, col + 1)].m_materialIndex; + break; + case Physics::QuadMeshType::Hole: + materialIndex0 = physx::PxHeightFieldMaterial::eHOLE; + materialIndex1 = physx::PxHeightFieldMaterial::eHOLE; + break; + default: + AZ_Assert(false, "Unhandled case in GetPhysXMaterialIndicesFromHeightfieldSamples"); + break; + } + } + return { materialIndex0, materialIndex1 }; + } + void CreatePxGeometryFromHeightfield( Physics::HeightfieldShapeConfiguration& heightfieldConfig, physx::PxGeometryHolder& pxGeometry) { @@ -116,12 +177,8 @@ namespace PhysX for (int32_t row = 0; row < numRows; row++) { - const bool lastRowIndex = (row == (numRows - 1)); - for (int32_t col = 0; col < numCols; col++) { - const bool lastColumnIndex = (col == (numCols - 1)); - auto GetIndex = [numCols](int32_t row, int32_t col) { return (row * numCols) + col; @@ -134,52 +191,15 @@ namespace PhysX AZ_Assert(currentSample.m_materialIndex < physxMaximumMaterialIndex, "MaterialIndex must be less than 128"); currentPhysxSample.height = azlossy_cast( AZ::GetClamp(currentSample.m_height, minHeightBounds, maxHeightBounds) * scaleFactor); - if (lastRowIndex || lastColumnIndex) - { - // In PhysX, the material indices refer to the quad down and to the right of the sample. - // If we're in the last row or last column, there aren't any quads down or to the right, - // so just clear these out. - currentPhysxSample.materialIndex0 = 0; - currentPhysxSample.materialIndex1 = 0; - } - else - { - // Our source data is providing one material index per vertex, but PhysX wants one material index - // per triangle. The heuristic that we'll go with for selecting the material index is to choose - // the material for the vertex that's not on the diagonal of each triangle. - // Ex: A *---* B - // | / | For this, we'll use A for index0 and D for index1. - // C *---* D - // - // Ex: A *---* B - // | \ | For this, we'll use C for index0 and B for index1. - // C *---* D - // - // This is a pretty arbitrary choice, so the heuristic might need to be revisited over time if this - // causes incorrect or unpredictable physics material mappings. - switch (currentSample.m_quadMeshType) - { - case Physics::QuadMeshType::SubdivideUpperLeftToBottomRight: - currentPhysxSample.materialIndex0 = samples[GetIndex(row + 1, col)].m_materialIndex; - currentPhysxSample.materialIndex1 = samples[GetIndex(row, col + 1)].m_materialIndex; - // Set the tesselation flag to say that we need to go from UL to BR - currentPhysxSample.materialIndex0.setBit(); - break; - case Physics::QuadMeshType::SubdivideBottomLeftToUpperRight: - currentPhysxSample.materialIndex0 = currentSample.m_materialIndex; - currentPhysxSample.materialIndex1 = samples[GetIndex(row + 1, col + 1)].m_materialIndex; - break; - case Physics::QuadMeshType::Hole: - currentPhysxSample.materialIndex0 = physx::PxHeightFieldMaterial::eHOLE; - currentPhysxSample.materialIndex1 = physx::PxHeightFieldMaterial::eHOLE; - break; - default: - AZ_Warning("PhysX Heightfield", false, "Unhandled case in CreatePxGeometryFromConfig"); - currentPhysxSample.materialIndex0 = 0; - currentPhysxSample.materialIndex1 = 0; - break; - } + auto [materialIndex0, materialIndex1] = GetPhysXMaterialIndicesFromHeightfieldSamples(samples, row, col, numRows, numCols); + currentPhysxSample.materialIndex0 = materialIndex0; + currentPhysxSample.materialIndex1 = materialIndex1; + + if (currentSample.m_quadMeshType == Physics::QuadMeshType::SubdivideUpperLeftToBottomRight) + { + // Set the tesselation flag to say that we need to go from UL to BR + currentPhysxSample.setTessFlag(); } } } @@ -1562,6 +1582,20 @@ namespace PhysX return configuration; } + + void SetMaterialsFromHeightfieldProvider(const AZ::EntityId& heightfieldProviderId, Physics::MaterialSelection& materialSelection) + { + AZStd::vector materialList; + Physics::HeightfieldProviderRequestsBus::EventResult( + materialList, heightfieldProviderId, &Physics::HeightfieldProviderRequestsBus::Events::GetMaterialList); + + materialSelection.SetMaterialSlots(Physics::MaterialSelection::SlotsArray(materialList.size(), "")); + + for (int i = 0; i < materialList.size(); ++i) + { + materialSelection.SetMaterialId(materialList[i], i); + } + } } // namespace Utils namespace ReflectionUtils diff --git a/Gems/PhysX/Code/Source/Utils.h b/Gems/PhysX/Code/Source/Utils.h index 525db03315..5244926aa2 100644 --- a/Gems/PhysX/Code/Source/Utils.h +++ b/Gems/PhysX/Code/Source/Utils.h @@ -188,8 +188,15 @@ namespace PhysX //! Returns defaultValue if the input is infinite or NaN, otherwise returns the input unchanged. const AZ::Vector3& Sanitize(const AZ::Vector3& input, const AZ::Vector3& defaultValue = AZ::Vector3::CreateZero()); + AZStd::pair GetPhysXMaterialIndicesFromHeightfieldSamples( + const AZStd::vector& samples, + const int32_t row, const int32_t col, + const int32_t numRows, const int32_t numCols); + Physics::HeightfieldShapeConfiguration CreateHeightfieldShapeConfiguration(AZ::EntityId entityId); + void SetMaterialsFromHeightfieldProvider(const AZ::EntityId& heightfieldProviderId, Physics::MaterialSelection& materialSelection); + namespace Geometry { using PointList = AZStd::vector; diff --git a/Gems/PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp b/Gems/PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp index ef112d8623..9bdc63e60d 100644 --- a/Gems/PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp +++ b/Gems/PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp @@ -19,6 +19,7 @@ #include #include #include +#include using ::testing::NiceMock; using ::testing::Return; @@ -27,18 +28,28 @@ namespace PhysXEditorTests { AZStd::vector GetSamples() { - AZStd::vector samples{ { 3.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight }, - { 2.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight }, - { 1.5f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight }, - { 1.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight }, - { 3.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight }, - { 1.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight }, - { 3.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight }, - { 0.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight }, - { 3.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight } }; + AZStd::vector samples{ { 3.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight, 0 }, + { 2.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight, 1 }, + { 1.5f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight, 2 }, + { 1.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight, 0 }, + { 3.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight, 1 }, + { 1.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight, 2 }, + { 3.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight, 0 }, + { 0.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight, 1 }, + { 3.0f, Physics::QuadMeshType::SubdivideUpperLeftToBottomRight, 2 } }; return samples; } + AZStd::vector GetMaterialList() + { + AZStd::vector materials{ + {Physics::MaterialId::FromUUID("{EC976D51-2C26-4C1E-BBF2-75BAAAFA162C}")}, + {Physics::MaterialId::FromUUID("{B9836F51-A235-4781-95E3-A6302BEE9EFF}")}, + {Physics::MaterialId::FromUUID("{7E060707-BB03-47EB-B046-4503C7145B6E}")} + }; + return materials; + } + EntityPtr SetupHeightfieldComponent() { // create an editor entity with a shape collider component and a box shape component @@ -78,6 +89,7 @@ namespace PhysXEditorTests x = -3.0f; y = 3.0f; }); + ON_CALL(mockShapeRequests, GetMaterialList).WillByDefault(Return(GetMaterialList())); } EntityPtr TestCreateActiveGameEntityFromEditorEntity(AZ::Entity* editorEntity) @@ -89,6 +101,89 @@ namespace PhysXEditorTests return gameEntity; } + class PhysXEditorHeightfieldFixture : public PhysXEditorFixture + { + public: + void SetUp() override + { + PhysXEditorFixture::SetUp(); + PopulateDefaultMaterialLibrary(); + + m_editorEntity = SetupHeightfieldComponent(); + m_editorMockShapeRequests = AZStd::make_unique>(m_editorEntity->GetId()); + SetupMockMethods(*m_editorMockShapeRequests.get()); + m_editorEntity->Activate(); + + m_gameEntity = TestCreateActiveGameEntityFromEditorEntity(m_editorEntity.get()); + m_gameMockShapeRequests = AZStd::make_unique>(m_gameEntity->GetId()); + SetupMockMethods(*m_gameMockShapeRequests.get()); + m_gameEntity->Activate(); + } + + void TearDown() override + { + CleanupHeightfieldComponent(); + + m_editorEntity = nullptr; + m_gameEntity = nullptr; + m_editorMockShapeRequests = nullptr; + m_gameMockShapeRequests = nullptr; + + PhysXEditorFixture::TearDown(); + } + + void PopulateDefaultMaterialLibrary() + { + AZ::Data::AssetId assetId = AZ::Data::AssetId(AZ::Uuid::Create()); + + // Create an asset out of our Script Event + Physics::MaterialLibraryAsset* matLibAsset = aznew Physics::MaterialLibraryAsset; + { + AZStd::vector matIds = GetMaterialList(); + + for (Physics::MaterialId matId : matIds) + { + Physics::MaterialFromAssetConfiguration matConfig; + matConfig.m_id = matId; + matConfig.m_configuration.m_surfaceType = matId.GetUuid().ToString(); + matLibAsset->AddMaterialData(matConfig); + } + } + + // Note: There is no interface to simply update material library asset. It has to go via updating the entire configuration which causes assets reloading. + // It makes sense as a safety mechanism in the Editor but makes it harder to write tests. + // Hence have to work around it via const_cast here to be able to simply set the generated asset into configuration. + AzPhysics::SystemConfiguration* sysConfig = const_cast(AZ::Interface::Get()->GetConfiguration()); + + AZ::Data::Asset assetData(assetId, matLibAsset, AZ::Data::AssetLoadBehavior::Default); + sysConfig->m_materialLibraryAsset = assetData; + } + + Physics::Material* GetMaterialFromRaycast(float x, float y) + { + AzPhysics::RayCastRequest request; + request.m_start = AZ::Vector3(x, y, 5.0f); + request.m_direction = AZ::Vector3(0.0f, 0.0f, -1.0f); + request.m_distance = 10.0f; + + //query the scene + auto* sceneInterface = AZ::Interface::Get(); + AzPhysics::SceneQueryHits result = sceneInterface->QueryScene(m_defaultSceneHandle, &request); + EXPECT_EQ(result.m_hits.size(), 1); + + if (result) + { + return result.m_hits[0].m_material; + } + + return nullptr; + }; + + EntityPtr m_editorEntity; + EntityPtr m_gameEntity; + AZStd::unique_ptr> m_editorMockShapeRequests; + AZStd::unique_ptr> m_gameMockShapeRequests; + }; TEST_F(PhysXEditorFixture, EditorHeightfieldColliderComponentDependenciesSatisfiedEntityIsValid) { @@ -149,21 +244,13 @@ namespace PhysXEditorTests CleanupHeightfieldComponent(); } - TEST_F(PhysXEditorFixture, EditorHeightfieldColliderComponentHeightfieldColliderWithAABoxCorrectRuntimeGeometry) + TEST_F(PhysXEditorHeightfieldFixture, EditorHeightfieldColliderComponentHeightfieldColliderWithAABoxCorrectRuntimeGeometry) { - EntityPtr editorEntity = SetupHeightfieldComponent(); - NiceMock mockShapeRequests(editorEntity->GetId()); - SetupMockMethods(mockShapeRequests); - editorEntity->Activate(); - - EntityPtr gameEntity = TestCreateActiveGameEntityFromEditorEntity(editorEntity.get()); - NiceMock mockShapeRequests2(gameEntity->GetId()); - SetupMockMethods(mockShapeRequests2); - gameEntity->Activate(); + AZ::EntityId gameEntityId = m_gameEntity->GetId(); AzPhysics::SimulatedBody* staticBody = nullptr; AzPhysics::SimulatedBodyComponentRequestsBus::EventResult( - staticBody, gameEntity->GetId(), &AzPhysics::SimulatedBodyComponentRequests::GetSimulatedBody); + staticBody, gameEntityId, &AzPhysics::SimulatedBodyComponentRequests::GetSimulatedBody); const auto* pxRigidStatic = static_cast(staticBody->GetNativePointer()); PHYSX_SCENE_READ_LOCK(pxRigidStatic->getScene()); @@ -183,7 +270,7 @@ namespace PhysXEditorTests int32_t numRows{ 0 }; int32_t numColumns{ 0 }; Physics::HeightfieldProviderRequestsBus::Event( - gameEntity->GetId(), &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldGridSize, numColumns, numRows); + gameEntityId, &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldGridSize, numColumns, numRows); EXPECT_EQ(numColumns, heightfield->getNbColumns()); EXPECT_EQ(numRows, heightfield->getNbRows()); @@ -194,12 +281,12 @@ namespace PhysXEditorTests float minHeightBounds{ 0.0f }; float maxHeightBounds{ 0.0f }; Physics::HeightfieldProviderRequestsBus::Event( - gameEntity->GetId(), &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldHeightBounds, minHeightBounds, + gameEntityId, &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldHeightBounds, minHeightBounds, maxHeightBounds); AZStd::vector samples; Physics::HeightfieldProviderRequestsBus::EventResult( - samples, gameEntity->GetId(), &Physics::HeightfieldProviderRequestsBus::Events::GetHeightsAndMaterials); + samples, gameEntityId, &Physics::HeightfieldProviderRequestsBus::Events::GetHeightsAndMaterials); const float halfBounds{ (maxHeightBounds - minHeightBounds) / 2.0f }; const float scaleFactor = (maxHeightBounds <= minHeightBounds) ? 1.0f : AZStd::numeric_limits::max() / halfBounds; @@ -208,7 +295,80 @@ namespace PhysXEditorTests EXPECT_EQ(samplePhysX.height, azlossy_cast(samplePhysics.m_height * scaleFactor)); } } - CleanupHeightfieldComponent(); + } + + TEST_F(PhysXEditorHeightfieldFixture, EditorHeightfieldColliderComponentHeightfieldColliderCorrectMaterials) + { + AZ::EntityId gameEntityId = m_gameEntity->GetId(); + + int32_t numRows{ 0 }; + int32_t numColumns{ 0 }; + Physics::HeightfieldProviderRequestsBus::Event( + gameEntityId, &Physics::HeightfieldProviderRequestsBus::Events::GetHeightfieldGridSize, numColumns, numRows); + + EXPECT_EQ(numRows, 3); + EXPECT_EQ(numColumns, 3); + + AZStd::vector samples; + Physics::HeightfieldProviderRequestsBus::EventResult( + samples, gameEntityId, &Physics::HeightfieldProviderRequestsBus::Events::GetHeightsAndMaterials); + + AzPhysics::SimulatedBody* staticBody = nullptr; + AzPhysics::SimulatedBodyComponentRequestsBus::EventResult( + staticBody, gameEntityId, &AzPhysics::SimulatedBodyComponentRequests::GetSimulatedBody); + + const auto* pxRigidStatic = static_cast(staticBody->GetNativePointer()); + PHYSX_SCENE_READ_LOCK(pxRigidStatic->getScene()); + + physx::PxShape* shape = nullptr; + pxRigidStatic->getShapes(&shape, 1, 0); + + physx::PxHeightFieldGeometry heightfieldGeometry; + shape->getHeightFieldGeometry(heightfieldGeometry); + + physx::PxHeightField* heightfield = heightfieldGeometry.heightField; + + AZStd::vector physicsSurfaceTypes; + for (Physics::MaterialId materialId : GetMaterialList()) + { + physicsSurfaceTypes.emplace_back(materialId.GetUuid().ToString()); + } + + // PhysX Heightfield cooking doesn't map 1-1 sample material indices to triangle material indices + // Hence hardcoding the expected material indices in the test + const int physicsMaterialsValidationDataIndex[] = {0, 2, 1, 1}; + + for (int sampleRow = 0; sampleRow < numRows; ++sampleRow) + { + for (int sampleColumn = 0; sampleColumn < numColumns; ++sampleColumn) + { + physx::PxHeightFieldSample samplePhysX = heightfield->getSample(sampleRow, sampleColumn); + Physics::HeightMaterialPoint samplePhysics = samples[sampleRow * numColumns + sampleColumn]; + + auto [materialIndex0, materialIndex1] = PhysX::Utils::GetPhysXMaterialIndicesFromHeightfieldSamples(samples, sampleRow, sampleColumn, numRows, numColumns); + EXPECT_EQ(samplePhysX.materialIndex0, materialIndex0); + EXPECT_EQ(samplePhysX.materialIndex1, materialIndex1); + + if (sampleRow != numRows - 1 && sampleColumn != numColumns - 1) + { + const float x_offset = -0.25f; + const float y_offset = 0.75f; + const float secondRayOffset = 0.5f; + + float rayX = x_offset + sampleColumn; + float rayY = y_offset + sampleRow; + + Physics::Material* mat1 = GetMaterialFromRaycast(rayX, rayY); + EXPECT_NE(mat1, nullptr); + + Physics::Material* mat2 = GetMaterialFromRaycast(rayX + secondRayOffset, rayY + secondRayOffset); + EXPECT_NE(mat2, nullptr); + + AZStd::string expectedMaterialName = physicsSurfaceTypes[physicsMaterialsValidationDataIndex[sampleRow * 2 + sampleColumn]]; + EXPECT_EQ(mat1->GetSurfaceTypeName(), expectedMaterialName); + } + } + } } } // namespace PhysXEditorTests diff --git a/Gems/PhysX/Code/Tests/EditorTestUtilities.cpp b/Gems/PhysX/Code/Tests/EditorTestUtilities.cpp index fa794c58a5..272d9157b2 100644 --- a/Gems/PhysX/Code/Tests/EditorTestUtilities.cpp +++ b/Gems/PhysX/Code/Tests/EditorTestUtilities.cpp @@ -70,6 +70,24 @@ namespace PhysXEditorTests } } + void PhysXEditorFixture::ConnectToPVD() + { + auto* debug = AZ::Interface::Get(); + if (debug) + { + debug->ConnectToPvd(); + } + } + + void PhysXEditorFixture::DisconnectFromPVD() + { + auto* debug = AZ::Interface::Get(); + if (debug) + { + debug->DisconnectFromPvd(); + } + } + // DefaultWorldBus AzPhysics::SceneHandle PhysXEditorFixture::GetDefaultSceneHandle() const { diff --git a/Gems/PhysX/Code/Tests/EditorTestUtilities.h b/Gems/PhysX/Code/Tests/EditorTestUtilities.h index 9dfe40f366..26566f724a 100644 --- a/Gems/PhysX/Code/Tests/EditorTestUtilities.h +++ b/Gems/PhysX/Code/Tests/EditorTestUtilities.h @@ -48,6 +48,9 @@ namespace PhysXEditorTests void SetUp() override; void TearDown() override; + void ConnectToPVD(); + void DisconnectFromPVD(); + // DefaultWorldBus AzPhysics::SceneHandle GetDefaultSceneHandle() const override; From 61dc7623d21108c3798c3fe3a6dd52fec851f955 Mon Sep 17 00:00:00 2001 From: dmcdiarmid-ly <63674186+dmcdiarmid-ly@users.noreply.github.com> Date: Thu, 20 Jan 2022 12:41:25 -0700 Subject: [PATCH 041/136] Minor change to a comment Signed-off-by: dmcdiarmid-ly <63674186+dmcdiarmid-ly@users.noreply.github.com> --- .../DiffuseProbeGridComponentController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp index b7dbbdbcf5..8c8b29a053 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridComponentController.cpp @@ -34,7 +34,7 @@ namespace AZ if (auto* serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(2) // ATOM-17127 + ->Version(2) // Added NumRaysPerProbe setting ->Field("ProbeSpacing", &DiffuseProbeGridComponentConfig::m_probeSpacing) ->Field("Extents", &DiffuseProbeGridComponentConfig::m_extents) ->Field("AmbientMultiplier", &DiffuseProbeGridComponentConfig::m_ambientMultiplier) From cc50a18fe997eeccc342d63f913942581d2fc9ae Mon Sep 17 00:00:00 2001 From: greerdv Date: Thu, 20 Jan 2022 11:38:22 +0000 Subject: [PATCH 042/136] add support for quad shapes in shape collider component Signed-off-by: greerdv --- .../Source/EditorShapeColliderComponent.cpp | 133 +++++++++++++++++- .../Source/EditorShapeColliderComponent.h | 11 ++ .../Code/Source/ShapeColliderComponent.h | 1 + 3 files changed, 144 insertions(+), 1 deletion(-) diff --git a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp index 59b659a0bf..f61b2fce74 100644 --- a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -64,6 +65,17 @@ namespace PhysX return AZ::Edit::PropertyVisibility::Hide; } + AZ::Crc32 EditorShapeColliderComponent::SingleSidedVisibility() + { + if ((m_shapeType == ShapeType::QuadSingleSided || m_shapeType == ShapeType::QuadDoubleSided) + && GetEntity()->FindComponent() == nullptr) + { + return AZ::Edit::PropertyVisibility::Show; + } + + return AZ::Edit::PropertyVisibility::Hide; + } + void EditorShapeColliderComponent::Reflect(AZ::ReflectContext* context) { if (auto serializeContext = azrtti_cast(context)) @@ -74,6 +86,7 @@ namespace PhysX ->Field("DebugDrawSettings", &EditorShapeColliderComponent::m_colliderDebugDraw) ->Field("ShapeConfigs", &EditorShapeColliderComponent::m_shapeConfigs) ->Field("SubdivisionCount", &EditorShapeColliderComponent::m_subdivisionCount) + ->Field("SingleSided", &EditorShapeColliderComponent::m_singleSided) ; if (auto editContext = serializeContext->GetEditContext()) @@ -100,6 +113,10 @@ namespace PhysX ->Attribute(AZ::Edit::Attributes::Max, Utils::MaxFrustumSubdivisions) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorShapeColliderComponent::OnSubdivisionCountChange) ->Attribute(AZ::Edit::Attributes::Visibility, &EditorShapeColliderComponent::SubdivisionCountVisibility) + ->DataElement(AZ::Edit::UIHandlers::Default, &EditorShapeColliderComponent::m_singleSided, "Single sided", + "If enabled, planar shapes will only collide from one direction (not valid for shapes attached to dynamic rigid bodies)") + ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorShapeColliderComponent::OnSingleSidedChange) + ->Attribute(AZ::Edit::Attributes::Visibility, &EditorShapeColliderComponent::SingleSidedVisibility) ; } } @@ -126,7 +143,6 @@ namespace PhysX incompatible.push_back(AZ_CRC_CE("AxisAlignedBoxShapeService")); incompatible.push_back(AZ_CRC_CE("CompoundShapeService")); incompatible.push_back(AZ_CRC_CE("DiskShapeService")); - incompatible.push_back(AZ_CRC_CE("QuadShapeService")); incompatible.push_back(AZ_CRC_CE("TubeShapeService")); incompatible.push_back(AZ_CRC_CE("ReferenceShapeService")); } @@ -206,6 +222,12 @@ namespace PhysX break; } + case ShapeType::QuadSingleSided: + case ShapeType::QuadDoubleSided: + { + // a quad shape has no interior, just return an empty vector of sample points + break; + } default: AZ_WarningOnce("PhysX Shape Collider Component", false, "Unsupported shape type in UpdateCachedSamplePoints"); break; @@ -331,6 +353,11 @@ namespace PhysX UpdateCylinderConfig(uniformScale); } + else if (shapeCrc == ShapeConstants::Quad) + { + UpdateQuadConfig(overallScale); + } + else { m_shapeType = !shapeCrc ? ShapeType::None : ShapeType::Unsupported; @@ -354,6 +381,60 @@ namespace PhysX m_geometryCache.m_boxDimensions = scale * boxDimensions; } + void EditorShapeColliderComponent::UpdateQuadConfig(const AZ::Vector3& scale) + { + LmbrCentral::QuadShapeConfig quadShapeConfig; + LmbrCentral::QuadShapeComponentRequestBus::EventResult(quadShapeConfig, GetEntityId(), + &LmbrCentral::QuadShapeComponentRequests::GetQuadConfiguration); + + const float minDimension = 1e-3f; // used to prevent the dimensions being 0 in any direction + const float xDim = AZ::GetMax(minDimension, quadShapeConfig.m_width); + const float yDim = AZ::GetMax(minDimension, quadShapeConfig.m_height); + + if (m_singleSided) + { + AZStd::vector cookedData; + + constexpr AZ::u32 vertexCount = 4; + const AZ::Vector3 vertices[vertexCount] = + { + AZ::Vector3(-0.5f * xDim, -0.5f * yDim, 0.0f), + AZ::Vector3(-0.5f * xDim, 0.5f * yDim, 0.0f), + AZ::Vector3(0.5f * xDim, 0.5f * yDim, 0.0f), + AZ::Vector3(0.5f * xDim, -0.5f * yDim, 0.0f), + }; + + constexpr AZ::u32 indexCount = 6; + const AZ::u32 indices[indexCount] = + { + 0, 1, 2, + 0, 2, 3 + }; + + bool cookingResult = false; + Physics::SystemRequestBus::BroadcastResult(cookingResult, &Physics::SystemRequests::CookTriangleMeshToMemory, + vertices, vertexCount, indices, indexCount, cookedData); + + Physics::CookedMeshShapeConfiguration shapeConfig; + shapeConfig.SetCookedMeshData(cookedData.data(), cookedData.size(), + Physics::CookedMeshShapeConfiguration::MeshType::TriangleMesh); + shapeConfig.m_scale = scale; + + SetShapeConfig(ShapeType::QuadSingleSided, shapeConfig); + } + + else + { + // it's not possible to create a perfectly 2d convex in PhysX, so the best we can do is a very thin box + const float zDim = AZ::GetMax(minDimension, 1e-3f * AZ::GetMin(xDim, yDim)); + const AZ::Vector3 boxDimensions(xDim, yDim, zDim); + + SetShapeConfig(ShapeType::QuadDoubleSided, Physics::BoxShapeConfiguration(boxDimensions)); + + m_shapeConfigs.back()->m_scale = scale; + } + } + void EditorShapeColliderComponent::UpdateCapsuleConfig(const AZ::Vector3& scale) { LmbrCentral::CapsuleShapeConfig lmbrCentralCapsuleShapeConfig; @@ -425,6 +506,12 @@ namespace PhysX } } + void EditorShapeColliderComponent::OnSingleSidedChange() + { + UpdateShapeConfigs(); + CreateStaticEditorCollider(); + } + AZ::u32 EditorShapeColliderComponent::OnSubdivisionCountChange() { const AZ::Vector3 uniformScale = Utils::GetUniformScale(GetEntityId()); @@ -615,6 +702,8 @@ namespace PhysX m_editorSceneHandle = m_sceneInterface->GetSceneHandle(AzPhysics::EditorPhysicsSceneName); } + UpdateTriggerSettings(); + UpdateSingleSidedSettings(); UpdateShapeConfigs(); // Debug drawing @@ -767,6 +856,7 @@ namespace PhysX if (changeReason == LmbrCentral::ShapeComponentNotifications::ShapeChangeReasons::ShapeChanged) { UpdateShapeConfigs(); + UpdateTriggerSettings(); CreateStaticEditorCollider(); Physics::ColliderComponentEventBus::Event(GetEntityId(), &Physics::ColliderComponentEvents::OnColliderChanged); @@ -849,4 +939,45 @@ namespace PhysX { return m_colliderConfig.m_isTrigger; } + + void EditorShapeColliderComponent::UpdateTriggerSettings() + { + if (m_shapeType == ShapeType::QuadSingleSided || m_shapeType == ShapeType::QuadDoubleSided) + { + if (!m_previousIsTrigger.has_value()) + { + m_previousIsTrigger = m_colliderConfig.m_isTrigger; + } + m_colliderConfig.SetPropertyVisibility(Physics::ColliderConfiguration::PropertyVisibility::IsTrigger, false); + } + else + { + if (m_previousIsTrigger.has_value()) + { + m_colliderConfig.m_isTrigger = m_previousIsTrigger.value(); + m_previousIsTrigger.reset(); + } + m_colliderConfig.SetPropertyVisibility(Physics::ColliderConfiguration::PropertyVisibility::IsTrigger, true); + } + } + + void EditorShapeColliderComponent::UpdateSingleSidedSettings() + { + if (GetEntity()->FindComponent()) + { + if (!m_previousSingleSided.has_value()) + { + m_previousSingleSided = m_singleSided; + } + m_singleSided = false; + } + else + { + if (m_previousSingleSided.has_value()) + { + m_singleSided = m_previousSingleSided.value(); + m_previousSingleSided.reset(); + } + } + } } // namespace PhysX diff --git a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.h b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.h index 3422d4959f..0f5350b781 100644 --- a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.h +++ b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.h @@ -41,6 +41,8 @@ namespace PhysX Sphere, PolygonPrism, Cylinder, + QuadDoubleSided, + QuadSingleSided, Unsupported }; @@ -89,6 +91,7 @@ namespace PhysX AZ::u32 OnConfigurationChanged(); void UpdateShapeConfigs(); void UpdateBoxConfig(const AZ::Vector3& scale); + void UpdateQuadConfig(const AZ::Vector3& scale); void UpdateCapsuleConfig(const AZ::Vector3& scale); void UpdateSphereConfig(const AZ::Vector3& scale); void UpdateCylinderConfig(const AZ::Vector3& scale); @@ -103,6 +106,8 @@ namespace PhysX AZ::u32 OnSubdivisionCountChange(); AZ::Crc32 SubdivisionCountVisibility(); + void OnSingleSidedChange(); + AZ::Crc32 SingleSidedVisibility(); // AZ::Component void Activate() override; @@ -137,6 +142,9 @@ namespace PhysX AZ::Aabb GetColliderShapeAabb() override; bool IsTrigger() override; + void UpdateTriggerSettings(); + void UpdateSingleSidedSettings(); + Physics::ColliderConfiguration m_colliderConfig; //!< Stores collision layers, whether the collider is a trigger, etc. DebugDraw::Collider m_colliderDebugDraw; //!< Handles drawing the collider based on global and local AzPhysics::SceneInterface* m_sceneInterface = nullptr; @@ -151,6 +159,9 @@ namespace PhysX //! @note 16 is the number of subdivisions in the debug cylinder that is loaded as a mesh (not generated procedurally) AZ::u8 m_subdivisionCount = 16; mutable GeometryCache m_geometryCache; //!< Cached data for generating sample points inside the attached shape. + AZStd::optional m_previousIsTrigger; //!< Stores the previous trigger setting if the shape is changed to one which does not support triggers. + bool m_singleSided = false; //!< Used for 2d shapes like quad which may be treated as either single or doubled sided. + AZStd::optional m_previousSingleSided; //!< Stores the previous single sided setting when unable to support single-sided shapes (such as when used with a dynamic rigid body). AzPhysics::SystemEvents::OnConfigurationChangedEvent::Handler m_physXConfigChangedHandler; AzPhysics::SystemEvents::OnMaterialLibraryChangedEvent::Handler m_onMaterialLibraryChangedEventHandler; diff --git a/Gems/PhysX/Code/Source/ShapeColliderComponent.h b/Gems/PhysX/Code/Source/ShapeColliderComponent.h index 2065f17dcf..cfc51f08ed 100644 --- a/Gems/PhysX/Code/Source/ShapeColliderComponent.h +++ b/Gems/PhysX/Code/Source/ShapeColliderComponent.h @@ -30,6 +30,7 @@ namespace PhysX static const AZ::Crc32 Sphere = AZ_CRC("Sphere", 0x55f96687); static const AZ::Crc32 PolygonPrism = AZ_CRC("PolygonPrism", 0xd6b50036); static const AZ::Crc32 Cylinder = AZ_CRC("Cylinder", 0x9b045bea); + static const AZ::Crc32 Quad = AZ_CRC("QuadShape", 0x40d75e14); } // namespace ShapeConstants /// Component that provides a collider based on geometry from a shape component. From a8eb5be2e6f3952ce1fdff147104dd1e1e049d7a Mon Sep 17 00:00:00 2001 From: greerdv Date: Thu, 20 Jan 2022 13:24:01 +0000 Subject: [PATCH 043/136] fix order of triangle indices for single-sided quad collider Signed-off-by: greerdv --- Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp index f61b2fce74..b935ff2536 100644 --- a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp @@ -407,8 +407,8 @@ namespace PhysX constexpr AZ::u32 indexCount = 6; const AZ::u32 indices[indexCount] = { - 0, 1, 2, - 0, 2, 3 + 0, 2, 1, + 0, 3, 2 }; bool cookingResult = false; From f61011f5ac8382c7db145538f873933a64e76b51 Mon Sep 17 00:00:00 2001 From: greerdv Date: Thu, 20 Jan 2022 18:14:33 +0000 Subject: [PATCH 044/136] add editor side tests for quad colliders Signed-off-by: greerdv --- .../Source/EditorShapeColliderComponent.cpp | 3 +- .../Tests/ShapeColliderComponentTests.cpp | 150 +++++++++++++++++- 2 files changed, 148 insertions(+), 5 deletions(-) diff --git a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp index b935ff2536..bdf70fc227 100644 --- a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp @@ -702,9 +702,9 @@ namespace PhysX m_editorSceneHandle = m_sceneInterface->GetSceneHandle(AzPhysics::EditorPhysicsSceneName); } - UpdateTriggerSettings(); UpdateSingleSidedSettings(); UpdateShapeConfigs(); + UpdateTriggerSettings(); // Debug drawing m_colliderDebugDraw.Connect(GetEntityId()); @@ -947,6 +947,7 @@ namespace PhysX if (!m_previousIsTrigger.has_value()) { m_previousIsTrigger = m_colliderConfig.m_isTrigger; + m_colliderConfig.m_isTrigger = false; } m_colliderConfig.SetPropertyVisibility(Physics::ColliderConfiguration::PropertyVisibility::IsTrigger, false); } diff --git a/Gems/PhysX/Code/Tests/ShapeColliderComponentTests.cpp b/Gems/PhysX/Code/Tests/ShapeColliderComponentTests.cpp index 06ba4f3e9c..21d381a259 100644 --- a/Gems/PhysX/Code/Tests/ShapeColliderComponentTests.cpp +++ b/Gems/PhysX/Code/Tests/ShapeColliderComponentTests.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -452,21 +453,55 @@ namespace PhysXEditorTests EXPECT_TRUE(aabb.GetMin().IsClose(translation - 0.5f * scale * boxDimensions)); } - void SetTrigger(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent, bool isTrigger) + void SetBoolValueOnComponent(AZ::Component* component, AZ::Crc32 name, bool value) { AZ::SerializeContext* serializeContext = nullptr; AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext); AzToolsFramework::InstanceDataHierarchy instanceDataHierarchy; - instanceDataHierarchy.AddRootInstance(editorShapeColliderComponent); + instanceDataHierarchy.AddRootInstance(component); instanceDataHierarchy.Build(serializeContext, AZ::SerializeContext::ENUM_ACCESS_FOR_WRITE); AzToolsFramework::InstanceDataHierarchy::InstanceDataNode* instanceNode = - instanceDataHierarchy.FindNodeByPartialAddress({ AZ_CRC("Trigger", 0x1a6b0f5d) }); + instanceDataHierarchy.FindNodeByPartialAddress({ name }); if (instanceNode) { - instanceNode->Write(isTrigger); + instanceNode->Write(value); } } + void SetTrigger(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent, bool isTrigger) + { + SetBoolValueOnComponent(editorShapeColliderComponent, AZ_CRC("Trigger", 0x1a6b0f5d), isTrigger); + } + + bool GetBoolValueFromComponent(AZ::Component* component, AZ::Crc32 name) + { + AZ::SerializeContext* serializeContext = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext); + AzToolsFramework::InstanceDataHierarchy instanceDataHierarchy; + instanceDataHierarchy.AddRootInstance(component); + instanceDataHierarchy.Build(serializeContext, AZ::SerializeContext::ENUM_ACCESS_FOR_READ); + AzToolsFramework::InstanceDataHierarchy::InstanceDataNode* instanceNode = + instanceDataHierarchy.FindNodeByPartialAddress({ name }); + bool value = false; + instanceNode->Read(value); + return value; + } + + bool IsTrigger(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent) + { + return GetBoolValueFromComponent(editorShapeColliderComponent, AZ_CRC("Trigger")); + } + + void SetSingleSided(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent, bool singleSided) + { + SetBoolValueOnComponent(editorShapeColliderComponent, AZ_CRC("SingleSided"), singleSided); + } + + bool IsSingleSided(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent) + { + return GetBoolValueFromComponent(editorShapeColliderComponent, AZ_CRC("SingleSided")); + } + EntityPtr CreateRigidBox(const AZ::Vector3& boxDimensions, const AZ::Vector3& position) { EntityPtr rigidBodyEditorEntity = CreateInactiveEditorEntity("RigidBodyEditorEntity"); @@ -566,4 +601,111 @@ namespace PhysXEditorTests EXPECT_THAT(aabb.GetMin(), UnitTest::IsClose(-0.5f * boxDimensions * parentScale)); } + class PhysXEditorParamBoolFixture + : public ::testing::WithParamInterface + , public PhysXEditorFixture + { + }; + + TEST_P(PhysXEditorParamBoolFixture, EditorShapeColliderComponent_ShapeColliderWithQuadShapeNonUniformlyScalesCorrectly) + { + // test both single and double-sided quad colliders + bool singleSided = GetParam(); + + EntityPtr editorEntity = CreateInactiveEditorEntity("QuadEntity"); + editorEntity->CreateComponent(LmbrCentral::EditorQuadShapeComponentTypeId); + auto* shapeColliderComponent = editorEntity->CreateComponent(); + SetSingleSided(shapeColliderComponent, singleSided); + editorEntity->CreateComponent(); + const auto entityId = editorEntity->GetId(); + + editorEntity->Activate(); + + LmbrCentral::QuadShapeComponentRequestBus::Event(entityId, &LmbrCentral::QuadShapeComponentRequests::SetQuadWidth, 1.2f); + LmbrCentral::QuadShapeComponentRequestBus::Event(entityId, &LmbrCentral::QuadShapeComponentRequests::SetQuadHeight, 0.8f); + + // update the transform scale and non-uniform scale + AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalUniformScale, 3.0f); + AZ::NonUniformScaleRequestBus::Event(entityId, &AZ::NonUniformScaleRequests::SetScale, AZ::Vector3(1.5f, 0.5f, 1.0f)); + + // make a game entity and check that its AABB is as expected + EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get()); + AZ::Aabb aabb = gameEntity->FindComponent()->GetAabb(); + + EXPECT_NEAR(aabb.GetMin().GetX(), -2.7f, 1e-3f); + EXPECT_NEAR(aabb.GetMin().GetY(), -0.6f, 1e-3f); + EXPECT_NEAR(aabb.GetMax().GetX(), 2.7f, 1e-3f); + EXPECT_NEAR(aabb.GetMax().GetY(), 0.6f, 1e-3f); + EXPECT_TRUE(true); + } + + TEST_P(PhysXEditorParamBoolFixture, EditorShapeColliderComponent_TriggerSettingIsRememberedWhenSwitchingToQuadAndBack) + { + bool initialTriggerSetting = GetParam(); + + // create an editor entity with a box component (which does support trigger) + EntityPtr editorEntity = CreateInactiveEditorEntity("QuadEntity"); + auto* boxShapeComponent = editorEntity->CreateComponent(LmbrCentral::EditorBoxShapeComponentTypeId); + auto* shapeColliderComponent = editorEntity->CreateComponent(); + SetTrigger(shapeColliderComponent, initialTriggerSetting); + editorEntity->Activate(); + + // the trigger setting should be what it was set to + EXPECT_EQ(IsTrigger(shapeColliderComponent), initialTriggerSetting); + + // deactivate the entity and swap the box for a quad (which does not support trigger) + editorEntity->Deactivate(); + editorEntity->RemoveComponent(boxShapeComponent); + auto* quadShapeComponent = editorEntity->CreateComponent(LmbrCentral::EditorQuadShapeComponentTypeId); + editorEntity->Activate(); + + // the trigger setting should now be false, because quad shape does not support triggers + EXPECT_FALSE(IsTrigger(shapeColliderComponent)); + + // swap back to a box shape + editorEntity->Deactivate(); + editorEntity->RemoveComponent(quadShapeComponent); + editorEntity->AddComponent(boxShapeComponent); + editorEntity->Activate(); + + // the original trigger setting should have been remembered + EXPECT_EQ(IsTrigger(shapeColliderComponent), initialTriggerSetting); + + // the quad shape component is no longer attached to the entity so won't be automatically cleared up + delete quadShapeComponent; + } + + TEST_P(PhysXEditorParamBoolFixture, EditorShapeColliderComponent_SingleSidedSettingIsRememberedWhenAddingAndRemovingRigidBody) + { + bool initialSingleSidedSetting = GetParam(); + + // create an editor entity without a rigid body (that means both single-sided and double-sided quads are valid) + EntityPtr editorEntity = CreateInactiveEditorEntity("QuadEntity"); + editorEntity->CreateComponent(LmbrCentral::EditorQuadShapeComponentTypeId); + auto* shapeColliderComponent = editorEntity->CreateComponent(); + SetSingleSided(shapeColliderComponent, initialSingleSidedSetting); + editorEntity->Activate(); + + // verify that the single sided setting matches the initial value + EXPECT_EQ(IsSingleSided(shapeColliderComponent), initialSingleSidedSetting); + + // add an editor rigid body component (this should mean single-sided quads are not supported) + editorEntity->Deactivate(); + auto rigidBodyComponent = editorEntity->CreateComponent(); + editorEntity->Activate(); + + EXPECT_FALSE(IsSingleSided(shapeColliderComponent)); + + // remove the editor rigid body component (the previous single-sided setting should be restored) + editorEntity->Deactivate(); + editorEntity->RemoveComponent(rigidBodyComponent); + editorEntity->Activate(); + + EXPECT_EQ(IsSingleSided(shapeColliderComponent), initialSingleSidedSetting); + + // the rigid body component is no longer attached to the entity so won't be automatically cleared up + delete rigidBodyComponent; + } + + INSTANTIATE_TEST_CASE_P(PhysXEditorTests, PhysXEditorParamBoolFixture, ::testing::Bool()); } // namespace PhysXEditorTests From 6a700e6b955d784b814cf7d39aa1ed65244236fa Mon Sep 17 00:00:00 2001 From: greerdv Date: Thu, 20 Jan 2022 19:10:56 +0000 Subject: [PATCH 045/136] add test for runtime behaviour of single sided quad collider Signed-off-by: greerdv --- .../Tests/ShapeColliderComponentTests.cpp | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/Gems/PhysX/Code/Tests/ShapeColliderComponentTests.cpp b/Gems/PhysX/Code/Tests/ShapeColliderComponentTests.cpp index 21d381a259..c164e5de63 100644 --- a/Gems/PhysX/Code/Tests/ShapeColliderComponentTests.cpp +++ b/Gems/PhysX/Code/Tests/ShapeColliderComponentTests.cpp @@ -707,5 +707,39 @@ namespace PhysXEditorTests delete rigidBodyComponent; } - INSTANTIATE_TEST_CASE_P(PhysXEditorTests, PhysXEditorParamBoolFixture, ::testing::Bool()); + INSTANTIATE_TEST_CASE_P(PhysXEditorTest, PhysXEditorParamBoolFixture, ::testing::Bool()); + + TEST_F(PhysXEditorFixture, EditorShapeColliderComponent_SingleSidedQuadDoesNotCollideFromBelow) + { + // create an editor entity without a rigid body (that means both single-sided and double-sided quads are valid), positioned at the origin + EntityPtr editorQuadEntity = CreateInactiveEditorEntity("QuadEntity"); + editorQuadEntity->CreateComponent(LmbrCentral::EditorQuadShapeComponentTypeId); + auto* shapeColliderComponent = editorQuadEntity->CreateComponent(); + SetSingleSided(shapeColliderComponent, true); + editorQuadEntity->Activate(); + LmbrCentral::QuadShapeComponentRequestBus::Event(editorQuadEntity->GetId(), &LmbrCentral::QuadShapeComponentRequests::SetQuadHeight, 10.0f); + LmbrCentral::QuadShapeComponentRequestBus::Event(editorQuadEntity->GetId(), &LmbrCentral::QuadShapeComponentRequests::SetQuadWidth, 10.0f); + + // add a second entity with a box collider and a rigid body, positioned below the quad + EntityPtr editorBoxEntity = CreateInactiveEditorEntity("BoxEntity"); + editorBoxEntity->CreateComponent(LmbrCentral::BoxShapeComponentTypeId); + editorBoxEntity->CreateComponent(); + editorBoxEntity->CreateComponent(); + editorBoxEntity->Activate(); + AZ::TransformBus::Event(editorBoxEntity->GetId(), &AZ::TransformBus::Events::SetWorldTranslation, -AZ::Vector3::CreateAxisZ()); + + EntityPtr gameQuadEntity = CreateActiveGameEntityFromEditorEntity(editorQuadEntity.get()); + EntityPtr gameBoxEntity = CreateActiveGameEntityFromEditorEntity(editorBoxEntity.get()); + + // give the box enough upward velocity to rise above the level of the quad and simulate + Physics::RigidBodyRequestBus::Event(gameBoxEntity->GetId(), &Physics::RigidBodyRequests::SetLinearVelocity, AZ::Vector3::CreateAxisZ(6.0f)); + PhysX::TestUtils::UpdateScene(m_defaultScene, AzPhysics::SystemConfiguration::DefaultFixedTimestep, 200); + + // the box should travel through the base of the quad because it has no collision from that direction + // and land on the top surface of the quad, which does have collision + float finalHeight = 0.0f; + AZ::TransformBus::EventResult(finalHeight, gameBoxEntity->GetId(), &AZ::TransformBus::Events::GetWorldZ); + + EXPECT_GT(finalHeight, 0.0f); + } } // namespace PhysXEditorTests From 6fde1389bf6536d1196517c5df3686d4f5ef7078 Mon Sep 17 00:00:00 2001 From: Neil Widmaier Date: Thu, 20 Jan 2022 13:35:08 -0800 Subject: [PATCH 046/136] adding editor level load automation script Signed-off-by: Neil Widmaier --- .../Atom/tests/hydra_Atom_LevelLoadTest.py | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_Atom_LevelLoadTest.py diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_Atom_LevelLoadTest.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_Atom_LevelLoadTest.py new file mode 100644 index 0000000000..77886e2123 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_Atom_LevelLoadTest.py @@ -0,0 +1,85 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. +For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + + +def Atom_LevelLoadTest(): + """ + Summary: + Loads all graphics levels within the AutomatedTesting project in editor. For each level this script will verify that + the level loads, and can enter/exit gameplay without crashing the editor. + + Test setup: + - Store all available levels in a list. + - Set up a for loop to run all checks for each level. + + Expected Behavior: + Test verifies that each level loads, enters/exits game mode, and reports success for all test actions. + + Test Steps for each level: + 1) Create tuple with level load success and failure messages + 2) Open the level using the python test tools command + 3) Verify level is loaded using a separate command, and report success/failure + 4) Create tuple with success and failure messages for entering gameplay + 5) Enter gameplay and report result + 6) Create tuple with success and failure messages for exiting gameplay + 7) Exit Gameplay and report result + + :return: None + """ + + import azlmbr.legacy.general as general + + from editor_python_test_tools.utils import Report, Tracer, TestHelper + + level_list = ["hermanubis", "hermanubis_high", "macbeth_shaderballs", "PbrMaterialChart", "ShadowTest", "Sponza"] + + with Tracer() as error_tracer: + # + + for level in level_list: + + # 1. Create tuple with level load success and failure messages + level_check_tupple = (f"loaded {level}", f"failed to load {level}") + + # 2. Open the level using the python test tools command + TestHelper.init_idle() + TestHelper.open_level("graphics", level) + + # 3. Verify level is loaded using a separate command, and report success/failure + load_success = general.get_current_level_name() + Report.info(load_success) + if load_success == level: + level_match = True + else: + level_match = False + Report.info(level_match) + Report.result(level_check_tupple, level_match) + + # 4. Create tuple with success and failure messages for entering gameplay + Enter_game_mode_tupple = (f"{level} entered gameplay successfully ", f"{level} failed to enter gameplay") + + # 5. Enter gameplay and report result + TestHelper.enter_game_mode(Enter_game_mode_tupple) + + # 6. Create tuple with success and failure messages for exiting gameplay + Exit_game_mode_tupple = (f"{level} exited gameplay successfully ", f"{level} failed to exit gameplay") + + # 7. Exit Gameplay and report result + TestHelper.exit_game_mode(Exit_game_mode_tupple) + + + # 11. Look for errors or asserts. + TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) + for error_info in error_tracer.errors: + Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") + for assert_info in error_tracer.asserts: + Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}") + + +if __name__ == "__main__": + from editor_python_test_tools.utils import Report + Report.start_test(Atom_LevelLoadTest) From 3977edb21ec25cba410e86bc03535a8b9df768af Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 19 Jan 2022 15:48:57 -0600 Subject: [PATCH 047/136] Atom Tools: Removing unnecessary modules, components, and dead code from SMC Looking toward creating a bare bones template for a standalone application, simplifying and removing any boilerplate wherever possible. SMC followed patterns established by material editor, subdividing everything into multiple modules, which required manually adding static modules, implementing system components with little to no functionality, and a bunch of unnecessary files for such a simple application. This change deletes unnecessary boilerplate code, moving everything into a single module, making the application class responsible for reflecting classes and buses. Signed-off-by: Guthrie Adams --- .../Application/AtomToolsApplication.cpp | 1 + .../Code/CMakeLists.txt | 45 +--- .../ShaderManagementConsoleDocumentModule.h | 28 --- .../ShaderManagementConsoleWindowModule.h | 28 --- .../ShaderManagementConsoleDocument.h | 2 +- .../ShaderManagementConsoleDocumentModule.cpp | 30 --- ...haderManagementConsoleDocumentRequestBus.h | 0 ...nagementConsoleDocumentSystemComponent.cpp | 86 ------- ...ManagementConsoleDocumentSystemComponent.h | 41 ---- .../ShaderManagementConsole_Traits_Linux.h | 2 - .../Mac/ShaderManagementConsole_Traits_Mac.h | 2 - .../ShaderManagementConsole_Traits_Windows.h | 2 - .../ShaderManagementConsoleApplication.cpp | 219 ++++++++++++++++-- .../ShaderManagementConsoleApplication.h | 29 ++- .../ShaderManagementConsoleRequestBus.h | 0 .../ShaderManagementConsoleBrowserWidget.cpp | 201 ---------------- .../Window/ShaderManagementConsoleWindow.cpp | 17 +- .../Window/ShaderManagementConsoleWindow.h | 4 +- ...ShaderManagementConsoleWindowComponent.cpp | 206 ---------------- .../ShaderManagementConsoleWindowComponent.h | 76 ------ .../ShaderManagementConsoleWindowModule.cpp | 38 --- .../ShaderManagementConsoleToolBar.cpp | 32 --- .../ToolBar/ShaderManagementConsoleToolBar.h | 31 --- .../Code/shadermanagementconsole_files.cmake | 11 + ...hadermanagementconsoledocument_files.cmake | 17 -- .../shadermanagementconsolewindow_files.cmake | 22 -- 26 files changed, 259 insertions(+), 911 deletions(-) delete mode 100644 Gems/Atom/Tools/ShaderManagementConsole/Code/Include/Atom/Document/ShaderManagementConsoleDocumentModule.h delete mode 100644 Gems/Atom/Tools/ShaderManagementConsole/Code/Include/Atom/Window/ShaderManagementConsoleWindowModule.h delete mode 100644 Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocumentModule.cpp rename Gems/Atom/Tools/ShaderManagementConsole/Code/{Include/Atom => Source}/Document/ShaderManagementConsoleDocumentRequestBus.h (100%) delete mode 100644 Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocumentSystemComponent.cpp delete mode 100644 Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocumentSystemComponent.h rename Gems/Atom/Tools/ShaderManagementConsole/Code/{Include/Atom/Core => Source}/ShaderManagementConsoleRequestBus.h (100%) delete mode 100644 Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleBrowserWidget.cpp delete mode 100644 Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindowComponent.cpp delete mode 100644 Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindowComponent.h delete mode 100644 Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindowModule.cpp delete mode 100644 Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ToolBar/ShaderManagementConsoleToolBar.cpp delete mode 100644 Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ToolBar/ShaderManagementConsoleToolBar.h delete mode 100644 Gems/Atom/Tools/ShaderManagementConsole/Code/shadermanagementconsoledocument_files.cmake delete mode 100644 Gems/Atom/Tools/ShaderManagementConsole/Code/shadermanagementconsolewindow_files.cmake diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp index 7b6be61050..150b06cabd 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Application/AtomToolsApplication.cpp @@ -157,6 +157,7 @@ namespace AtomToolsFramework components.insert( components.end(), { + azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), azrtti_typeid(), diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/CMakeLists.txt b/Gems/Atom/Tools/ShaderManagementConsole/Code/CMakeLists.txt index c5ceab5360..3c5de1cc1b 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/CMakeLists.txt @@ -19,48 +19,10 @@ if(NOT PAL_TRAIT_ATOM_SHADER_MANAGEMENT_CONSOLE_APPLICATION_SUPPORTED) endif() ly_add_target( - NAME ShaderManagementConsole.Document STATIC - NAMESPACE Gem - FILES_CMAKE - shadermanagementconsoledocument_files.cmake - INCLUDE_DIRECTORIES - PRIVATE - . - Source - PUBLIC - Include - BUILD_DEPENDENCIES - PUBLIC - Gem::AtomToolsFramework.Static - Gem::AtomToolsFramework.Editor - Gem::Atom_RPI.Edit - Gem::Atom_RPI.Public - Gem::Atom_RHI.Reflect -) - -ly_add_target( - NAME ShaderManagementConsole.Window STATIC + NAME ShaderManagementConsole EXECUTABLE NAMESPACE Gem AUTOMOC AUTORCC - FILES_CMAKE - shadermanagementconsolewindow_files.cmake - INCLUDE_DIRECTORIES - PRIVATE - . - Source - PUBLIC - Include - BUILD_DEPENDENCIES - PUBLIC - Gem::AtomToolsFramework.Static - Gem::AtomToolsFramework.Editor - Gem::Atom_RPI.Public -) - -ly_add_target( - NAME ShaderManagementConsole EXECUTABLE - NAMESPACE Gem FILES_CMAKE shadermanagementconsole_files.cmake ${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake @@ -77,8 +39,9 @@ ly_add_target( PRIVATE Gem::AtomToolsFramework.Static Gem::AtomToolsFramework.Editor - Gem::ShaderManagementConsole.Window - Gem::ShaderManagementConsole.Document + Gem::Atom_RPI.Edit + Gem::Atom_RPI.Public + Gem::Atom_RHI.Reflect RUNTIME_DEPENDENCIES Gem::AtomToolsFramework.Editor Gem::EditorPythonBindings.Editor diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Include/Atom/Document/ShaderManagementConsoleDocumentModule.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Include/Atom/Document/ShaderManagementConsoleDocumentModule.h deleted file mode 100644 index dd5cc01506..0000000000 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Include/Atom/Document/ShaderManagementConsoleDocumentModule.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include - -namespace ShaderManagementConsole -{ - //! Entry point for Shader Management Console Document library. - class ShaderManagementConsoleDocumentModule - : public AZ::Module - { - public: - AZ_RTTI(ShaderManagementConsoleDocumentModule, "{81D7A170-9284-4DE9-8D92-B6B94E8A2BDF}", AZ::Module); - AZ_CLASS_ALLOCATOR(ShaderManagementConsoleDocumentModule, AZ::SystemAllocator, 0); - - ShaderManagementConsoleDocumentModule(); - - //! Add required SystemComponents to the SystemEntity. - AZ::ComponentTypeList GetRequiredSystemComponents() const override; - }; -} diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Include/Atom/Window/ShaderManagementConsoleWindowModule.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Include/Atom/Window/ShaderManagementConsoleWindowModule.h deleted file mode 100644 index ff365ee98c..0000000000 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Include/Atom/Window/ShaderManagementConsoleWindowModule.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include - -namespace ShaderManagementConsole -{ - //! Entry point for Shader Management Console Window library. - class ShaderManagementConsoleWindowModule - : public AZ::Module - { - public: - AZ_RTTI(ShaderManagementConsoleWindowModule, "{57D6239C-AE03-4ED8-9125-35C5B1625503}", AZ::Module); - AZ_CLASS_ALLOCATOR(ShaderManagementConsoleWindowModule, AZ::SystemAllocator, 0); - - ShaderManagementConsoleWindowModule(); - - //! Add required SystemComponents to the SystemEntity. - AZ::ComponentTypeList GetRequiredSystemComponents() const override; - }; -} diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.h index eb7d6b87a0..bd51616f7a 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.h +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocument.h @@ -7,12 +7,12 @@ */ #pragma once -#include #include #include #include #include #include +#include namespace ShaderManagementConsole { diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocumentModule.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocumentModule.cpp deleted file mode 100644 index a9415fd85b..0000000000 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocumentModule.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include - -namespace ShaderManagementConsole -{ - ShaderManagementConsoleDocumentModule::ShaderManagementConsoleDocumentModule() - { - // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here. - m_descriptors.insert(m_descriptors.end(), { - ShaderManagementConsoleDocumentSystemComponent::CreateDescriptor(), - }); - } - - AZ::ComponentTypeList ShaderManagementConsoleDocumentModule::GetRequiredSystemComponents() const - { - return AZ::ComponentTypeList{ - azrtti_typeid(), - azrtti_typeid(), - }; - } -} diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Include/Atom/Document/ShaderManagementConsoleDocumentRequestBus.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocumentRequestBus.h similarity index 100% rename from Gems/Atom/Tools/ShaderManagementConsole/Code/Include/Atom/Document/ShaderManagementConsoleDocumentRequestBus.h rename to Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocumentRequestBus.h diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocumentSystemComponent.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocumentSystemComponent.cpp deleted file mode 100644 index 55b800067a..0000000000 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocumentSystemComponent.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include -#include - -namespace ShaderManagementConsole -{ - void ShaderManagementConsoleDocumentSystemComponent::Reflect(AZ::ReflectContext* context) - { - if (AZ::SerializeContext* serialize = azrtti_cast(context)) - { - serialize->Class() - ->Version(0); - - if (AZ::EditContext* ec = serialize->GetEditContext()) - { - ec->Class("ShaderManagementConsoleDocumentSystemComponent", "Manages documents") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System")) - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ; - } - } - - if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) - { - behaviorContext->EBus("ShaderManagementConsoleDocumentRequestBus") - ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) - ->Attribute(AZ::Script::Attributes::Category, "Editor") - ->Attribute(AZ::Script::Attributes::Module, "shadermanagementconsole") - ->Event("GetShaderOptionCount", &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionCount) - ->Event("GetShaderOptionDescriptor", &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionDescriptor) - ->Event("GetShaderVariantCount", &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderVariantCount) - ->Event("GetShaderVariantInfo", &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderVariantInfo) - ; - } - } - - void ShaderManagementConsoleDocumentSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) - { - required.push_back(AZ_CRC_CE("AtomToolsDocumentSystemService")); - required.push_back(AZ_CRC_CE("AssetProcessorToolsConnection")); - required.push_back(AZ_CRC_CE("AssetDatabaseService")); - required.push_back(AZ_CRC_CE("PropertyManagerService")); - required.push_back(AZ_CRC_CE("RPISystem")); - } - - void ShaderManagementConsoleDocumentSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) - { - provided.push_back(AZ_CRC_CE("ShaderManagementConsoleDocumentSystemService")); - } - - void ShaderManagementConsoleDocumentSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) - { - incompatible.push_back(AZ_CRC_CE("ShaderManagementConsoleDocumentSystemService")); - } - - void ShaderManagementConsoleDocumentSystemComponent::Init() - { - } - - void ShaderManagementConsoleDocumentSystemComponent::Activate() - { - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast( - &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Handler::RegisterDocumentType, - []() - { - return aznew ShaderManagementConsoleDocument(); - }); - } - - void ShaderManagementConsoleDocumentSystemComponent::Deactivate() - { - } -} diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocumentSystemComponent.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocumentSystemComponent.h deleted file mode 100644 index 1ee825f6de..0000000000 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Document/ShaderManagementConsoleDocumentSystemComponent.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include - -namespace ShaderManagementConsole -{ - //! ShaderManagementConsoleDocumentSystemComponent - class ShaderManagementConsoleDocumentSystemComponent - : public AZ::Component - { - public: - AZ_COMPONENT(ShaderManagementConsoleDocumentSystemComponent, "{1610159D-59DC-48B1-B2D1-FCE7AFD3B012}"); - - ShaderManagementConsoleDocumentSystemComponent() = default; - ~ShaderManagementConsoleDocumentSystemComponent() = default; - ShaderManagementConsoleDocumentSystemComponent(const ShaderManagementConsoleDocumentSystemComponent&) = delete; - ShaderManagementConsoleDocumentSystemComponent& operator =(const ShaderManagementConsoleDocumentSystemComponent&) = delete; - - static void Reflect(AZ::ReflectContext* context); - - static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); - static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); - static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); - - private: - //////////////////////////////////////////////////////////////////////// - // AZ::Component interface implementation - void Init() override; - void Activate() override; - void Deactivate() override; - //////////////////////////////////////////////////////////////////////// - }; -} diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Platform/Linux/ShaderManagementConsole_Traits_Linux.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Platform/Linux/ShaderManagementConsole_Traits_Linux.h index 2897402f04..c4cb36c3c3 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Platform/Linux/ShaderManagementConsole_Traits_Linux.h +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Platform/Linux/ShaderManagementConsole_Traits_Linux.h @@ -7,5 +7,3 @@ */ #pragma once -#define AZ_TRAIT_SHADER_MANAGEMENT_CONSOLE_EXT "" - diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Platform/Mac/ShaderManagementConsole_Traits_Mac.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Platform/Mac/ShaderManagementConsole_Traits_Mac.h index 627cce90c9..c4cb36c3c3 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Platform/Mac/ShaderManagementConsole_Traits_Mac.h +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Platform/Mac/ShaderManagementConsole_Traits_Mac.h @@ -7,5 +7,3 @@ */ #pragma once -#define AZ_TRAIT_SHADER_MANAGEMENT_CONSOLE_EXT ".app" - diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Platform/Windows/ShaderManagementConsole_Traits_Windows.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Platform/Windows/ShaderManagementConsole_Traits_Windows.h index 4bd905f929..c4cb36c3c3 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Platform/Windows/ShaderManagementConsole_Traits_Windows.h +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Platform/Windows/ShaderManagementConsole_Traits_Windows.h @@ -7,5 +7,3 @@ */ #pragma once -#define AZ_TRAIT_SHADER_MANAGEMENT_CONSOLE_EXT ".exe" - diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp index a242716b52..ba8038319b 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.cpp @@ -6,21 +6,90 @@ * */ -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include #include +#include #include +AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT +#include +#include +#include +AZ_POP_DISABLE_WARNING + +void InitShaderManagementConsoleResources() +{ + // Must register qt resources from other modules + Q_INIT_RESOURCE(ShaderManagementConsole); + Q_INIT_RESOURCE(InspectorWidget); + Q_INIT_RESOURCE(AtomToolsAssetBrowser); +} + namespace ShaderManagementConsole { - //! This function returns the build system target name of "ShaderManagementConsole" - AZStd::string ShaderManagementConsoleApplication::GetBuildTargetName() const + ShaderManagementConsoleApplication::ShaderManagementConsoleApplication(int* argc, char*** argv) + : Base(argc, argv) { -#if !defined(LY_CMAKE_TARGET) -#error "LY_CMAKE_TARGET must be defined in order to add this source file to a CMake executable target" -#endif - return AZStd::string_view{ LY_CMAKE_TARGET }; + InitShaderManagementConsoleResources(); + + QApplication::setApplicationName("O3DE Shader Management Console"); + + // The settings registry has been created at this point, so add the CMake target + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization( + *AZ::SettingsRegistry::Get(), GetBuildTargetName()); + + ShaderManagementConsoleRequestBus::Handler::BusConnect(); + AzToolsFramework::EditorWindowRequestBus::Handler::BusConnect(); + AtomToolsFramework::AtomToolsMainWindowFactoryRequestBus::Handler::BusConnect(); + } + + ShaderManagementConsoleApplication::~ShaderManagementConsoleApplication() + { + ShaderManagementConsoleRequestBus::Handler::BusDisconnect(); + AzToolsFramework::EditorWindowRequestBus::Handler::BusDisconnect(); + AtomToolsFramework::AtomToolsMainWindowFactoryRequestBus::Handler::BusDisconnect(); + m_window.reset(); + } + + void ShaderManagementConsoleApplication::Reflect(AZ::ReflectContext* context) + { + Base::Reflect(context); + + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) + { + behaviorContext->EBus("ShaderManagementConsoleRequestBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) + ->Attribute(AZ::Script::Attributes::Category, "Editor") + ->Attribute(AZ::Script::Attributes::Module, "shadermanagementconsole") + ->Event("GetSourceAssetInfo", &ShaderManagementConsoleRequestBus::Events::GetSourceAssetInfo) + ->Event("FindMaterialAssetsUsingShader", &ShaderManagementConsoleRequestBus::Events::FindMaterialAssetsUsingShader ) + ->Event("GetMaterialInstanceShaderItems", &ShaderManagementConsoleRequestBus::Events::GetMaterialInstanceShaderItems) + ; + + behaviorContext->EBus("ShaderManagementConsoleDocumentRequestBus") + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Attribute(AZ::Script::Attributes::Category, "Editor") + ->Attribute(AZ::Script::Attributes::Module, "shadermanagementconsole") + ->Event("GetShaderOptionCount", &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionCount) + ->Event("GetShaderOptionDescriptor", &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderOptionDescriptor) + ->Event("GetShaderVariantCount", &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderVariantCount) + ->Event("GetShaderVariantInfo", &ShaderManagementConsoleDocumentRequestBus::Events::GetShaderVariantInfo) + ; + } } const char* ShaderManagementConsoleApplication::GetCurrentConfigurationName() const @@ -34,25 +103,139 @@ namespace ShaderManagementConsole #endif } - ShaderManagementConsoleApplication::ShaderManagementConsoleApplication(int* argc, char*** argv) - : Base(argc, argv) + void ShaderManagementConsoleApplication::StartCommon(AZ::Entity* systemEntity) { - QApplication::setApplicationName("O3DE Shader Management Console"); + Base::StartCommon(systemEntity); - // The settings registry has been created at this point, so add the CMake target - AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization( - *AZ::SettingsRegistry::Get(), GetBuildTargetName()); + AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast( + &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Handler::RegisterDocumentType, + []() { return aznew ShaderManagementConsoleDocument(); }); } - void ShaderManagementConsoleApplication::CreateStaticModules(AZStd::vector& outModules) + AZStd::string ShaderManagementConsoleApplication::GetBuildTargetName() const { - Base::CreateStaticModules(outModules); - outModules.push_back(aznew ShaderManagementConsoleDocumentModule); - outModules.push_back(aznew ShaderManagementConsoleWindowModule); +#if !defined(LY_CMAKE_TARGET) +#error "LY_CMAKE_TARGET must be defined in order to add this source file to a CMake executable target" +#endif + //! Returns the build system target name of "ShaderManagementConsole" + return AZStd::string_view{ LY_CMAKE_TARGET }; } AZStd::vector ShaderManagementConsoleApplication::GetCriticalAssetFilters() const { return AZStd::vector({ "passes/", "config/" }); } + + QWidget* ShaderManagementConsoleApplication::GetAppMainWindow() + { + return m_window.get(); + } + + void ShaderManagementConsoleApplication::CreateMainWindow() + { + m_assetBrowserInteractions.reset(aznew ShaderManagementConsoleBrowserInteractions); + m_window.reset(aznew ShaderManagementConsoleWindow); + m_window->show(); + } + + void ShaderManagementConsoleApplication::DestroyMainWindow() + { + m_window.reset(); + } + + AZ::Data::AssetInfo ShaderManagementConsoleApplication::GetSourceAssetInfo(const AZStd::string& sourceAssetFileName) + { + bool result = false; + AZ::Data::AssetInfo assetInfo; + AZStd::string watchFolder; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult( + result, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, sourceAssetFileName.c_str(), assetInfo, + watchFolder); + AZ_Error(nullptr, result, "Failed to get the asset info for the file: %s.", sourceAssetFileName.c_str()); + + return assetInfo; + } + + AZStd::vector ShaderManagementConsoleApplication::FindMaterialAssetsUsingShader(const AZStd::string& shaderFilePath) + { + // Collect the material types referencing the shader + AZStd::vector materialTypeSources; + + AzToolsFramework::AssetDatabase::AssetDatabaseConnection assetDatabaseConnection; + assetDatabaseConnection.OpenDatabase(); + + assetDatabaseConnection.QuerySourceDependencyByDependsOnSource( + shaderFilePath.c_str(), nullptr, AzToolsFramework::AssetDatabase::SourceFileDependencyEntry::DEP_Any, + [&](AzToolsFramework::AssetDatabase::SourceFileDependencyEntry& sourceFileDependencyEntry) + { + AZStd::string assetExtension; + if (AzFramework::StringFunc::Path::GetExtension(sourceFileDependencyEntry.m_source.c_str(), assetExtension, false)) + { + if (assetExtension == "materialtype") + { + materialTypeSources.push_back(sourceFileDependencyEntry.m_source); + } + } + return true; + }); + + AzToolsFramework::AssetDatabase::ProductDatabaseEntryContainer productDependencies; + for (const auto& materialTypeSource : materialTypeSources) + { + bool result = false; + AZ::Data::AssetInfo materialTypeSourceAssetInfo; + AZStd::string watchFolder; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult( + result, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, materialTypeSource.c_str(), + materialTypeSourceAssetInfo, watchFolder); + + assetDatabaseConnection.QueryDirectReverseProductDependenciesBySourceGuidSubId( + materialTypeSourceAssetInfo.m_assetId.m_guid, materialTypeSourceAssetInfo.m_assetId.m_subId, + [&](AzToolsFramework::AssetDatabase::ProductDatabaseEntry& entry) + { + AZStd::string assetExtension; + if (AzFramework::StringFunc::Path::GetExtension(entry.m_productName.c_str(), assetExtension, false)) + { + if (assetExtension == "azmaterial") + { + productDependencies.push_back(entry); + } + } + return true; + }); + } + + AZStd::vector results; + results.reserve(productDependencies.size()); + for (auto product : productDependencies) + { + assetDatabaseConnection.QueryCombinedByProductID( + product.m_productID, + [&](AzToolsFramework::AssetDatabase::CombinedDatabaseEntry& combined) + { + results.push_back({ combined.m_sourceGuid, combined.m_subID }); + return false; + }, + nullptr); + } + return results; + } + + AZStd::vector ShaderManagementConsoleApplication::GetMaterialInstanceShaderItems( + const AZ::Data::AssetId& assetId) + { + auto materialAsset = AZ::RPI::AssetUtils::LoadAssetById(assetId, AZ::RPI::AssetUtils::TraceLevel::Error); + + auto materialInstance = AZ::RPI::Material::Create(materialAsset); + AZ_Error( + nullptr, materialAsset, "Failed to get a material instance from product asset id: %s", + assetId.ToString().c_str()); + + if (materialInstance != nullptr) + { + return AZStd::vector( + materialInstance->GetShaderCollection().begin(), materialInstance->GetShaderCollection().end()); + } + return AZStd::vector(); + } } // namespace ShaderManagementConsole diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.h index 6b0365e6bd..3bb62d0756 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.h +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleApplication.h @@ -8,12 +8,21 @@ #pragma once +#include #include +#include +#include +#include +#include +#include namespace ShaderManagementConsole { class ShaderManagementConsoleApplication : public AtomToolsFramework::AtomToolsDocumentApplication + , private ShaderManagementConsoleRequestBus::Handler + , private AtomToolsFramework::AtomToolsMainWindowFactoryRequestBus::Handler + , private AzToolsFramework::EditorWindowRequestBus::Handler { public: AZ_TYPE_INFO(ShaderManagementConsole::ShaderManagementConsoleApplication, "{A31B1AEB-4DA3-49CD-884A-CC998FF7546F}"); @@ -21,13 +30,31 @@ namespace ShaderManagementConsole using Base = AtomToolsFramework::AtomToolsDocumentApplication; ShaderManagementConsoleApplication(int* argc, char*** argv); + ~ShaderManagementConsoleApplication(); // AzFramework::Application overrides... - void CreateStaticModules(AZStd::vector& outModules) override; + void Reflect(AZ::ReflectContext* context) override; const char* GetCurrentConfigurationName() const override; + void StartCommon(AZ::Entity* systemEntity) override; // AtomToolsFramework::AtomToolsApplication overrides... AZStd::string GetBuildTargetName() const override; AZStd::vector GetCriticalAssetFilters() const override; + + // AzToolsFramework::EditorWindowRequests::Bus::Handler + QWidget* GetAppMainWindow() override; + + // AtomToolsMainWindowFactoryRequestBus::Handler overrides... + void CreateMainWindow() override; + void DestroyMainWindow() override; + + // ShaderManagementConsoleRequestBus::Handler overrides... + AZ::Data::AssetInfo GetSourceAssetInfo(const AZStd::string& sourceAssetFileName) override; + AZStd::vector FindMaterialAssetsUsingShader(const AZStd::string& shaderFilePath) override; + AZStd::vector GetMaterialInstanceShaderItems(const AZ::Data::AssetId& assetId) override; + + private: + AZStd::unique_ptr m_window; + AZStd::unique_ptr m_assetBrowserInteractions; }; } // namespace ShaderManagementConsole diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Include/Atom/Core/ShaderManagementConsoleRequestBus.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleRequestBus.h similarity index 100% rename from Gems/Atom/Tools/ShaderManagementConsole/Code/Include/Atom/Core/ShaderManagementConsoleRequestBus.h rename to Gems/Atom/Tools/ShaderManagementConsole/Code/Source/ShaderManagementConsoleRequestBus.h diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleBrowserWidget.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleBrowserWidget.cpp deleted file mode 100644 index eb863a195a..0000000000 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleBrowserWidget.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include -#include -#include -AZ_POP_DISABLE_WARNING - -namespace ShaderManagementConsole -{ - ShaderManagementConsoleBrowserWidget::ShaderManagementConsoleBrowserWidget(QWidget* parent) - : QWidget(parent) - , m_ui(new Ui::ShaderManagementConsoleBrowserWidget) - { - using namespace AzToolsFramework::AssetBrowser; - - m_ui->setupUi(this); - - m_ui->m_searchWidget->Setup(true, true); - m_ui->m_searchWidget->SetFilterState("", AZ::RPI::ShaderAsset::Group, true); - m_ui->m_searchWidget->setMinimumSize(QSize(150, 0)); - - // Get the asset browser model - AssetBrowserModel* assetBrowserModel = nullptr; - AssetBrowserComponentRequestBus::BroadcastResult(assetBrowserModel, &AssetBrowserComponentRequests::GetAssetBrowserModel); - AZ_Assert(assetBrowserModel, "Failed to get file browser model"); - - // Hook up the data set to the tree view - m_filterModel = aznew AssetBrowserFilterModel(this); - m_filterModel->setSourceModel(assetBrowserModel); - m_filterModel->SetFilter(CreateFilter()); - - m_ui->m_assetBrowserTreeViewWidget->setModel(m_filterModel); - m_ui->m_assetBrowserTreeViewWidget->SetShowSourceControlIcons(true); - m_ui->m_assetBrowserTreeViewWidget->setSelectionMode(QAbstractItemView::SelectionMode::ExtendedSelection); - - // Maintains the tree expansion state between runs - m_ui->m_assetBrowserTreeViewWidget->SetName("AssetBrowserTreeView_main"); - - connect(m_ui->m_searchWidget->GetFilter().data(), &AssetBrowserEntryFilter::updatedSignal, m_filterModel, &AssetBrowserFilterModel::filterUpdatedSlot); - connect(m_filterModel, &AssetBrowserFilterModel::filterChanged, this, [this]() - { - const bool hasFilter = !m_ui->m_searchWidget->GetFilterString().isEmpty(); - constexpr bool selectFirstFilteredIndex = true; - m_ui->m_assetBrowserTreeViewWidget->UpdateAfterFilter(hasFilter, selectFirstFilteredIndex); - }); - connect(m_ui->m_assetBrowserTreeViewWidget, &AssetBrowserTreeView::activated, this, &ShaderManagementConsoleBrowserWidget::OpenSelectedEntries); - connect(m_ui->m_assetBrowserTreeViewWidget, &AssetBrowserTreeView::selectionChangedSignal, [this]() { - const auto& selectedAssets = m_ui->m_assetBrowserTreeViewWidget->GetSelectedAssets(); - if (!selectedAssets.empty()) - { - m_ui->m_previewerFrame->Display(selectedAssets.front()); - } - else - { - m_ui->m_previewerFrame->Clear(); - } - }); - - AssetBrowserModelNotificationBus::Handler::BusConnect(); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect(); - } - - ShaderManagementConsoleBrowserWidget::~ShaderManagementConsoleBrowserWidget() - { - // Maintains the tree expansion state between runs - m_ui->m_assetBrowserTreeViewWidget->SaveState(); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect(); - AssetBrowserModelNotificationBus::Handler::BusDisconnect(); - } - - AzToolsFramework::AssetBrowser::FilterConstType ShaderManagementConsoleBrowserWidget::CreateFilter() const - { - using namespace AzToolsFramework::AssetBrowser; - - QSharedPointer sourceFilter(new EntryTypeFilter); - sourceFilter->SetEntryType(AssetBrowserEntry::AssetEntryType::Source); - - QSharedPointer folderFilter(new EntryTypeFilter); - folderFilter->SetEntryType(AssetBrowserEntry::AssetEntryType::Folder); - - QSharedPointer sourceOrFolderFilter(new CompositeFilter(CompositeFilter::LogicOperatorType::OR)); - sourceOrFolderFilter->AddFilter(sourceFilter); - sourceOrFolderFilter->AddFilter(folderFilter); - - QSharedPointer finalFilter(new CompositeFilter(CompositeFilter::LogicOperatorType::AND)); - finalFilter->AddFilter(sourceOrFolderFilter); - finalFilter->AddFilter(m_ui->m_searchWidget->GetFilter()); - - return finalFilter; - } - - void ShaderManagementConsoleBrowserWidget::OpenSelectedEntries() - { - const AZStd::vector entries = m_ui->m_assetBrowserTreeViewWidget->GetSelectedAssets(); - - const int multiSelectPromptThreshold = 10; - if (entries.size() >= multiSelectPromptThreshold) - { - if (QMessageBox::question( - QApplication::activeWindow(), - QString("Attemptng to open %1 files").arg(entries.size()), - "Would you like to open anyway?", - QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) - { - return; - } - } - - for (const AssetBrowserEntry* entry : entries) - { - const SourceAssetBrowserEntry* sourceEntry = azrtti_cast(entry); - if (!sourceEntry) - { - const ProductAssetBrowserEntry* productEntry = azrtti_cast(entry); - if (productEntry) - { - sourceEntry = azrtti_cast(productEntry->GetParent()); - } - } - - if (sourceEntry) - { - if (AzFramework::StringFunc::Path::IsExtension(sourceEntry->GetFullPath().c_str(), AZ::RPI::ShaderVariantListSourceData::Extension)) - { - AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, sourceEntry->GetFullPath()); - } - else - { - QDesktopServices::openUrl(QUrl::fromLocalFile(sourceEntry->GetFullPath().c_str())); - } - } - } - } - - void ShaderManagementConsoleBrowserWidget::EntryAdded(const AssetBrowserEntry* entry) - { - if (m_pathToSelect.empty()) - { - return; - } - - const SourceAssetBrowserEntry* sourceEntry = azrtti_cast(entry); - if (!sourceEntry) - { - const ProductAssetBrowserEntry* productEntry = azrtti_cast(entry); - if (productEntry) - { - sourceEntry = azrtti_cast(productEntry->GetParent()); - } - } - - if (sourceEntry) - { - AZStd::string sourcePath = sourceEntry->GetFullPath(); - AzFramework::StringFunc::Path::Normalize(sourcePath); - if (m_pathToSelect == sourcePath) - { - m_ui->m_assetBrowserTreeViewWidget->SelectFileAtPath(m_pathToSelect); - m_pathToSelect.clear(); - } - } - } - - void ShaderManagementConsoleBrowserWidget::OnDocumentOpened(const AZ::Uuid& documentId) - { - AZStd::string absolutePath; - AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(absolutePath, documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetAbsolutePath); - if (!absolutePath.empty()) - { - m_pathToSelect = absolutePath; - AzFramework::StringFunc::Path::Normalize(m_pathToSelect); - m_ui->m_assetBrowserTreeViewWidget->SelectFileAtPath(m_pathToSelect); - } - } - -} // namespace ShaderManagementConsole - -#include diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp index 8e8e047e83..f4672d670e 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.cpp @@ -6,15 +6,17 @@ * */ -#include #include #include #include #include +#include #include +#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include +#include #include #include #include @@ -39,10 +41,6 @@ namespace ShaderManagementConsole setObjectName("ShaderManagementConsoleWindow"); - m_toolBar = new ShaderManagementConsoleToolBar(this); - m_toolBar->setObjectName("ToolBar"); - addToolBar(m_toolBar); - m_assetBrowser->SetFilterState("", AZ::RPI::ShaderAsset::Group, true); m_assetBrowser->SetOpenHandler([](const AZStd::string& absolutePath) { if (AzFramework::StringFunc::Path::IsExtension(absolutePath.c_str(), AZ::RPI::ShaderVariantListSourceData::Extension)) @@ -63,10 +61,19 @@ namespace ShaderManagementConsole m_actionNew->setEnabled(false); m_actionSaveAsChild->setVisible(false); m_actionSaveAsChild->setEnabled(false); + m_actionSaveAll->setVisible(false); + m_actionSaveAll->setEnabled(false); OnDocumentOpened(AZ::Uuid::CreateNull()); } + bool ShaderManagementConsoleWindow::GetOpenDocumentParams(AZStd::string& openPath) + { + openPath = QFileDialog::getOpenFileName( + this, tr("Open Document"), AZ::Utils::GetProjectPath().c_str(), tr("Files (*.%1)").arg(AZ::RPI::ShaderVariantListSourceData::Extension)).toUtf8().constData(); + return !openPath.empty(); + } + QWidget* ShaderManagementConsoleWindow::CreateDocumentTabView(const AZ::Uuid& documentId) { AZStd::unordered_set optionNames; diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.h index 1c7479e526..d5dd04c434 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.h +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindow.h @@ -14,7 +14,6 @@ #include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include #include AZ_POP_DISABLE_WARNING #endif @@ -36,8 +35,7 @@ namespace ShaderManagementConsole ~ShaderManagementConsoleWindow() = default; protected: + bool GetOpenDocumentParams(AZStd::string& openPath) override; QWidget* CreateDocumentTabView(const AZ::Uuid& documentId) override; - - ShaderManagementConsoleToolBar* m_toolBar = {}; }; } // namespace ShaderManagementConsole diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindowComponent.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindowComponent.cpp deleted file mode 100644 index a59712d572..0000000000 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindowComponent.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include -#include -#include -AZ_POP_DISABLE_WARNING - -namespace ShaderManagementConsole -{ - void ShaderManagementConsoleWindowComponent::Reflect(AZ::ReflectContext* context) - { - if (AZ::SerializeContext* serialize = azrtti_cast(context)) - { - serialize->Class() - ->Version(0); - } - - if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) - { - behaviorContext->EBus("ShaderManagementConsoleRequestBus") - ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation) - ->Attribute(AZ::Script::Attributes::Category, "Editor") - ->Attribute(AZ::Script::Attributes::Module, "shadermanagementconsole") - ->Event("GetSourceAssetInfo", &ShaderManagementConsoleRequestBus::Events::GetSourceAssetInfo) - ->Event("FindMaterialAssetsUsingShader", &ShaderManagementConsoleRequestBus::Events::FindMaterialAssetsUsingShader ) - ->Event("GetMaterialInstanceShaderItems", &ShaderManagementConsoleRequestBus::Events::GetMaterialInstanceShaderItems) - ; - } - } - - void ShaderManagementConsoleWindowComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) - { - required.push_back(AZ_CRC_CE("AssetBrowserService")); - required.push_back(AZ_CRC_CE("PropertyManagerService")); - required.push_back(AZ_CRC_CE("SourceControlService")); - required.push_back(AZ_CRC_CE("AtomToolsMainWindowSystemService")); - } - - void ShaderManagementConsoleWindowComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) - { - provided.push_back(AZ_CRC_CE("ShaderManagementConsoleWindowService")); - } - - void ShaderManagementConsoleWindowComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) - { - incompatible.push_back(AZ_CRC_CE("ShaderManagementConsoleWindowService")); - } - - void ShaderManagementConsoleWindowComponent::Init() - { - } - - void ShaderManagementConsoleWindowComponent::Activate() - { - AzToolsFramework::EditorWindowRequestBus::Handler::BusConnect(); - AtomToolsFramework::AtomToolsMainWindowFactoryRequestBus::Handler::BusConnect(); - ShaderManagementConsoleRequestBus::Handler::BusConnect(); - AzToolsFramework::SourceControlConnectionRequestBus::Broadcast(&AzToolsFramework::SourceControlConnectionRequests::EnableSourceControl, true); - } - - void ShaderManagementConsoleWindowComponent::Deactivate() - { - ShaderManagementConsoleRequestBus::Handler::BusDisconnect(); - AtomToolsFramework::AtomToolsMainWindowFactoryRequestBus::Handler::BusDisconnect(); - AzToolsFramework::EditorWindowRequestBus::Handler::BusDisconnect(); - - m_window.reset(); - } - - QWidget* ShaderManagementConsoleWindowComponent::GetAppMainWindow() - { - return m_window.get(); - } - - void ShaderManagementConsoleWindowComponent::CreateMainWindow() - { - m_assetBrowserInteractions.reset(aznew ShaderManagementConsoleBrowserInteractions); - - m_window.reset(aznew ShaderManagementConsoleWindow); - m_window->show(); - } - - void ShaderManagementConsoleWindowComponent::DestroyMainWindow() - { - m_window.reset(); - } - - AZ::Data::AssetInfo ShaderManagementConsoleWindowComponent::GetSourceAssetInfo(const AZStd::string& sourceAssetFileName) - { - bool result = false; - AZ::Data::AssetInfo assetInfo; - AZStd::string watchFolder; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - result, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, sourceAssetFileName.c_str(), assetInfo, - watchFolder); - AZ_Error(nullptr, result, "Failed to get the asset info for the file: %s.", sourceAssetFileName.c_str()); - - return assetInfo; - } - - AZStd::vector ShaderManagementConsoleWindowComponent::FindMaterialAssetsUsingShader(const AZStd::string& shaderFilePath) - { - // Collect the material types referencing the shader - AZStd::vector materialTypeSources; - - AzToolsFramework::AssetDatabase::AssetDatabaseConnection assetDatabaseConnection; - assetDatabaseConnection.OpenDatabase(); - - assetDatabaseConnection.QuerySourceDependencyByDependsOnSource( - shaderFilePath.c_str(), - nullptr, - AzToolsFramework::AssetDatabase::SourceFileDependencyEntry::DEP_Any, - [&](AzToolsFramework::AssetDatabase::SourceFileDependencyEntry& sourceFileDependencyEntry) { - AZStd::string assetExtension; - if (AzFramework::StringFunc::Path::GetExtension(sourceFileDependencyEntry.m_source.c_str(), assetExtension, false)) - { - if (assetExtension == "materialtype") - { - materialTypeSources.push_back(sourceFileDependencyEntry.m_source); - } - } - return true; - }); - - AzToolsFramework::AssetDatabase::ProductDatabaseEntryContainer productDependencies; - for (const auto& materialTypeSource : materialTypeSources) - { - bool result = false; - AZ::Data::AssetInfo materialTypeSourceAssetInfo; - AZStd::string watchFolder; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - result, - &AzToolsFramework::AssetSystem::AssetSystemRequest::GetSourceInfoBySourcePath, - materialTypeSource.c_str(), - materialTypeSourceAssetInfo, - watchFolder - ); - - assetDatabaseConnection.QueryDirectReverseProductDependenciesBySourceGuidSubId( - materialTypeSourceAssetInfo.m_assetId.m_guid, - materialTypeSourceAssetInfo.m_assetId.m_subId, - [&](AzToolsFramework::AssetDatabase::ProductDatabaseEntry& entry) { - AZStd::string assetExtension; - if (AzFramework::StringFunc::Path::GetExtension(entry.m_productName.c_str(), assetExtension, false)) - { - if (assetExtension == "azmaterial") - { - productDependencies.push_back(entry); - } - } - return true; - }); - } - - AZStd::vector results; - results.reserve(productDependencies.size()); - for (auto product : productDependencies) - { - assetDatabaseConnection.QueryCombinedByProductID( - product.m_productID, - [&](AzToolsFramework::AssetDatabase::CombinedDatabaseEntry& combined) { - results.push_back({combined.m_sourceGuid, combined.m_subID}); - return false; - }, - nullptr - ); - } - return results; - } - - AZStd::vector ShaderManagementConsoleWindowComponent::GetMaterialInstanceShaderItems(const AZ::Data::AssetId& assetId) - { - auto materialAsset = AZ::RPI::AssetUtils::LoadAssetById(assetId, AZ::RPI::AssetUtils::TraceLevel::Error); - - auto materialInstance = AZ::RPI::Material::Create(materialAsset); - AZ_Error(nullptr, materialAsset, "Failed to get a material instance from product asset id: %s", assetId.ToString().c_str()); - - if (materialInstance != nullptr) - { - return AZStd::vector(materialInstance->GetShaderCollection().begin(), materialInstance->GetShaderCollection().end()); - } - return AZStd::vector(); - } -} diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindowComponent.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindowComponent.h deleted file mode 100644 index aab0f7ce37..0000000000 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindowComponent.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -#include - -#include -#include - -#include -#include - -namespace ShaderManagementConsole -{ - //! ShaderManagementConsoleWindowComponent is the entry point for the Shader Management Console gem user interface, and is mainly - //! used for initialization and registration of other classes, including ShaderManagementConsoleWindow. - class ShaderManagementConsoleWindowComponent - : public AZ::Component - , private AtomToolsFramework::AtomToolsMainWindowFactoryRequestBus::Handler - , private ShaderManagementConsoleRequestBus::Handler - , private AzToolsFramework::EditorWindowRequestBus::Handler - { - public: - AZ_COMPONENT(ShaderManagementConsoleWindowComponent, "{03976F19-3C74-49FE-A15F-7D3CADBA616C}"); - - static void Reflect(AZ::ReflectContext* context); - - static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); - static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); - static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); - - private: - // Temporary structure when generating shader variants. - struct ShaderVariantListInfo - { - AZStd::string m_materialFileName; - AZStd::vector m_shaderItems; - }; - - ////////////////////////////////////////////////////////////////////////// - // AzToolsFramework::EditorWindowRequests::Bus::Handler - QWidget* GetAppMainWindow() override; - ////////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////// - // AtomToolsMainWindowFactoryRequestBus::Handler overrides... - void CreateMainWindow() override; - void DestroyMainWindow() override; - //////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////// - // ShaderManagementConsoleRequestBus::Handler overrides... - AZ::Data::AssetInfo GetSourceAssetInfo(const AZStd::string& sourceAssetFileName) override; - AZStd::vector FindMaterialAssetsUsingShader(const AZStd::string& shaderFilePath) override; - AZStd::vector GetMaterialInstanceShaderItems(const AZ::Data::AssetId& assetId) override; - //////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////// - // AZ::Component interface implementation - void Init() override; - void Activate() override; - void Deactivate() override; - //////////////////////////////////////////////////////////////////////// - - AZStd::unique_ptr m_window; - AZStd::unique_ptr m_assetBrowserInteractions; - }; -} diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindowModule.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindowModule.cpp deleted file mode 100644 index a13b873aee..0000000000 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ShaderManagementConsoleWindowModule.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include - -void InitShaderManagementConsoleResources() -{ - // Must register qt resources from other modules - Q_INIT_RESOURCE(ShaderManagementConsole); - Q_INIT_RESOURCE(InspectorWidget); - Q_INIT_RESOURCE(AtomToolsAssetBrowser); -} - -namespace ShaderManagementConsole -{ - ShaderManagementConsoleWindowModule::ShaderManagementConsoleWindowModule() - { - InitShaderManagementConsoleResources(); - - // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here. - m_descriptors.insert(m_descriptors.end(), { - ShaderManagementConsoleWindowComponent::CreateDescriptor(), - }); - } - - AZ::ComponentTypeList ShaderManagementConsoleWindowModule::GetRequiredSystemComponents() const - { - return AZ::ComponentTypeList{ - azrtti_typeid(), - }; - } -} // namespace ShaderManagementConsole diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ToolBar/ShaderManagementConsoleToolBar.cpp b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ToolBar/ShaderManagementConsoleToolBar.cpp deleted file mode 100644 index 5699713240..0000000000 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ToolBar/ShaderManagementConsoleToolBar.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include - -AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include -#include -#include -#include -AZ_POP_DISABLE_WARNING - -namespace ShaderManagementConsole -{ - ShaderManagementConsoleToolBar::ShaderManagementConsoleToolBar(QWidget* parent) - : QToolBar(parent) - { - AzQtComponents::ToolBar::addMainToolBarStyle(this); - } - - ShaderManagementConsoleToolBar::~ShaderManagementConsoleToolBar() - { - } -} // namespace ShaderManagementConsole - -#include diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ToolBar/ShaderManagementConsoleToolBar.h b/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ToolBar/ShaderManagementConsoleToolBar.h deleted file mode 100644 index c4d300d4e0..0000000000 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/Source/Window/ToolBar/ShaderManagementConsoleToolBar.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#endif - -namespace ShaderManagementConsole -{ - class ModelComboBox; - class LightingPresetComboBox; - - class ShaderManagementConsoleToolBar - : public QToolBar - { - Q_OBJECT - public: - - ShaderManagementConsoleToolBar(QWidget* parent = 0); - ~ShaderManagementConsoleToolBar(); - - private: - }; -} // namespace ShaderManagementConsole diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/shadermanagementconsole_files.cmake b/Gems/Atom/Tools/ShaderManagementConsole/Code/shadermanagementconsole_files.cmake index e832ba2784..dac14b7f16 100644 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/shadermanagementconsole_files.cmake +++ b/Gems/Atom/Tools/ShaderManagementConsole/Code/shadermanagementconsole_files.cmake @@ -7,8 +7,19 @@ # set(FILES + Source/Document/ShaderManagementConsoleDocumentRequestBus.h + Source/Document/ShaderManagementConsoleDocument.cpp + Source/Document/ShaderManagementConsoleDocument.h + + Source/Window/ShaderManagementConsoleBrowserInteractions.h + Source/Window/ShaderManagementConsoleBrowserInteractions.cpp + Source/Window/ShaderManagementConsoleWindow.h + Source/Window/ShaderManagementConsoleWindow.cpp + Source/Window/ShaderManagementConsole.qrc + Source/main.cpp Source/ShaderManagementConsoleApplication.cpp Source/ShaderManagementConsoleApplication.h + Source/ShaderManagementConsoleRequestBus.h ../Scripts/GenerateShaderVariantListForMaterials.py ) diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/shadermanagementconsoledocument_files.cmake b/Gems/Atom/Tools/ShaderManagementConsole/Code/shadermanagementconsoledocument_files.cmake deleted file mode 100644 index 220d2895ac..0000000000 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/shadermanagementconsoledocument_files.cmake +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. -# For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -set(FILES - Include/Atom/Document/ShaderManagementConsoleDocumentModule.h - Include/Atom/Document/ShaderManagementConsoleDocumentRequestBus.h - Source/Document/ShaderManagementConsoleDocument.cpp - Source/Document/ShaderManagementConsoleDocument.h - Source/Document/ShaderManagementConsoleDocumentModule.cpp - Source/Document/ShaderManagementConsoleDocumentSystemComponent.cpp - Source/Document/ShaderManagementConsoleDocumentSystemComponent.h -) diff --git a/Gems/Atom/Tools/ShaderManagementConsole/Code/shadermanagementconsolewindow_files.cmake b/Gems/Atom/Tools/ShaderManagementConsole/Code/shadermanagementconsolewindow_files.cmake deleted file mode 100644 index fb5cc0dad6..0000000000 --- a/Gems/Atom/Tools/ShaderManagementConsole/Code/shadermanagementconsolewindow_files.cmake +++ /dev/null @@ -1,22 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. -# For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -set(FILES - Include/Atom/Window/ShaderManagementConsoleWindowModule.h - Include/Atom/Core/ShaderManagementConsoleRequestBus.h - Source/Window/ShaderManagementConsoleBrowserInteractions.h - Source/Window/ShaderManagementConsoleBrowserInteractions.cpp - Source/Window/ShaderManagementConsoleWindow.h - Source/Window/ShaderManagementConsoleWindow.cpp - Source/Window/ShaderManagementConsoleWindowModule.cpp - Source/Window/ShaderManagementConsole.qrc - Source/Window/ShaderManagementConsoleWindowComponent.h - Source/Window/ShaderManagementConsoleWindowComponent.cpp - Source/Window/ToolBar/ShaderManagementConsoleToolBar.h - Source/Window/ToolBar/ShaderManagementConsoleToolBar.cpp -) From bd57a2832b7d213aace029d2513c41a4c133adad Mon Sep 17 00:00:00 2001 From: Nana Axel Date: Thu, 20 Jan 2022 23:27:29 +0100 Subject: [PATCH 048/136] Fix issues when configuring projects and gems (#7001) The new `o3de_pal_dir` function raise an issue when configuring projects/gems. This commit apply a simple fix to pass parameters as strings. Signed-off-by: Axel Nana --- Templates/DefaultGem/Template/CMakeLists.txt | 2 +- Templates/DefaultGem/Template/Code/CMakeLists.txt | 2 +- Templates/MinimalProject/Template/Gem/CMakeLists.txt | 2 +- cmake/3rdParty.cmake | 6 +++--- cmake/3rdParty/BuiltInPackages.cmake | 2 +- cmake/Configurations.cmake | 2 +- cmake/Install.cmake | 2 +- cmake/LYTestWrappers.cmake | 2 +- cmake/LYWrappers.cmake | 2 +- cmake/PAL.cmake | 6 +++--- cmake/Packaging.cmake | 2 +- cmake/RuntimeDependencies.cmake | 2 +- 12 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Templates/DefaultGem/Template/CMakeLists.txt b/Templates/DefaultGem/Template/CMakeLists.txt index f4c55dd1a5..4d1bb2308c 100644 --- a/Templates/DefaultGem/Template/CMakeLists.txt +++ b/Templates/DefaultGem/Template/CMakeLists.txt @@ -10,7 +10,7 @@ set(gem_path ${CMAKE_CURRENT_LIST_DIR}) set(gem_json ${gem_path}/gem.json) o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) -o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} "${gem_restricted_path}" "${gem_path}" "${gem_parent_relative_path}") # Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the # project cmake for this platform. diff --git a/Templates/DefaultGem/Template/Code/CMakeLists.txt b/Templates/DefaultGem/Template/Code/CMakeLists.txt index c5ff305b2a..282734a191 100644 --- a/Templates/DefaultGem/Template/Code/CMakeLists.txt +++ b/Templates/DefaultGem/Template/Code/CMakeLists.txt @@ -12,7 +12,7 @@ # in which case it will see if that platform is present here or in the restricted folder. # i.e. It could here in our gem : Gems/${Name}/Code/Platform/ or # //Gems/${Name}/Code -o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_gem_restricted_path} ${o3de_gem_path} ${o3de_gem_name}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} "${gem_restricted_path}" "${gem_path}" "${gem_name}") # Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the # traits for this platform. Traits for a platform are defines for things like whether or not something in this gem diff --git a/Templates/MinimalProject/Template/Gem/CMakeLists.txt b/Templates/MinimalProject/Template/Gem/CMakeLists.txt index 6b1dcf9172..f23bc9d954 100644 --- a/Templates/MinimalProject/Template/Gem/CMakeLists.txt +++ b/Templates/MinimalProject/Template/Gem/CMakeLists.txt @@ -16,7 +16,7 @@ o3de_restricted_path(${gem_json} gem_restricted_path gem_parent_relative_path) # in which case it will see if that platform is present here or in the restricted folder. # i.e. It could here : ${Name}/Code/Platform/ or # //${Name}/Code -o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${gem_restricted_path} ${gem_path} ${gem_parent_relative_path}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} "${gem_restricted_path}" "${gem_path}" "${gem_parent_relative_path}") # Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the # traits for this platform. Traits for a platform are defines for things like whether or not something in this project diff --git a/cmake/3rdParty.cmake b/cmake/3rdParty.cmake index 1bea5f4f67..e9dd00dbdb 100644 --- a/cmake/3rdParty.cmake +++ b/cmake/3rdParty.cmake @@ -186,7 +186,7 @@ function(ly_add_external_target) endif() # Check if there is a pal file - o3de_pal_dir(pal_file ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}/${ly_add_external_target_PACKAGE}_${PAL_PLATFORM_NAME_LOWERCASE}.cmake ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) + o3de_pal_dir(pal_file ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}/${ly_add_external_target_PACKAGE}_${PAL_PLATFORM_NAME_LOWERCASE}.cmake "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}") if(NOT EXISTS ${pal_file}) set(pal_file ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}/${ly_add_external_target_PACKAGE}_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) endif() @@ -357,12 +357,12 @@ endfunction() # Add the 3rdParty folder to find the modules list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/3rdParty) -o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/3rdParty/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/3rdParty/Platform/${PAL_PLATFORM_NAME} "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}") list(APPEND CMAKE_MODULE_PATH ${pal_dir}) if(NOT INSTALLED_ENGINE) # Add the 3rdParty cmake files to the IDE ly_include_cmake_file_list(cmake/3rdParty/cmake_files.cmake) - o3de_pal_dir(pal_3rdparty_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) + o3de_pal_dir(pal_3rdparty_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/3rdParty/Platform/${PAL_PLATFORM_NAME} "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}") ly_include_cmake_file_list(${pal_3rdparty_dir}/cmake_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake) endif() diff --git a/cmake/3rdParty/BuiltInPackages.cmake b/cmake/3rdParty/BuiltInPackages.cmake index e81cfffe01..63500a3f1e 100644 --- a/cmake/3rdParty/BuiltInPackages.cmake +++ b/cmake/3rdParty/BuiltInPackages.cmake @@ -12,7 +12,7 @@ # cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake #include the platform-specific 3rd party packages. -o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}") set(LY_PAL_PACKAGE_FILE_NAME ${pal_dir}/BuiltInPackages_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) include(${LY_PAL_PACKAGE_FILE_NAME}) diff --git a/cmake/Configurations.cmake b/cmake/Configurations.cmake index ee2b2fc96b..63af3d8810 100644 --- a/cmake/Configurations.cmake +++ b/cmake/Configurations.cmake @@ -204,5 +204,5 @@ foreach(conf IN LISTS CMAKE_CONFIGURATION_TYPES) endforeach() # flags are defined per platform, follow platform files under Platform//Configurations_.cmake -o3de_pal_dir(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}") include(${pal_dir}/Configurations_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) diff --git a/cmake/Install.cmake b/cmake/Install.cmake index 55f56b05e8..7320ff7016 100644 --- a/cmake/Install.cmake +++ b/cmake/Install.cmake @@ -195,6 +195,6 @@ function(ly_install_run_script SCRIPT) endfunction() if(LY_INSTALL_ENABLED) - o3de_pal_dir(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) + o3de_pal_dir(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}") include(${pal_dir}/Install_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) endif() diff --git a/cmake/LYTestWrappers.cmake b/cmake/LYTestWrappers.cmake index 9f4cd41a47..014b02631f 100644 --- a/cmake/LYTestWrappers.cmake +++ b/cmake/LYTestWrappers.cmake @@ -141,7 +141,7 @@ function(ly_add_test) set(wrapper_file ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}/LYTestWrappers_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) if(NOT EXISTS ${wrapper_file}) - o3de_pal_dir(wrapper_file ${wrapper_file} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) + o3de_pal_dir(wrapper_file ${wrapper_file} "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}") endif() include(${wrapper_file}) diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index a2f4359fd5..cb3a07678c 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -11,7 +11,7 @@ set(LY_UNITY_BUILD ON CACHE BOOL "UNITY builds") include(CMakeFindDependencyMacro) include(cmake/LyAutoGen.cmake) -o3de_pal_dir(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}") include(${pal_dir}/LYWrappers_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) # Not all platforms support unity builds diff --git a/cmake/PAL.cmake b/cmake/PAL.cmake index 0359408200..a43e601c74 100644 --- a/cmake/PAL.cmake +++ b/cmake/PAL.cmake @@ -322,9 +322,9 @@ function(ly_get_absolute_pal_filename out_name in_name) endif() if(${ARGC} GREATER 4) - o3de_pal_dir(abs_name ${in_name} ${object_restricted_path} ${object_path} ${parent_relative_path}) + o3de_pal_dir(abs_name ${in_name} "${object_restricted_path}" "${object_path}" "${parent_relative_path}") else() - o3de_pal_dir(abs_name ${in_name} ${object_restricted_path} ${object_path}) + o3de_pal_dir(abs_name ${in_name} "${object_restricted_path}" "${object_path}") endif() set(${out_name} ${abs_name} PARENT_SCOPE) endfunction() @@ -433,7 +433,7 @@ function(ly_get_list_relative_pal_filename out_name in_name) set(${out_name} ${relative_name} PARENT_SCOPE) endfunction() -o3de_pal_dir(pal_cmake_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) +o3de_pal_dir(pal_cmake_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}") ly_include_cmake_file_list(${pal_cmake_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 81409369dc..83bf95b330 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -73,7 +73,7 @@ set(CPACK_PROJECT_CONFIG_FILE ${CPACK_SOURCE_DIR}/PackagingConfig.cmake) set(CPACK_AUTO_GEN_TAG ${LY_INSTALLER_AUTO_GEN_TAG}) # attempt to apply platform specific settings -o3de_pal_dir(pal_dir ${CPACK_SOURCE_DIR}/Platform/${PAL_HOST_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) +o3de_pal_dir(pal_dir ${CPACK_SOURCE_DIR}/Platform/${PAL_HOST_PLATFORM_NAME} "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}") include(${pal_dir}/Packaging_${PAL_HOST_PLATFORM_NAME_LOWERCASE}.cmake) # if we get here and the generator hasn't been set, then a non fatal error occurred disabling packaging support diff --git a/cmake/RuntimeDependencies.cmake b/cmake/RuntimeDependencies.cmake index d36789791f..aa84d97ab3 100644 --- a/cmake/RuntimeDependencies.cmake +++ b/cmake/RuntimeDependencies.cmake @@ -6,6 +6,6 @@ # # -o3de_pal_dir(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} ${O3DE_ENGINE_RESTRICTED_PATH} ${LY_ROOT_FOLDER}) +o3de_pal_dir(pal_dir ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Platform/${PAL_PLATFORM_NAME} "${O3DE_ENGINE_RESTRICTED_PATH}" "${LY_ROOT_FOLDER}") include(${pal_dir}/RuntimeDependencies_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) From dac77605d923159ddde84d56ed331a14e10b532c Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 20 Jan 2022 16:29:11 -0600 Subject: [PATCH 049/136] Atom Tools: removing unused traits for ME executable extension Signed-off-by: Guthrie Adams --- .../Code/Source/Platform/Linux/MaterialEditor_Traits_Linux.h | 3 --- .../Code/Source/Platform/Mac/MaterialEditor_Traits_Mac.h | 3 --- .../Source/Platform/Windows/MaterialEditor_Traits_Windows.h | 3 --- 3 files changed, 9 deletions(-) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/MaterialEditor_Traits_Linux.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/MaterialEditor_Traits_Linux.h index 368b681b4c..03320d1dd8 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/MaterialEditor_Traits_Linux.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Linux/MaterialEditor_Traits_Linux.h @@ -6,6 +6,3 @@ * */ #pragma once - -#define AZ_TRAIT_MATERIALEDITOR_EXT "" - diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Mac/MaterialEditor_Traits_Mac.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Mac/MaterialEditor_Traits_Mac.h index 2f46a3a12f..03320d1dd8 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Mac/MaterialEditor_Traits_Mac.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Mac/MaterialEditor_Traits_Mac.h @@ -6,6 +6,3 @@ * */ #pragma once - -#define AZ_TRAIT_MATERIALEDITOR_EXT ".app" - diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Windows/MaterialEditor_Traits_Windows.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Windows/MaterialEditor_Traits_Windows.h index 2f016a2488..03320d1dd8 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Windows/MaterialEditor_Traits_Windows.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Platform/Windows/MaterialEditor_Traits_Windows.h @@ -6,6 +6,3 @@ * */ #pragma once - -#define AZ_TRAIT_MATERIALEDITOR_EXT ".exe" - From b49a7a9975d000e51bc2ac2895752e3d4b1bef74 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 20 Jan 2022 16:58:48 -0600 Subject: [PATCH 050/136] =?UTF-8?q?Atom=20Tools:=20updating=20gem=20autolo?= =?UTF-8?q?ad=20settings=20registry=20for=20ME=20and=20SMC=20to=20disable?= =?UTF-8?q?=20script=20canvas=20developer=20gem=20Script=20canvas=20and=20?= =?UTF-8?q?related=20gems=20were=20already=20being=20disabled=20for=20some?= =?UTF-8?q?=20atom=20tools.=20The=20script=20canvas=20developer=20gem=20wa?= =?UTF-8?q?s=20not=20added=20initially=20because=20it=E2=80=99s=20not=20us?= =?UTF-8?q?ed=20in=20automated=20testing=20or=20other=20common=20projects.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guthrie Adams --- Registry/gem_autoload.materialeditor.setreg | 3 +++ Registry/gem_autoload.shadermanagementconsole.setreg | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Registry/gem_autoload.materialeditor.setreg b/Registry/gem_autoload.materialeditor.setreg index fd00ff05c7..653cc80056 100644 --- a/Registry/gem_autoload.materialeditor.setreg +++ b/Registry/gem_autoload.materialeditor.setreg @@ -28,6 +28,9 @@ "ScriptCanvas.Editor": { "AutoLoad": false }, + "ScriptCanvasDeveloper": { + "AutoLoad": false + }, "ScriptCanvasPhysics": { "AutoLoad": false }, diff --git a/Registry/gem_autoload.shadermanagementconsole.setreg b/Registry/gem_autoload.shadermanagementconsole.setreg index fd00ff05c7..653cc80056 100644 --- a/Registry/gem_autoload.shadermanagementconsole.setreg +++ b/Registry/gem_autoload.shadermanagementconsole.setreg @@ -28,6 +28,9 @@ "ScriptCanvas.Editor": { "AutoLoad": false }, + "ScriptCanvasDeveloper": { + "AutoLoad": false + }, "ScriptCanvasPhysics": { "AutoLoad": false }, From 02acf2f65ea3ecb606a6f9411efc257fd3e51f3c Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Sat, 18 Sep 2021 23:57:52 -0700 Subject: [PATCH 051/136] Updated MaterialPropertyId class in preparation for nested material property sets. Here the class has been generalized for a list of group names and a final property name, rather than assuming a single group containing the property. This included removing the unused GetPropertyName and GetGroupName functions. All that's really need from this class is conversion to a full property ID string. Testing: New unit test. Reprocessed all core material types and StandardPBR test materials used in Atom Sample Viewer's material screenshot test. Atom Sample Viewer material screenshot test script. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../RPI.Edit/Material/MaterialPropertyId.h | 18 +-- .../RPI.Edit/Material/MaterialPropertyId.cpp | 83 ++++++----- .../Material/MaterialTypeSourceData.cpp | 12 +- .../Material/MaterialPropertyIdTests.cpp | 131 ++++++++++++++++++ Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake | 1 + .../Code/Source/Document/MaterialDocument.cpp | 8 +- .../MaterialInspector/MaterialInspector.cpp | 4 +- .../EditorMaterialComponentInspector.cpp | 2 +- .../Material/EditorMaterialComponentUtil.cpp | 4 +- .../EditorMaterialModelUvNameMapInspector.cpp | 4 +- 10 files changed, 210 insertions(+), 57 deletions(-) create mode 100644 Gems/Atom/RPI/Code/Tests/Material/MaterialPropertyIdTests.cpp diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h index 77d49f3407..4b6d78c092 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h @@ -9,6 +9,7 @@ #pragma once #include +#include namespace AZ { @@ -16,27 +17,28 @@ namespace AZ { class MaterialAsset; - //! Utility for building material property names consisting of a group name and a property sub-name. - //! Represented as "[groupName].[propertyName]". - //! The group name is optional, in which case the ID will just be "[propertyName]". + //! Utility for building material property IDs. + //! These IDs are represented like "groupA.groupB.[...].propertyName". + //! The groups are optional, in which case the full property ID will just be like "propertyName". class MaterialPropertyId { public: static bool IsValidName(AZStd::string_view name); static bool IsValidName(const AZ::Name& name); - //! Creates a MaterialPropertyId from a full name string like "[groupName].[propertyName]" or just "[propertyName]" + //! Creates a MaterialPropertyId from a full name string like "groupA.groupB.[...].propertyName" or just "propertyName". + //! Also checks the name for validity. static MaterialPropertyId Parse(AZStd::string_view fullPropertyId); MaterialPropertyId() = default; + explicit MaterialPropertyId(AZStd::string_view propertyName); MaterialPropertyId(AZStd::string_view groupName, AZStd::string_view propertyName); MaterialPropertyId(const Name& groupName, const Name& propertyName); + MaterialPropertyId(const AZStd::array_view names); AZ_DEFAULT_COPY_MOVE(MaterialPropertyId); - const Name& GetGroupName() const; - const Name& GetPropertyName() const; - const Name& GetFullName() const; + operator const Name&() const; //! Returns a pointer to the full name ("[groupName].[propertyName]"). //! This is included for convenience so it can be used for error messages in the same way an AZ::Name is used. @@ -52,8 +54,6 @@ namespace AZ private: Name m_fullName; - Name m_groupName; - Name m_propertyName; }; } // namespace RPI diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp index e74ec3e6e0..1be5c4485c 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp @@ -27,63 +27,84 @@ namespace AZ bool MaterialPropertyId::IsValid() const { - const bool groupNameIsValid = m_groupName.IsEmpty() || IsValidName(m_groupName); - const bool propertyNameIsValid = IsValidName(m_propertyName); - return groupNameIsValid && propertyNameIsValid; + return !m_fullName.IsEmpty(); } MaterialPropertyId MaterialPropertyId::Parse(AZStd::string_view fullPropertyId) { AZStd::vector tokens; - AzFramework::StringFunc::Tokenize(fullPropertyId.data(), tokens, '.', true, true); + AzFramework::StringFunc::Tokenize(fullPropertyId, tokens, '.', true, true); - if (tokens.size() == 1) + if (tokens.empty()) { - return MaterialPropertyId{"", tokens[0]}; + AZ_Error("MaterialPropertyId", false, "Property ID is empty.", fullPropertyId.data()); + return MaterialPropertyId{}; } - else if (tokens.size() == 2) + + for (const auto& token : tokens) { - return MaterialPropertyId{tokens[0], tokens[1]}; + if (!IsValidName(token)) + { + AZ_Error("MaterialPropertyId", false, "Property ID '%.*s' is not a valid identifier.", AZ_STRING_ARG(fullPropertyId)); + return MaterialPropertyId{}; + } + } + + MaterialPropertyId id; + id.m_fullName = fullPropertyId; + return id; + } + + MaterialPropertyId::MaterialPropertyId(AZStd::string_view propertyName) + { + if (!IsValidName(propertyName)) + { + AZ_Error("MaterialPropertyId", false, "Property name '%.*s' is not a valid identifier.", AZ_STRING_ARG(propertyName)); } else { - AZ_Error("MaterialPropertyId", false, "Property ID '%s' is not a valid identifier.", fullPropertyId.data()); - return MaterialPropertyId{}; + m_fullName = propertyName; } } MaterialPropertyId::MaterialPropertyId(AZStd::string_view groupName, AZStd::string_view propertyName) - : MaterialPropertyId(Name{groupName}, Name{propertyName}) { - } - - MaterialPropertyId::MaterialPropertyId(const Name& groupName, const Name& propertyName) - { - AZ_Error("MaterialPropertyId", groupName.IsEmpty() || IsValidName(groupName), "Group name '%s' is not a valid identifier.", groupName.GetCStr()); - AZ_Error("MaterialPropertyId", IsValidName(propertyName), "Property name '%s' is not a valid identifier.", propertyName.GetCStr()); - m_groupName = groupName; - m_propertyName = propertyName; - if (groupName.IsEmpty()) + if (!IsValidName(groupName)) { - m_fullName = m_propertyName.GetStringView(); + AZ_Error("MaterialPropertyId", false, "Group name '%.*s' is not a valid identifier.", AZ_STRING_ARG(groupName)); + } + else if (!IsValidName(propertyName)) + { + AZ_Error("MaterialPropertyId", false, "Property name '%.*s' is not a valid identifier.", AZ_STRING_ARG(propertyName)); } else { - m_fullName = AZStd::string::format("%s.%s", m_groupName.GetCStr(), m_propertyName.GetCStr()); + m_fullName = AZStd::string::format("%.*s.%.*s", AZ_STRING_ARG(groupName), AZ_STRING_ARG(propertyName)); } } - - const Name& MaterialPropertyId::GetGroupName() const + + MaterialPropertyId::MaterialPropertyId(const Name& groupName, const Name& propertyName) + : MaterialPropertyId(groupName.GetStringView(), propertyName.GetStringView()) { - return m_groupName; + } + + MaterialPropertyId::MaterialPropertyId(const AZStd::array_view names) + { + for (const auto& name : names) + { + if (!IsValidName(name)) + { + AZ_Error("MaterialPropertyId", false, "'%s' is not a valid identifier.", name.c_str()); + return; + } + } + + AZStd::string fullName; + AzFramework::StringFunc::Join(fullName, names.begin(), names.end(), "."); + m_fullName = fullName; } - const Name& MaterialPropertyId::GetPropertyName() const - { - return m_propertyName; - } - - const Name& MaterialPropertyId::GetFullName() const + MaterialPropertyId::operator const Name&() const { return m_fullName; } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index 87c064f571..ddc2bc842b 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -400,7 +400,7 @@ namespace AZ continue; } - materialTypeAssetCreator.BeginMaterialProperty(propertyId.GetFullName(), property.m_dataType); + materialTypeAssetCreator.BeginMaterialProperty(propertyId, property.m_dataType); if (property.m_dataType == MaterialPropertyDataType::Enum) { @@ -454,18 +454,18 @@ namespace AZ if (result == MaterialUtils::GetImageAssetResult::Missing) { materialTypeAssetCreator.ReportError( - "Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), + "Material property '%s': Could not find the image '%s'", propertyId.GetCStr(), property.m_value.GetValue().data()); } else { - materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset); + materialTypeAssetCreator.SetPropertyValue(propertyId, imageAsset); } } break; case MaterialPropertyDataType::Enum: { - MaterialPropertyIndex propertyIndex = materialTypeAssetCreator.GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId.GetFullName()); + MaterialPropertyIndex propertyIndex = materialTypeAssetCreator.GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId); const MaterialPropertyDescriptor* propertyDescriptor = materialTypeAssetCreator.GetMaterialPropertiesLayout()->GetPropertyDescriptor(propertyIndex); AZ::Name enumName = AZ::Name(property.m_value.GetValue()); @@ -476,12 +476,12 @@ namespace AZ } else { - materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), enumValue); + materialTypeAssetCreator.SetPropertyValue(propertyId, enumValue); } } break; default: - materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.m_value); + materialTypeAssetCreator.SetPropertyValue(propertyId, property.m_value); break; } } diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertyIdTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertyIdTests.cpp new file mode 100644 index 0000000000..2b729ed8ef --- /dev/null +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialPropertyIdTests.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +namespace UnitTest +{ + using namespace AZ; + using namespace RPI; + + class MaterialPropertyIdTests + : public RPITestFixture + { + }; + + TEST_F(MaterialPropertyIdTests, TestConstructWithPropertyName) + { + MaterialPropertyId id{"color"}; + EXPECT_TRUE(id.IsValid()); + EXPECT_STREQ(id.GetCStr(), "color"); + AZ::Name idCastedToName = id; + EXPECT_EQ(idCastedToName, AZ::Name{"color"}); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithPropertyName_BadName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + MaterialPropertyId id{"color?"}; + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithTwoNames) + { + MaterialPropertyId id{"baseColor", "factor"}; + EXPECT_TRUE(id.IsValid()); + EXPECT_STREQ(id.GetCStr(), "baseColor.factor"); + AZ::Name idCastedToName = id; + EXPECT_EQ(idCastedToName, AZ::Name{"baseColor.factor"}); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithTwoNames_BadGroupName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + MaterialPropertyId id{"layer1.baseColor", "factor"}; + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithTwoNames_BadPropertyName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + MaterialPropertyId id{"baseColor", ".factor"}; + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithMultipleNames) + { + AZStd::vector names{"layer1", "clearCoat", "normal", "factor"}; + MaterialPropertyId id{names}; + EXPECT_TRUE(id.IsValid()); + EXPECT_STREQ(id.GetCStr(), "layer1.clearCoat.normal.factor"); + AZ::Name idCastedToName = id; + EXPECT_EQ(idCastedToName, AZ::Name{"layer1.clearCoat.normal.factor"}); + } + + TEST_F(MaterialPropertyIdTests, TestConstructWithMultipleNames_BadName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + AZStd::vector names{"layer1", "clear-coat", "normal", "factor"}; + MaterialPropertyId id{names}; + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialPropertyIdTests, TestParse) + { + MaterialPropertyId id = MaterialPropertyId::Parse("layer1.clearCoat.normal.factor"); + EXPECT_TRUE(id.IsValid()); + EXPECT_STREQ(id.GetCStr(), "layer1.clearCoat.normal.factor"); + AZ::Name idCastedToName = id; + EXPECT_EQ(idCastedToName, AZ::Name{"layer1.clearCoat.normal.factor"}); + } + + TEST_F(MaterialPropertyIdTests, TestParse_BadName) + { + ErrorMessageFinder errorMessageFinder; + errorMessageFinder.AddExpectedErrorMessage("not a valid identifier"); + + MaterialPropertyId id = MaterialPropertyId::Parse("layer1.clearCoat.normal,factor"); + EXPECT_FALSE(id.IsValid()); + + errorMessageFinder.CheckExpectedErrorsFound(); + } + + TEST_F(MaterialPropertyIdTests, TestNameValidity) + { + EXPECT_TRUE(MaterialPropertyId::IsValidName("a")); + EXPECT_TRUE(MaterialPropertyId::IsValidName("z")); + EXPECT_TRUE(MaterialPropertyId::IsValidName("A")); + EXPECT_TRUE(MaterialPropertyId::IsValidName("Z")); + EXPECT_TRUE(MaterialPropertyId::IsValidName("_")); + EXPECT_TRUE(MaterialPropertyId::IsValidName("m_layer10bazBAZ")); + EXPECT_FALSE(MaterialPropertyId::IsValidName("")); + EXPECT_FALSE(MaterialPropertyId::IsValidName("1layer")); + EXPECT_FALSE(MaterialPropertyId::IsValidName("base-color")); + EXPECT_FALSE(MaterialPropertyId::IsValidName("base.color")); + EXPECT_FALSE(MaterialPropertyId::IsValidName("base/color")); + } +} diff --git a/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake b/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake index 5d67948ac8..57ee71e412 100644 --- a/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake +++ b/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake @@ -37,6 +37,7 @@ set(FILES Tests/Material/MaterialSourceDataTests.cpp Tests/Material/MaterialFunctorTests.cpp Tests/Material/MaterialFunctorSourceDataSerializerTests.cpp + Tests/Material/MaterialPropertyIdTests.cpp Tests/Material/MaterialPropertyValueSourceDataTests.cpp Tests/Material/MaterialTests.cpp Tests/Model/ModelTests.cpp diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 641d586ea7..8f25e41827 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -589,7 +589,7 @@ namespace MaterialEditor const MaterialPropertyId propertyId(groupName, propertyName); - const auto it = m_properties.find(propertyId.GetFullName()); + const auto it = m_properties.find(propertyId); if (it != m_properties.end() && propertyFilter(it->second)) { MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue()); @@ -597,7 +597,7 @@ namespace MaterialEditor { if (!AtomToolsFramework::ConvertToExportFormat(exportPath, propertyId.GetFullName(), propertyDefinition, propertyValue)) { - AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetFullName().GetCStr(), m_absolutePath.c_str()); + AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetCStr(), m_absolutePath.c_str()); result = false; return false; } @@ -783,7 +783,7 @@ namespace MaterialEditor AtomToolsFramework::DynamicPropertyConfig propertyConfig; // Assign id before conversion so it can be used in dynamic description - propertyConfig.m_id = MaterialPropertyId(groupName, propertyName).GetCStr(); + propertyConfig.m_id = MaterialPropertyId(groupName, propertyName); const auto& propertyIndex = m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id); const bool propertyIndexInBounds = propertyIndex.IsValid() && propertyIndex.GetIndex() < m_materialAsset->GetPropertyValues().size(); @@ -854,7 +854,7 @@ namespace MaterialEditor propertyConfig = {}; propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::String; - propertyConfig.m_id = MaterialPropertyId(UvGroupName, shaderInput).GetCStr(); + propertyConfig.m_id = MaterialPropertyId(UvGroupName, shaderInput); propertyConfig.m_name = shaderInput; propertyConfig.m_displayName = shaderInput; propertyConfig.m_groupName = "UV Sets"; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp index 7790b9bef5..0af051894d 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialInspector/MaterialInspector.cpp @@ -152,7 +152,7 @@ namespace MaterialEditor AtomToolsFramework::DynamicProperty property; AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, - AZ::RPI::MaterialPropertyId(groupName, uvNamePair.m_shaderInput.ToString()).GetFullName()); + AZ::RPI::MaterialPropertyId(groupName, uvNamePair.m_shaderInput.ToString())); group.m_properties.push_back(property); property.SetValue(property.GetConfig().m_parentValue); @@ -189,7 +189,7 @@ namespace MaterialEditor AtomToolsFramework::DynamicProperty property; AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult( property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty, - AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name).GetFullName()); + AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name)); group.m_properties.push_back(property); } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp index bfa9f1d36f..b20fe5802d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentInspector.cpp @@ -310,7 +310,7 @@ namespace AZ AtomToolsFramework::DynamicPropertyConfig propertyConfig; // Assign id before conversion so it can be used in dynamic description - propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name).GetFullName(); + propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name); AtomToolsFramework::ConvertToPropertyConfig(propertyConfig, propertyDefinition); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index d3e125426c..f46876fdfb 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -116,7 +116,7 @@ namespace AZ editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition){ const AZ::RPI::MaterialPropertyId propertyId(groupName, propertyName); const AZ::RPI::MaterialPropertyIndex propertyIndex = - editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId.GetFullName()); + editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId); AZ::RPI::MaterialPropertyValue propertyValue = editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]; @@ -128,7 +128,7 @@ namespace AZ } // Check for and apply any property overrides before saving property values - auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId.GetFullName()); + auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId); if (propertyOverrideItr != editData.m_materialPropertyOverrideMap.end()) { propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialModelUvNameMapInspector.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialModelUvNameMapInspector.cpp index 0cf6410fc5..53d7980fdc 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialModelUvNameMapInspector.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialModelUvNameMapInspector.cpp @@ -96,7 +96,7 @@ namespace AZ const AZStd::string materialUvName = m_materialUvNames[i].m_uvName.GetStringView(); propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::Enum; - propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, shaderInput).GetFullName(); + propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, shaderInput); propertyConfig.m_name = shaderInput; propertyConfig.m_displayName = materialUvName; propertyConfig.m_description = shaderInput; @@ -248,7 +248,7 @@ namespace AZ const AZStd::string materialUvName = m_materialUvNames[i].m_uvName.GetStringView(); propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::Enum; - propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, shaderInput).GetFullName(); + propertyConfig.m_id = AZ::RPI::MaterialPropertyId(groupName, shaderInput); propertyConfig.m_name = shaderInput; propertyConfig.m_displayName = materialUvName; propertyConfig.m_description = shaderInput; From 8d5a53ab9313069b758ea904fe572911e331b218 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 12 Jan 2022 15:31:37 -0800 Subject: [PATCH 052/136] Minor changes per code review feedback. Added explicit keyword. Renmoved unnecessary local variable. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h | 2 +- .../RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h index 4b6d78c092..5b3c0488cb 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h @@ -34,7 +34,7 @@ namespace AZ explicit MaterialPropertyId(AZStd::string_view propertyName); MaterialPropertyId(AZStd::string_view groupName, AZStd::string_view propertyName); MaterialPropertyId(const Name& groupName, const Name& propertyName); - MaterialPropertyId(const AZStd::array_view names); + explicit MaterialPropertyId(const AZStd::array_view names); AZ_DEFAULT_COPY_MOVE(MaterialPropertyId); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp index 1be5c4485c..a1fee51d0a 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp @@ -99,9 +99,7 @@ namespace AZ } } - AZStd::string fullName; - AzFramework::StringFunc::Join(fullName, names.begin(), names.end(), "."); - m_fullName = fullName; + AzFramework::StringFunc::Join(m_fullName, names.begin(), names.end(), "."); } MaterialPropertyId::operator const Name&() const From 534843df0f478a122cc082ba9814f3967e5b5c75 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Wed, 12 Jan 2022 15:32:49 -0800 Subject: [PATCH 053/136] Added MaterialPropertyId::GetStringView() utility function. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Include/Atom/RPI.Edit/Material/MaterialPropertyId.h | 6 ++++++ .../Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h index 5b3c0488cb..fd63494f30 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialPropertyId.h @@ -41,8 +41,14 @@ namespace AZ operator const Name&() const; //! Returns a pointer to the full name ("[groupName].[propertyName]"). + //! Same as Name::GetCStr() //! This is included for convenience so it can be used for error messages in the same way an AZ::Name is used. const char* GetCStr() const; + + //! Returns a string_view of the full name ("[groupName].[propertyName]"). + //! Same as Name::GetStringView() + //! This is included for convenience so it can be used for string comparison in the same way an AZ::Name is used. + AZStd::string_view GetStringView() const; //! Returns a hash of the full name. This is needed for compatibility with NameIdReflectionMap. Name::Hash GetHash() const; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp index a1fee51d0a..4880de33fe 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp @@ -111,6 +111,11 @@ namespace AZ { return m_fullName.GetCStr(); } + + AZStd::string_view MaterialPropertyId::GetStringView() const + { + return m_fullName.GetStringView(); + } Name::Hash MaterialPropertyId::GetHash() const { From 858a92f39437d18ac1369aa269f791c54842554b Mon Sep 17 00:00:00 2001 From: Shirang Jia Date: Thu, 20 Jan 2022 15:47:53 -0800 Subject: [PATCH 054/136] Deduplicate Jenkins parameters (#7035) Signed-off-by: Shirang Jia --- scripts/build/Jenkins/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 51f89d7829..b55689b871 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -813,7 +813,7 @@ try { } } - pipelineProperties.add(parameters(pipelineParameters)) + pipelineProperties.add(parameters(pipelineParameters.unique())) properties(pipelineProperties) // Stash the INCREMENTAL_BUILD_SCRIPT_PATH since all nodes will use it From e2d157006c260e99bc3e122d7368de04f5a280af Mon Sep 17 00:00:00 2001 From: evanchia Date: Thu, 20 Jan 2022 15:57:09 -0800 Subject: [PATCH 055/136] Temporary fix for editor log stomping during python tests Signed-off-by: evanchia --- Code/Editor/CryEdit.cpp | 2 -- Tools/LyTestTools/ly_test_tools/o3de/editor_test.py | 8 +++++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 1c4e22b99e..cf233dc285 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -2134,8 +2134,6 @@ bool CCryEditApp::FixDanglingSharedMemory(const QString& sharedMemName) const int CCryEditApp::ExitInstance(int exitCode) { - AZ_TracePrintf("Exit", "Called ExitInstance() with exit code: 0x%x", exitCode); - if (m_pEditor) { m_pEditor->OnBeginShutdownSequence(); diff --git a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py index 8bd4fbe29a..672259b076 100644 --- a/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py +++ b/Tools/LyTestTools/ly_test_tools/o3de/editor_test.py @@ -315,7 +315,7 @@ class EditorTestSuite(): return 8 ## Internal ## - _TIMEOUT_CRASH_LOG = 20 # Maximum time (seconds) for waiting for a crash file, in secondss + _TIMEOUT_CRASH_LOG = 20 # Maximum time (seconds) for waiting for a crash file, in seconds _TEST_FAIL_RETCODE = 0xF # Return code for test failure @pytest.fixture(scope="class") @@ -772,7 +772,8 @@ class EditorTestSuite(): return_code = editor.get_returncode() editor_log_content = editor_utils.retrieve_editor_log_content(run_id, log_name, workspace) # Save the editor log - workspace.artifact_manager.save_artifact(os.path.join(editor_utils.retrieve_log_path(run_id, workspace), log_name)) + workspace.artifact_manager.save_artifact(os.path.join(editor_utils.retrieve_log_path(run_id, workspace), log_name), + f'({run_id}){log_name}') if return_code == 0: test_result = Result.Pass.create(test_spec, output, editor_log_content) else: @@ -847,7 +848,8 @@ class EditorTestSuite(): return_code = editor.get_returncode() editor_log_content = editor_utils.retrieve_editor_log_content(run_id, log_name, workspace) # Save the editor log - workspace.artifact_manager.save_artifact(os.path.join(editor_utils.retrieve_log_path(run_id, workspace), log_name)) + workspace.artifact_manager.save_artifact(os.path.join(editor_utils.retrieve_log_path(run_id, workspace), log_name), + f'({run_id}){log_name}') if return_code == 0: # No need to scrap the output, as all the tests have passed for test_spec in test_spec_list: From b9ba9f5ca83f31687f6b3c94e092e8c49759fb8d Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Thu, 20 Jan 2022 16:11:31 -0800 Subject: [PATCH 056/136] Got RPI unit tests building and passing again. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../RPI.Edit/Material/MaterialPropertyId.cpp | 4 +++- .../RPI.Edit/Material/MaterialSourceData.cpp | 6 +++--- .../Material/MaterialTypeSourceData.cpp | 17 +++++++++++------ .../Tests/Material/MaterialSourceDataTests.cpp | 2 +- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp index 4880de33fe..d123fe33b7 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialPropertyId.cpp @@ -99,7 +99,9 @@ namespace AZ } } - AzFramework::StringFunc::Join(m_fullName, names.begin(), names.end(), "."); + AZStd::string fullName; // m_fullName is a Name, not a string, so we have to join into a local variable temporarily. + AzFramework::StringFunc::Join(fullName, names.begin(), names.end(), "."); + m_fullName = fullName; } MaterialPropertyId::operator const Name&() const diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp index b921b186c0..2fa4ff648e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialSourceData.cpp @@ -340,16 +340,16 @@ namespace AZ if (result == MaterialUtils::GetImageAssetResult::Missing) { materialAssetCreator.ReportWarning( - "Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(), + "Material property '%s': Could not find the image '%s'", propertyId.GetCStr(), property.second.m_value.GetValue().data()); } imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad); - materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset); + materialAssetCreator.SetPropertyValue(propertyId, imageAsset); } else { - materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.second.m_value); + materialAssetCreator.SetPropertyValue(propertyId, property.second.m_value); } } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index ddc2bc842b..3a5992f8dd 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -140,7 +140,7 @@ namespace AZ { if (action.m_operation == "rename") { - if (action.m_renameFrom == propertyId.GetFullName().GetStringView()) + if (action.m_renameFrom == propertyId.GetStringView()) { propertyId = MaterialPropertyId::Parse(action.m_renameTo); renamed = true; @@ -177,14 +177,19 @@ namespace AZ // Do the search again with the new names - groupIter = m_propertyLayout.m_properties.find(propertyId.GetGroupName().GetStringView()); - if (groupIter != m_propertyLayout.m_properties.end()) + AZStd::vector tokens; + AZ::StringFunc::Tokenize(propertyId.GetStringView(), tokens, ".", true, true); + if (tokens.size() == 2) { - for (const PropertyDefinition& property : groupIter->second) + groupIter = m_propertyLayout.m_properties.find(tokens[0]); + if (groupIter != m_propertyLayout.m_properties.end()) { - if (property.m_name == propertyId.GetPropertyName().GetStringView()) + for (const PropertyDefinition& property : groupIter->second) { - return &property; + if (property.m_name == tokens[1]) + { + return &property; + } } } } diff --git a/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp b/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp index 5e09fe6612..94518c6aef 100644 --- a/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/Material/MaterialSourceDataTests.cpp @@ -905,7 +905,7 @@ namespace UnitTest JsonTestResult loadResult = LoadTestDataFromJson(material, inputJson); auto materialAssetResult = material.CreateMaterialAsset(Uuid::CreateRandom(), "test.material", AZ::RPI::MaterialAssetProcessingMode::PreBake); EXPECT_TRUE(materialAssetResult); - MaterialPropertyIndex propertyIndex = materialAssetResult.GetValue()->GetMaterialPropertiesLayout()->FindPropertyIndex(MaterialPropertyId{groupName, propertyName}.GetFullName()); + MaterialPropertyIndex propertyIndex = materialAssetResult.GetValue()->GetMaterialPropertiesLayout()->FindPropertyIndex(MaterialPropertyId{groupName, propertyName}); CheckSimilar(expectedFinalValue, materialAssetResult.GetValue()->GetPropertyValues()[propertyIndex.GetIndex()].GetValue()); } From 32e2ba754bc67d66e6dad87916360569db6c4a72 Mon Sep 17 00:00:00 2001 From: Nicholas Van Sickle Date: Thu, 20 Jan 2022 16:53:33 -0800 Subject: [PATCH 057/136] Add Dom::Path class for representing positions in a Dom (#7008) * Add Dom::Path class for representing positions in a Dom This also adds Value support for doing a path-based lookup. The serialized representation is presently compliant with the JSON-pointer spec but the implementation supports Node types and may be later expanded if we require additional functionality (e.g. XPath style conditional querying). Signed-off-by: Nicholas Van Sickle --- Code/Framework/AzCore/AzCore/DOM/DomPath.cpp | 478 ++++++++++++++++++ Code/Framework/AzCore/AzCore/DOM/DomPath.h | 144 ++++++ Code/Framework/AzCore/AzCore/DOM/DomValue.cpp | 121 +++++ Code/Framework/AzCore/AzCore/DOM/DomValue.h | 13 + .../AzCore/AzCore/azcore_files.cmake | 2 + .../AzCore/Tests/DOM/DomPathBenchmarks.cpp | 99 ++++ .../AzCore/Tests/DOM/DomPathTests.cpp | 177 +++++++ .../AzCore/Tests/azcoretests_files.cmake | 2 + 8 files changed, 1036 insertions(+) create mode 100644 Code/Framework/AzCore/AzCore/DOM/DomPath.cpp create mode 100644 Code/Framework/AzCore/AzCore/DOM/DomPath.h create mode 100644 Code/Framework/AzCore/Tests/DOM/DomPathBenchmarks.cpp create mode 100644 Code/Framework/AzCore/Tests/DOM/DomPathTests.cpp diff --git a/Code/Framework/AzCore/AzCore/DOM/DomPath.cpp b/Code/Framework/AzCore/AzCore/DOM/DomPath.cpp new file mode 100644 index 0000000000..bc50a8513c --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomPath.cpp @@ -0,0 +1,478 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include + +namespace AZ::Dom +{ + PathEntry::PathEntry(size_t value) + : m_value(value) + { + } + + PathEntry::PathEntry(AZ::Name value) + : m_value(AZStd::move(value)) + { + } + + PathEntry::PathEntry(AZStd::string_view value) + : m_value(AZ::Name(value)) + { + } + + PathEntry& PathEntry::operator=(size_t value) + { + m_value = value; + return *this; + } + + PathEntry& PathEntry::operator=(AZ::Name value) + { + m_value = AZStd::move(value); + return *this; + } + + PathEntry& PathEntry::operator=(AZStd::string_view value) + { + m_value = AZ::Name(value); + return *this; + } + + bool PathEntry::operator==(const PathEntry& other) const + { + return m_value == other.m_value; + } + + bool PathEntry::operator==(size_t value) const + { + return IsIndex() && GetIndex() == value; + } + + bool PathEntry::operator==(const AZ::Name& key) const + { + return IsKey() && GetKey() == key; + } + + bool PathEntry::operator==(AZStd::string_view key) const + { + return IsKey() && GetKey() == AZ::Name(key); + } + + bool PathEntry::operator!=(const PathEntry& other) const + { + return m_value != other.m_value; + } + + bool PathEntry::operator!=(size_t value) const + { + return !IsIndex() || GetIndex() != value; + } + + bool PathEntry::operator!=(const AZ::Name& key) const + { + return !IsKey() || GetKey() != key; + } + + bool PathEntry::operator!=(AZStd::string_view key) const + { + return !IsKey() || GetKey() != AZ::Name(key); + } + + void PathEntry::SetEndOfArray() + { + m_value = EndOfArrayIndex; + } + + bool PathEntry::IsEndOfArray() const + { + const size_t* result = AZStd::get_if(&m_value); + return result == nullptr ? false : ((*result) == EndOfArrayIndex); + } + + bool PathEntry::IsIndex() const + { + const size_t* result = AZStd::get_if(&m_value); + return result == nullptr ? false : ((*result) != EndOfArrayIndex); + } + + bool PathEntry::IsKey() const + { + return AZStd::holds_alternative(m_value); + } + + size_t PathEntry::GetIndex() const + { + AZ_Assert(IsIndex(), "GetIndex called on PathEntry that is not an index"); + return AZStd::get(m_value); + } + + const AZ::Name& PathEntry::GetKey() const + { + AZ_Assert(IsKey(), "Key called on PathEntry that is not a key"); + return AZStd::get(m_value); + } + + Path::Path(AZStd::initializer_list init) + : m_entries(init) + { + } + + Path::Path(AZStd::string_view pathString) + { + FromString(pathString); + } + + Path Path::operator/(const PathEntry& entry) const + { + Path newPath(*this); + newPath /= entry; + return newPath; + } + + Path Path::operator/(size_t index) const + { + return *this / PathEntry(index); + } + + Path Path::operator/(AZ::Name key) const + { + return *this / PathEntry(key); + } + + Path Path::operator/(AZStd::string_view key) const + { + return *this / PathEntry(key); + } + + Path Path::operator/(const Path& other) const + { + Path newPath(*this); + newPath /= other; + return newPath; + } + + Path& Path::operator/=(const PathEntry& entry) + { + Push(entry); + return *this; + } + + Path& Path::operator/=(size_t index) + { + return *this /= PathEntry(index); + } + + Path& Path::operator/=(AZ::Name key) + { + return *this /= PathEntry(key); + } + + Path& Path::operator/=(AZStd::string_view key) + { + return *this /= PathEntry(key); + } + + Path& Path::operator/=(const Path& other) + { + for (const PathEntry& entry : other) + { + Push(entry); + } + return *this; + } + + bool Path::operator==(const Path& other) const + { + return m_entries == other.m_entries; + } + + const Path::ContainerType& Path::GetEntries() const + { + return m_entries; + } + + void Path::Push(PathEntry entry) + { + m_entries.push_back(AZStd::move(entry)); + } + + void Path::Push(size_t entry) + { + Push(PathEntry(entry)); + } + + void Path::Push(AZ::Name entry) + { + Push(PathEntry(AZStd::move(entry))); + } + + void Path::Push(AZStd::string_view entry) + { + Push(AZ::Name(entry)); + } + + void Path::Pop() + { + m_entries.pop_back(); + } + + void Path::Clear() + { + m_entries.clear(); + } + + PathEntry Path::At(size_t index) const + { + if (index < m_entries.size()) + { + return m_entries[index]; + } + return {}; + } + + size_t Path::Size() const + { + return m_entries.size(); + } + + PathEntry& Path::operator[](size_t index) + { + return m_entries[index]; + } + + const PathEntry& Path::operator[](size_t index) const + { + return m_entries[index]; + } + + Path::ContainerType::iterator Path::begin() + { + return m_entries.begin(); + } + + Path::ContainerType::iterator Path::end() + { + return m_entries.end(); + } + + Path::ContainerType::const_iterator Path::begin() const + { + return m_entries.cbegin(); + } + + Path::ContainerType::const_iterator Path::end() const + { + return m_entries.cend(); + } + + Path::ContainerType::const_iterator Path::cbegin() const + { + return m_entries.cbegin(); + } + + Path::ContainerType::const_iterator Path::cend() const + { + return m_entries.cend(); + } + + size_t Path::size() const + { + return m_entries.size(); + } + + size_t Path::GetStringLength() const + { + size_t size = 0; + for (const PathEntry& entry : m_entries) + { + ++size; + if (entry.IsEndOfArray()) + { + size += 1; + } + else if (entry.IsIndex()) + { + const size_t index = entry.GetIndex(); + const double digitCount = index > 0 ? log10(aznumeric_cast(index + 1)) : 1.0; + size += aznumeric_cast(ceil(digitCount)); + } + else + { + const char* nameBuffer = entry.GetKey().GetCStr(); + for (size_t i = 0; nameBuffer[i]; ++i) + { + if (nameBuffer[i] == EscapeCharacter || nameBuffer[i] == PathSeparator) + { + ++size; + } + ++size; + } + } + } + return size; + } + + void Path::FormatString(char* stringBuffer, size_t bufferSize) const + { + size_t bufferIndex = 0; + + auto putChar = [&](char c) + { + if (bufferIndex == bufferSize) + { + return; + } + stringBuffer[bufferIndex++] = c; + }; + + auto writeToBuffer = [&](const char* key) + { + for (size_t keyIndex = 0; key[keyIndex]; ++keyIndex) + { + const char c = key[keyIndex]; + if (c == EscapeCharacter) + { + putChar(EscapeCharacter); + putChar(TildeSequence); + } + else if (c == PathSeparator) + { + putChar(EscapeCharacter); + putChar(ForwardSlashSequence); + } + else + { + putChar(c); + } + } + }; + + for (const PathEntry& entry : m_entries) + { + putChar(PathSeparator); + if (entry.IsEndOfArray()) + { + putChar(EndOfArrayCharacter); + } + else if (entry.IsIndex()) + { + bufferIndex += azsnprintf(&stringBuffer[bufferIndex], bufferSize - bufferIndex, "%zu", entry.GetIndex()); + } + else + { + writeToBuffer(entry.GetKey().GetCStr()); + } + } + + putChar('\0'); + } + + AZStd::string Path::ToString() const + { + AZStd::string formattedString; + const size_t size = GetStringLength(); + formattedString.resize_no_construct(size); + FormatString(formattedString.data(), size + 1); + return formattedString; + } + + void Path::AppendToString(AZStd::string& output) const + { + const size_t startIndex = output.length(); + const size_t stringLength = GetStringLength(); + output.resize_no_construct(startIndex + stringLength); + FormatString(output.data() + startIndex, stringLength + 1); + } + + void Path::FromString(AZStd::string_view pathString) + { + m_entries.clear(); + if (pathString.empty()) + { + return; + } + + size_t pathEntryCount = 0; + for (size_t i = 1; i <= pathString.size(); ++i) + { + if (pathString[i] == PathSeparator) + { + ++pathEntryCount; + } + } + m_entries.reserve(pathEntryCount); + + // Ignore a preceeding path separator and start processing after it + size_t pathIndex = pathString[0] == PathSeparator ? 1 : 0; + bool isNumber = true; + AZStd::string convertedSection; + for (size_t i = pathIndex; i <= pathString.size(); ++i) + { + if (i == pathString.size() || pathString[i] == PathSeparator) + { + AZStd::string_view section = pathString.substr(pathIndex, i - pathIndex); + if (section.size() == 1 && section[0] == EndOfArrayCharacter) + { + PathEntry entry; + entry.SetEndOfArray(); + m_entries.push_back(AZStd::move(entry)); + } + else if (isNumber && !section.empty()) + { + size_t index = 0; + ConsoleTypeHelpers::StringToValue(index, section); + m_entries.push_back(PathEntry{ index }); + } + else + { + convertedSection.clear(); + size_t lastPos = 0; + size_t posToEscape = section.find(EscapeCharacter); + while (posToEscape != AZStd::string_view::npos) + { + if (convertedSection.empty()) + { + convertedSection.reserve(section.size() - 1); + } + convertedSection += section.substr(lastPos, posToEscape - lastPos); + if (section[posToEscape + 1] == ForwardSlashSequence) + { + convertedSection += '/'; + } + else + { + convertedSection += '~'; + } + + lastPos = posToEscape + 2; + posToEscape = section.find(EscapeCharacter, posToEscape + 2); + } + + if (!convertedSection.empty()) + { + convertedSection += section.substr(lastPos); + m_entries.emplace_back(convertedSection); + } + else + { + m_entries.emplace_back(section); + } + } + pathIndex = i + 1; + isNumber = true; + continue; + } + + const char c = pathString[i]; + isNumber = isNumber && c >= '0' && c <= '9'; + } + } +} // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/DomPath.h b/Code/Framework/AzCore/AzCore/DOM/DomPath.h new file mode 100644 index 0000000000..39f7c7da98 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/DOM/DomPath.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include +#include +#include + +namespace AZ::Dom +{ + //! Represents the path to a direct descendant of a Value. + //! PathEntry may be one of the following: + //! - Index, a numerical index for indexing within Arrays and Nodes + //! - Key, a name for indexing within Objects and Nodes + //! - EndOfArray, a special-case indicator for representing the end of an array + //! used by the patching system to represent push / pop back operations. + class PathEntry final + { + public: + static constexpr size_t EndOfArrayIndex = size_t(-1); + + PathEntry() = default; + PathEntry(const PathEntry&) = default; + PathEntry(PathEntry&&) = default; + explicit PathEntry(size_t value); + explicit PathEntry(AZ::Name value); + explicit PathEntry(AZStd::string_view value); + + PathEntry& operator=(const PathEntry&) = default; + PathEntry& operator=(PathEntry&&) = default; + PathEntry& operator=(size_t value); + PathEntry& operator=(AZ::Name value); + PathEntry& operator=(AZStd::string_view value); + + bool operator==(const PathEntry& other) const; + bool operator==(size_t index) const; + bool operator==(const AZ::Name& key) const; + bool operator==(AZStd::string_view key) const; + bool operator!=(const PathEntry& other) const; + bool operator!=(size_t index) const; + bool operator!=(const AZ::Name& key) const; + bool operator!=(AZStd::string_view key) const; + + void SetEndOfArray(); + + bool IsEndOfArray() const; + bool IsIndex() const; + bool IsKey() const; + + size_t GetIndex() const; + const AZ::Name& GetKey() const; + + private: + AZStd::variant m_value; + }; + + //! Represents a path, represented as a series of PathEntry values, to a position in a Value. + class Path final + { + public: + using ContainerType = AZStd::vector; + static constexpr char PathSeparator = '/'; + static constexpr char EscapeCharacter = '~'; + static constexpr char TildeSequence = '0'; + static constexpr char ForwardSlashSequence = '1'; + static constexpr char EndOfArrayCharacter = '-'; + + Path() = default; + Path(const Path&) = default; + Path(Path&&) = default; + explicit Path(AZStd::initializer_list init); + //! Creates a Path from a path string, a path string is formatted per the JSON pointer specification + //! and looks like "/path/to/value/0" + explicit Path(AZStd::string_view pathString); + + template + explicit Path(InputIterator first, InputIterator last) + : m_entries(first, last) + { + } + + Path& operator=(const Path&) = default; + Path& operator=(Path&&) = default; + + Path operator/(const PathEntry&) const; + Path operator/(size_t) const; + Path operator/(AZ::Name) const; + Path operator/(AZStd::string_view) const; + Path operator/(const Path&) const; + + Path& operator/=(const PathEntry&); + Path& operator/=(size_t); + Path& operator/=(AZ::Name); + Path& operator/=(AZStd::string_view); + Path& operator/=(const Path&); + + bool operator==(const Path&) const; + + const ContainerType& GetEntries() const; + void Push(PathEntry entry); + void Push(size_t entry); + void Push(AZ::Name entry); + void Push(AZStd::string_view key); + void Pop(); + void Clear(); + PathEntry At(size_t index) const; + size_t Size() const; + + PathEntry& operator[](size_t index); + const PathEntry& operator[](size_t index) const; + + ContainerType::iterator begin(); + ContainerType::iterator end(); + ContainerType::const_iterator begin() const; + ContainerType::const_iterator end() const; + ContainerType::const_iterator cbegin() const; + ContainerType::const_iterator cend() const; + size_t size() const; + + //! Gets the length this path would require, if string-formatted. + //! The length includes the contents of the string but not a null terminator. + size_t GetStringLength() const; + //! Formats a JSON-pointer style path string into the target buffer. + //! This operation will fail if bufferSize < GetStringLength() + 1 + void FormatString(char* stringBuffer, size_t bufferSize) const; + //! Returns a JSON-pointer style path string for this path. + AZStd::string ToString() const; + void AppendToString(AZStd::string& output) const; + //! Reads a JSON-pointer style path from pathString and replaces this path's contents. + //! Paths are accepted in the following forms: + //! "/path/to/foo/0" + //! "path/to/foo/0" + void FromString(AZStd::string_view pathString); + + private: + ContainerType m_entries; + }; +} // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/DomValue.cpp b/Code/Framework/AzCore/AzCore/DOM/DomValue.cpp index 10c8e33715..793fadd092 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomValue.cpp +++ b/Code/Framework/AzCore/AzCore/DOM/DomValue.cpp @@ -6,6 +6,7 @@ * */ +#include #include #include #include @@ -1177,4 +1178,124 @@ namespace AZ::Dom { return m_value; } + + Value& Value::operator[](const PathEntry& entry) + { + if (entry.IsEndOfArray()) + { + Array::ContainerType& array = GetArrayInternal(); + array.push_back(); + return array[array.size() - 1]; + } + return entry.IsIndex() ? operator[](entry.GetIndex()) : operator[](entry.GetKey()); + } + + const Value& Value::operator[](const PathEntry& entry) const + { + return entry.IsIndex() ? operator[](entry.GetIndex()) : operator[](entry.GetKey()); + } + + Value& Value::operator[](const Path& path) + { + Value* value = this; + for (const PathEntry& entry : path) + { + value = &value->operator[](entry); + } + return *value; + } + + const Value& Value::operator[](const Path& path) const + { + const Value* value = this; + for (const PathEntry& entry : path) + { + value = &value->operator[](entry); + } + return *value; + } + + const Value* Value::FindChild(const PathEntry& entry) const + { + if (entry.IsEndOfArray()) + { + return nullptr; + } + else if (entry.IsIndex()) + { + const Array::ContainerType& array = GetArrayInternal(); + const size_t index = entry.GetIndex(); + if (index < array.size()) + { + return &array[index]; + } + } + else + { + const Object::ContainerType& obj = GetObjectInternal(); + auto memberIt = FindMember(entry.GetKey()); + if (memberIt != obj.end()) + { + return &memberIt->second; + } + } + return nullptr; + } + + Value* Value::FindMutableChild(const PathEntry& entry) + { + if (entry.IsEndOfArray()) + { + Array::ContainerType& array = GetArrayInternal(); + array.push_back(); + return &array[array.size() - 1]; + } + else if (entry.IsIndex()) + { + Array::ContainerType& array = GetArrayInternal(); + const size_t index = entry.GetIndex(); + if (index < array.size()) + { + return &array[index]; + } + } + else + { + Object::ContainerType& obj = GetObjectInternal(); + auto memberIt = FindMutableMember(entry.GetKey()); + if (memberIt != obj.end()) + { + return &memberIt->second; + } + } + return nullptr; + } + + const Value* Value::FindChild(const Path& path) const + { + const Value* value = this; + for (const PathEntry& entry : path) + { + value = value->FindChild(entry); + if (value == nullptr) + { + return nullptr; + } + } + return value; + } + + Value* Value::FindMutableChild(const Path& path) + { + Value* value = this; + for (const PathEntry& entry : path) + { + value = value->FindMutableChild(entry); + if (value == nullptr) + { + return nullptr; + } + } + return value; + } } // namespace AZ::Dom diff --git a/Code/Framework/AzCore/AzCore/DOM/DomValue.h b/Code/Framework/AzCore/AzCore/DOM/DomValue.h index d1d3c1745d..be5d855003 100644 --- a/Code/Framework/AzCore/AzCore/DOM/DomValue.h +++ b/Code/Framework/AzCore/AzCore/DOM/DomValue.h @@ -22,6 +22,8 @@ namespace AZ::Dom { + class PathEntry; + class Path; using KeyType = AZ::Name; //! The type of underlying value stored in a value. \see Value @@ -380,6 +382,17 @@ namespace AZ::Dom Visitor::Result Accept(Visitor& visitor, bool copyStrings) const; AZStd::unique_ptr GetWriteHandler(); + // Path API... + Value& operator[](const PathEntry& entry); + const Value& operator[](const PathEntry& entry) const; + Value& operator[](const Path& path); + const Value& operator[](const Path& path) const; + + const Value* FindChild(const PathEntry& entry) const; + Value* FindMutableChild(const PathEntry& entry); + const Value* FindChild(const Path& path) const; + Value* FindMutableChild(const Path& path); + //! Gets the internal value of this Value. Note that this value's types may not correspond one-to-one with the Type enumeration, //! as internally the same type might have different storage mechanisms. Where possible, prefer using the typed API. const ValueType& GetInternalValue() const; diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index 8b8a3b377a..2c0c318648 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -116,6 +116,8 @@ set(FILES Debug/TraceReflection.h DOM/DomBackend.cpp DOM/DomBackend.h + DOM/DomPath.cpp + DOM/DomPath.h DOM/DomUtils.cpp DOM/DomUtils.h DOM/DomValue.cpp diff --git a/Code/Framework/AzCore/Tests/DOM/DomPathBenchmarks.cpp b/Code/Framework/AzCore/Tests/DOM/DomPathBenchmarks.cpp new file mode 100644 index 0000000000..624b24cd20 --- /dev/null +++ b/Code/Framework/AzCore/Tests/DOM/DomPathBenchmarks.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +namespace AZ::Dom::Benchmark +{ + using DomPathBenchmark = Tests::DomBenchmarkFixture; + + BENCHMARK_DEFINE_F(DomPathBenchmark, DomPath_Concatenate_InPlace)(benchmark::State& state) + { + AZ::Name entry1("entry1"); + AZ::Name entry2("entry2"); + PathEntry end; + end.SetEndOfArray(); + + for (auto _ : state) + { + Path p; + p /= entry1; + p /= entry2; + p /= 0; + p /= end; + } + + state.SetItemsProcessed(4 * state.iterations()); + } + BENCHMARK_REGISTER_F(DomPathBenchmark, DomPath_Concatenate_InPlace); + + BENCHMARK_DEFINE_F(DomPathBenchmark, DomPath_Concatenate_Copy)(benchmark::State& state) + { + AZ::Name entry1("entry1"); + AZ::Name entry2("entry2"); + PathEntry end; + end.SetEndOfArray(); + + for (auto _ : state) + { + Path p = Path() / entry1 / entry2 / 0 / end; + } + + state.SetItemsProcessed(4 * state.iterations()); + } + BENCHMARK_REGISTER_F(DomPathBenchmark, DomPath_Concatenate_Copy); + + BENCHMARK_DEFINE_F(DomPathBenchmark, DomPath_ToString)(benchmark::State& state) + { + Path p("/path/with/multiple/0/different/components/65536/999/-"); + AZStd::string s; + s.resize_no_construct(p.GetStringLength()); + + for (auto _ : state) + { + p.GetStringLength(); + p.FormatString(s.data(), s.size()); + } + + state.SetBytesProcessed(s.size() * state.iterations()); + } + BENCHMARK_REGISTER_F(DomPathBenchmark, DomPath_ToString); + + BENCHMARK_DEFINE_F(DomPathBenchmark, DomPath_FromString)(benchmark::State& state) + { + AZStd::string pathString = "/path/with/multiple/0/different/components/including-long-strings-like-this/65536/999/-"; + + for (auto _ : state) + { + Path p(pathString); + benchmark::DoNotOptimize(p); + } + + state.SetBytesProcessed(pathString.size() * state.iterations()); + } + BENCHMARK_REGISTER_F(DomPathBenchmark, DomPath_FromString); + + BENCHMARK_DEFINE_F(DomPathBenchmark, DomPathEntry_IsEndOfArray)(benchmark::State& state) + { + PathEntry name("name"); + PathEntry index(0); + PathEntry endOfArray; + endOfArray.SetEndOfArray(); + + for (auto _ : state) + { + name.IsEndOfArray(); + index.IsEndOfArray(); + endOfArray.IsEndOfArray(); + } + + state.SetItemsProcessed(3 * state.iterations()); + } + BENCHMARK_REGISTER_F(DomPathBenchmark, DomPathEntry_IsEndOfArray); +} diff --git a/Code/Framework/AzCore/Tests/DOM/DomPathTests.cpp b/Code/Framework/AzCore/Tests/DOM/DomPathTests.cpp new file mode 100644 index 0000000000..54bff9f29b --- /dev/null +++ b/Code/Framework/AzCore/Tests/DOM/DomPathTests.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include + +namespace AZ::Dom::Tests +{ + class DomPathTests : public DomTestFixture + { + }; + + TEST_F(DomPathTests, EmptyPath_IsEmpty) + { + Path path(""); + EXPECT_EQ(path.GetEntries().size(), 0); + } + + TEST_F(DomPathTests, EmptyPath_IsEqualToDefault) + { + EXPECT_EQ(Path(""), Path()); + } + + TEST_F(DomPathTests, Index_IsNumeric) + { + EXPECT_EQ(Path("/0")[0], 0); + EXPECT_EQ(Path("/20")[0], 20); + EXPECT_EQ(Path("/9999")[0], 9999); + EXPECT_EQ(Path("/0/4/5/1")[3], 1); + } + + TEST_F(DomPathTests, Index_ConvertsToString) + { + Path p; + EXPECT_EQ(p.ToString(), ""); + + p.Push(0); + EXPECT_EQ(p.ToString(), "/0"); + + p.Push(1); + EXPECT_EQ(p.ToString(), "/0/1"); + + p.Push(10); + EXPECT_EQ(p.ToString(), "/0/1/10"); + + p.Push(9999); + EXPECT_EQ(p.ToString(), "/0/1/10/9999"); + + p.Pop(); + EXPECT_EQ(p.ToString(), "/0/1/10"); + } + + TEST_F(DomPathTests, Key_IsString) + { + EXPECT_EQ(Path("/foo")[0], "foo"); + EXPECT_EQ(Path("/bar")[0], "bar"); + EXPECT_EQ(Path("/foo/bar/baz12345")[0], "foo"); + EXPECT_EQ(Path("/foo/bar/baz12345")[2], "baz12345"); + EXPECT_EQ(Path("//foo")[0], ""); + } + + TEST_F(DomPathTests, Key_ConvertsToString) + { + Path p; + + p.Push("foo"); + EXPECT_EQ(p.ToString(), "/foo"); + + p.Push("bar"); + EXPECT_EQ(p.ToString(), "/foo/bar"); + + p.Push("another_key"); + EXPECT_EQ(p.ToString(), "/foo/bar/another_key"); + + p.Pop(); + EXPECT_EQ(p.ToString(), "/foo/bar"); + } + + TEST_F(DomPathTests, Key_ConvertsFromEscaped) + { + EXPECT_EQ(Path("/foo~0")[0], "foo~"); + EXPECT_EQ(Path("/foo~0bar~0~0")[0], "foo~bar~~"); + EXPECT_EQ(Path("/foo~1bar/baz")[0], "foo/bar"); + EXPECT_EQ(Path("/~1foo~1")[0], "/foo/"); + } + + TEST_F(DomPathTests, Key_ConvertsToEscaped) + { + Path p; + + p.Push("with~tilde"); + EXPECT_EQ(p.ToString(), "/with~0tilde"); + + p.Push("with/slash"); + EXPECT_EQ(p.ToString(), "/with~0tilde/with~1slash"); + + p.Clear(); + p.Push("/~with/mixed/characters~"); + EXPECT_EQ(p.ToString(), "/~1~0with~1mixed~1characters~0"); + } + + TEST_F(DomPathTests, MixedPath_Resolves) + { + EXPECT_EQ(Path("/foo/0")[0], "foo"); + EXPECT_EQ(Path("/foo/0")[1], 0); + EXPECT_EQ(Path("/42/foo/bar/0")[0], 42); + EXPECT_EQ(Path("/42/foo/bar/0")[1], "foo"); + EXPECT_EQ(Path("/42/foo/bar/0")[2], "bar"); + EXPECT_EQ(Path("/42/foo/bar/0")[3], 0); + } + + TEST_F(DomPathTests, MixedPath_ConvertsToString) + { + Path p; + + p.Push("foo"); + EXPECT_EQ(p.ToString(), "/foo"); + + p.Push(0); + EXPECT_EQ(p.ToString(), "/foo/0"); + + p.Push("another_key"); + EXPECT_EQ(p.ToString(), "/foo/0/another_key"); + + p.Push(100); + EXPECT_EQ(p.ToString(), "/foo/0/another_key/100"); + + p.Pop(); + EXPECT_EQ(p.ToString(), "/foo/0/another_key"); + } + + TEST_F(DomPathTests, OperatorOverloads_Append) + { + EXPECT_EQ(Path("/foo/bar"), Path("/foo") / Path("/bar")); + EXPECT_EQ(Path("/foo"), Path("/foo") / Path()); + EXPECT_EQ(Path("/foo/1/bar/0"), Path("/foo/1") / Path("/bar/0")); + EXPECT_EQ(Path("/foo") / 0, Path("/foo/0")); + EXPECT_EQ(Path() / "foo" / "bar", Path("/foo/bar")); + EXPECT_EQ(Path("/foo") / "bar" / "baz", Path("/foo/bar/baz")); + + Path p("/foo/bar"); + p /= "baz"; + EXPECT_EQ(p, Path("/foo/bar/baz")); + p /= Path("0/1"); + EXPECT_EQ(p, Path("/foo/bar/baz/0/1")); + } + + TEST_F(DomPathTests, EndOfArray_FromString) + { + EXPECT_FALSE(Path("/foo/-")[0].IsEndOfArray()); + EXPECT_TRUE(Path("/foo/-")[1].IsEndOfArray()); + EXPECT_TRUE(Path("/foo/-/-")[2].IsEndOfArray()); + } + + TEST_F(DomPathTests, EndOfArray_ToString) + { + EXPECT_EQ(Path("/-").ToString(), "/-"); + EXPECT_EQ(Path("/0/-").ToString(), "/0/-"); + } + + TEST_F(DomPathTests, MixedPath_AppendToString) + { + Path p("/foo/0"); + AZStd::string s; + + p.AppendToString(s); + EXPECT_EQ(s, "/foo/0"); + p.AppendToString(s); + EXPECT_EQ(s, "/foo/0/foo/0"); + } +} // namespace AZ::Dom::Tests diff --git a/Code/Framework/AzCore/Tests/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake index aee6828b76..24a6601cf0 100644 --- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake +++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake @@ -219,6 +219,8 @@ set(FILES DOM/DomFixtures.h DOM/DomJsonTests.cpp DOM/DomJsonBenchmarks.cpp + DOM/DomPathTests.cpp + DOM/DomPathBenchmarks.cpp DOM/DomValueTests.cpp DOM/DomValueBenchmarks.cpp ) From b98b240a4001a7928d89facc9303aa9e20453568 Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Thu, 20 Jan 2022 18:16:51 -0800 Subject: [PATCH 058/136] Entity Reference P1 initial tests Signed-off-by: Scott Murray --- .../Atom/atom_utils/atom_constants.py | 2 + ...omEditorComponents_EntityReferenceAdded.py | 101 ++++++++++++++++-- 2 files changed, 92 insertions(+), 11 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py index e6d6ac7fb1..c3404c1e94 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py @@ -195,11 +195,13 @@ class AtomComponentProperties: def entity_reference(property: str = 'name') -> str: """ Entity Reference component properties. + - 'EntityIdReferences' component container of entityId references. Initially empty. :param property: From the last element of the property tree path. Default 'name' for component name string. :return: Full property path OR component name if no property specified. """ properties = { 'name': 'Entity Reference', + 'EntityIdReferences': 'Controller|Configuration|EntityIdReferences', } return properties[property] diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py index dddcca64fa..9dc4869f66 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py @@ -9,37 +9,55 @@ SPDX-License-Identifier: Apache-2.0 OR MIT class Tests: creation_undo = ( "UNDO Entity creation success", - "UNDO Entity creation failed") + "P0: UNDO Entity creation failed") creation_redo = ( "REDO Entity creation success", - "REDO Entity creation failed") + "P0: REDO Entity creation failed") entity_reference_creation = ( "Entity Reference Entity successfully created", - "Entity Reference Entity failed to be created") + "P0: Entity Reference Entity failed to be created") entity_reference_component = ( "Entity has an Entity Reference component", - "Entity failed to find Entity Reference component") + "P0: Entity failed to find Entity Reference component") enter_game_mode = ( "Entered game mode", - "Failed to enter game mode") + "P0: Failed to enter game mode") exit_game_mode = ( "Exited game mode", - "Couldn't exit game mode") + "P0: Couldn't exit game mode") is_visible = ( "Entity is visible", - "Entity was not visible") + "P0: Entity was not visible") is_hidden = ( "Entity is hidden", - "Entity was not hidden") + "P0: Entity was not hidden") entity_deleted = ( "Entity deleted", - "Entity was not deleted") + "P0: Entity was not deleted") deletion_undo = ( "UNDO deletion success", - "UNDO deletion failed") + "P0: UNDO deletion failed") deletion_redo = ( "REDO deletion success", - "REDO deletion failed") + "P0: REDO deletion failed") + entity_id_references_is_container = ( + "EntityIdReferences is a container property", + "P1: EntityIdReferences is NOT a container property") + container_append = ( + "EntityIdReferences append succeeded", + "P1: EntityIdReferences append did not succeed") + container_add = ( + "EntityIdReferences add succeeded", + "P1: EntityIdReferences add did not succeed") + container_update = ( + "EntityIdReferences update succeeded", + "P1: EntityIdReferences update did not succeed") + container_remove = ( + "EntityIdReferences remove succeeded", + "P1: EntityIdReferences remove did not succeed") + container_reset = ( + "EntityIdReferences reset succeeded", + "P1: EntityIdReferences reset did not succeed") def AtomEditorComponents_EntityReference_AddedToEntity(): @@ -119,6 +137,67 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): general.idle_wait_frames(1) Report.result(Tests.creation_redo, entity_reference_entity.exists()) + # Entities for EntityIdReferences tests + test_1 = EditorEntity.create_editor_entity('test_1') + test_2 = EditorEntity.create_editor_entity('test_2') + test_3 = EditorEntity.create_editor_entity('test_3') + + # is container property + Report.result( + Tests.entity_id_references_is_container, + entity_reference_component.is_property_container( + AtomComponentProperties.entity_reference('EntityIdReferences'))) + + # Append entity reference to container + entity_reference_component.append_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), + test_1.id) + Report.result( + Tests.container_append, + entity_reference_component.get_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), 0) == test_1.id) + + # Add entity reference to container + entity_reference_component.add_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), + 1, test_1.id) + Report.result( + Tests.container_add, + entity_reference_component.get_container_count( + AtomComponentProperties.entity_reference('EntityIdReferences')) == 2 + ) + + # Update entity reference + entity_reference_component.update_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), + 1, test_2.id) + Report.result( + Tests.container_update, + entity_reference_component.get_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), 1) == test_2.id) + + # Remove entity reference + entity_reference_component.append_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), + test_3.id) + count_before = entity_reference_component.get_container_count( + AtomComponentProperties.entity_reference('EntityIdReferences')) + entity_reference_component.remove_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), + 1) + count_after = entity_reference_component.get_container_count( + AtomComponentProperties.entity_reference('EntityIdReferences')) + remove_count = (count_before == 3) and (count_after == 2) + Report.result( + Tests.container_remove, + ((count_before == 3) and (count_after == 2) and + (entity_reference_component.get_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), 1) == test_3.id)) + ) + + # Reset + entity_reference_component.reset_container(AtomComponentProperties.entity_reference('EntityIdReferences')) + Report.result( + Tests.container_reset, + entity_reference_component.get_container_count( + AtomComponentProperties.entity_reference('EntityIdReferences')) == 0 + ) + # 5. Enter/Exit game mode. TestHelper.enter_game_mode(Tests.enter_game_mode) general.idle_wait_frames(1) From 93358dcbeb5148ea76bbb8fc10f0e325dcfe3a83 Mon Sep 17 00:00:00 2001 From: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> Date: Fri, 21 Jan 2022 09:19:53 +0000 Subject: [PATCH 059/136] Cherry-pick of PR-6700 - Updates to ViewportTitleDlg to better expose grid snapping visualization (#6997) * cherry-pick of PR 6700 Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * revert title dialog look to old style Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> --- Code/Editor/ViewportTitleDlg.cpp | 65 ++++++++++++++++++++------------ Code/Editor/ViewportTitleDlg.h | 3 +- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/Code/Editor/ViewportTitleDlg.cpp b/Code/Editor/ViewportTitleDlg.cpp index 75d16e9a40..12f47f70eb 100644 --- a/Code/Editor/ViewportTitleDlg.cpp +++ b/Code/Editor/ViewportTitleDlg.cpp @@ -229,25 +229,35 @@ void CViewportTitleDlg::SetupHelpersButton() void CViewportTitleDlg::SetupOverflowMenu() { - // Setup the overflow menu - QMenu* overFlowMenu = new QMenu(this); + // setup the overflow menu + auto overflowMenu = new QMenu(this); - m_audioMuteAction = new QAction("Mute Audio", overFlowMenu); + m_audioMuteAction = new QAction("Mute Audio", overflowMenu); connect(m_audioMuteAction, &QAction::triggered, this, &CViewportTitleDlg::OnBnClickedMuteAudio); - overFlowMenu->addAction(m_audioMuteAction); + overflowMenu->addAction(m_audioMuteAction); - m_enableVRAction = new QAction("Enable VR Preview", overFlowMenu); + m_enableVRAction = new QAction("Enable VR Preview", overflowMenu); connect(m_enableVRAction, &QAction::triggered, this, &CViewportTitleDlg::OnBnClickedEnableVR); - overFlowMenu->addAction(m_enableVRAction); + overflowMenu->addAction(m_enableVRAction); - overFlowMenu->addSeparator(); + overflowMenu->addSeparator(); - m_enableGridSnappingAction = new QAction("Enable Grid Snapping", overFlowMenu); + m_enableGridSnappingAction = new QAction("Enable Grid Snapping", overflowMenu); connect(m_enableGridSnappingAction, &QAction::triggered, this, &CViewportTitleDlg::OnGridSnappingToggled); m_enableGridSnappingAction->setCheckable(true); - overFlowMenu->addAction(m_enableGridSnappingAction); + overflowMenu->addAction(m_enableGridSnappingAction); - m_gridSizeActionWidget = new QWidgetAction(overFlowMenu); + m_enableGridVisualizationAction = new QAction("Show Grid", overflowMenu); + connect( + m_enableGridVisualizationAction, &QAction::triggered, + [] + { + SandboxEditor::SetShowingGrid(!SandboxEditor::ShowingGrid()); + }); + m_enableGridVisualizationAction->setCheckable(true); + overflowMenu->addAction(m_enableGridVisualizationAction); + + m_gridSizeActionWidget = new QWidgetAction(overflowMenu); m_gridSpinBox = new AzQtComponents::DoubleSpinBox(); m_gridSpinBox->setValue(SandboxEditor::GridSnappingSize()); m_gridSpinBox->setMinimum(1e-2f); @@ -257,31 +267,31 @@ void CViewportTitleDlg::SetupOverflowMenu() m_gridSpinBox, QOverload::of(&AzQtComponents::DoubleSpinBox::valueChanged), this, &CViewportTitleDlg::OnGridSpinBoxChanged); m_gridSizeActionWidget->setDefaultWidget(m_gridSpinBox); - overFlowMenu->addAction(m_gridSizeActionWidget); + overflowMenu->addAction(m_gridSizeActionWidget); - overFlowMenu->addSeparator(); + overflowMenu->addSeparator(); - m_enableAngleSnappingAction = new QAction("Enable Angle Snapping", overFlowMenu); + m_enableAngleSnappingAction = new QAction("Enable Angle Snapping", overflowMenu); connect(m_enableAngleSnappingAction, &QAction::triggered, this, &CViewportTitleDlg::OnAngleSnappingToggled); m_enableAngleSnappingAction->setCheckable(true); - overFlowMenu->addAction(m_enableAngleSnappingAction); + overflowMenu->addAction(m_enableAngleSnappingAction); - m_angleSizeActionWidget = new QWidgetAction(overFlowMenu); + m_angleSizeActionWidget = new QWidgetAction(overflowMenu); m_angleSpinBox = new AzQtComponents::DoubleSpinBox(); m_angleSpinBox->setValue(SandboxEditor::AngleSnappingSize()); m_angleSpinBox->setMinimum(1e-2f); - m_angleSpinBox->setToolTip(tr("Angle Snapping")); + m_angleSpinBox->setToolTip(tr("Angle size")); QObject::connect( m_angleSpinBox, QOverload::of(&AzQtComponents::DoubleSpinBox::valueChanged), this, &CViewportTitleDlg::OnAngleSpinBoxChanged); m_angleSizeActionWidget->setDefaultWidget(m_angleSpinBox); - overFlowMenu->addAction(m_angleSizeActionWidget); + overflowMenu->addAction(m_angleSizeActionWidget); - m_ui->m_overflowBtn->setMenu(overFlowMenu); + m_ui->m_overflowBtn->setMenu(overflowMenu); m_ui->m_overflowBtn->setPopupMode(QToolButton::InstantPopup); - connect(overFlowMenu, &QMenu::aboutToShow, this, &CViewportTitleDlg::UpdateOverFlowMenuState); + connect(overflowMenu, &QMenu::aboutToShow, this, &CViewportTitleDlg::UpdateOverFlowMenuState); UpdateMuteActionText(); } @@ -1004,31 +1014,36 @@ void CViewportTitleDlg::OnAngleSnappingToggled() MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapAngle)->trigger(); } -void CViewportTitleDlg::OnGridSpinBoxChanged(double value) +void CViewportTitleDlg::OnGridSpinBoxChanged(const double value) { - SandboxEditor::SetGridSnappingSize(static_cast(value)); + SandboxEditor::SetGridSnappingSize(aznumeric_cast(value)); } -void CViewportTitleDlg::OnAngleSpinBoxChanged(double value) +void CViewportTitleDlg::OnAngleSpinBoxChanged(const double value) { - SandboxEditor::SetAngleSnappingSize(static_cast(value)); + SandboxEditor::SetAngleSnappingSize(aznumeric_cast(value)); } void CViewportTitleDlg::UpdateOverFlowMenuState() { - bool gridSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapToGrid)->isChecked(); + const bool gridSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapToGrid)->isChecked(); { QSignalBlocker signalBlocker(m_enableGridSnappingAction); m_enableGridSnappingAction->setChecked(gridSnappingActive); } m_gridSizeActionWidget->setEnabled(gridSnappingActive); - bool angleSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapAngle)->isChecked(); + const bool angleSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapAngle)->isChecked(); { QSignalBlocker signalBlocker(m_enableAngleSnappingAction); m_enableAngleSnappingAction->setChecked(angleSnappingActive); } m_angleSizeActionWidget->setEnabled(angleSnappingActive); + + { + QSignalBlocker signalBlocker(m_enableGridVisualizationAction); + m_enableGridVisualizationAction->setChecked(SandboxEditor::ShowingGrid()); + } } namespace diff --git a/Code/Editor/ViewportTitleDlg.h b/Code/Editor/ViewportTitleDlg.h index 6996fe7750..f95828b428 100644 --- a/Code/Editor/ViewportTitleDlg.h +++ b/Code/Editor/ViewportTitleDlg.h @@ -171,6 +171,7 @@ protected: QAction* m_enableVRAction = nullptr; QAction* m_enableGridSnappingAction = nullptr; QAction* m_enableAngleSnappingAction = nullptr; + QAction* m_enableGridVisualizationAction = nullptr; QComboBox* m_cameraSpeed = nullptr; AzQtComponents::DoubleSpinBox* m_gridSpinBox = nullptr; AzQtComponents::DoubleSpinBox* m_angleSpinBox = nullptr; @@ -184,7 +185,7 @@ protected: namespace AzToolsFramework { - //! A component to reflect scriptable commands for the Editor + //! A component to reflect scriptable commands for the Editor. class ViewportTitleDlgPythonFuncsHandler : public AZ::Component { From 56c6f81627fcc957f30a46f5e818cad7558c79c8 Mon Sep 17 00:00:00 2001 From: Sergey Pereslavtsev Date: Fri, 21 Jan 2022 13:21:57 +0000 Subject: [PATCH 060/136] PR addressing. Removed RTTI from HeightMaterialPoint since it's just a struct of data with no intention being a part of class hierarchy Signed-off-by: Sergey Pereslavtsev --- .../Physics/HeightfieldProviderBus.h | 5 +- Gems/PhysX/Code/Source/Utils.cpp | 85 ++++++++++--------- ...ditorHeightfieldColliderComponentTests.cpp | 13 +-- 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h b/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h index da361f0a2b..585fb59ad6 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/HeightfieldProviderBus.h @@ -35,16 +35,15 @@ namespace Physics { } - virtual ~HeightMaterialPoint() = default; + ~HeightMaterialPoint() = default; static void Reflect(AZ::ReflectContext* context); - AZ_RTTI(HeightMaterialPoint, "{DF167ED4-24E6-4F7B-8AB7-42622F7DBAD3}"); + AZ_TYPE_INFO(HeightMaterialPoint, "{DF167ED4-24E6-4F7B-8AB7-42622F7DBAD3}"); float m_height{ 0.0f }; //!< Holds the height of this point in the heightfield relative to the heightfield entity location. QuadMeshType m_quadMeshType{ QuadMeshType::SubdivideUpperLeftToBottomRight }; //!< By default, create two triangles like this |\|, where this point is in the upper left corner. uint8_t m_materialIndex{ 0 }; //!< The surface material index for the upper left corner of this quad. uint16_t m_padding{ 0 }; //!< available for future use. - }; //! An interface to provide heightfield values. diff --git a/Gems/PhysX/Code/Source/Utils.cpp b/Gems/PhysX/Code/Source/Utils.cpp index a988f6791c..950404820d 100644 --- a/Gems/PhysX/Code/Source/Utils.cpp +++ b/Gems/PhysX/Code/Source/Utils.cpp @@ -71,7 +71,6 @@ namespace PhysX const int32_t row, const int32_t col, const int32_t numRows, const int32_t numCols) { - uint8_t materialIndex0 = 0; uint8_t materialIndex1 = 0; @@ -81,49 +80,51 @@ namespace PhysX // In PhysX, the material indices refer to the quad down and to the right of the sample. // If we're in the last row or last column, there aren't any quads down or to the right, // so just clear these out. - - if (!lastRowIndex && !lastColumnIndex) + if (lastRowIndex || lastColumnIndex) { - auto GetIndex = [numCols](int32_t row, int32_t col) - { - return (row * numCols) + col; - }; - - // Our source data is providing one material index per vertex, but PhysX wants one material index - // per triangle. The heuristic that we'll go with for selecting the material index is to choose - // the material for the vertex that's not on the diagonal of each triangle. - // Ex: A *---* B - // | / | For this, we'll use A for index0 and D for index1. - // C *---* D - // - // Ex: A *---* B - // | \ | For this, we'll use C for index0 and B for index1. - // C *---* D - // - // This is a pretty arbitrary choice, so the heuristic might need to be revisited over time if this - // causes incorrect or unpredictable physics material mappings. - - const Physics::HeightMaterialPoint& currentSample = samples[GetIndex(row, col)]; - - switch (currentSample.m_quadMeshType) - { - case Physics::QuadMeshType::SubdivideUpperLeftToBottomRight: - materialIndex0 = samples[GetIndex(row + 1, col)].m_materialIndex; - materialIndex1 = samples[GetIndex(row, col + 1)].m_materialIndex; - break; - case Physics::QuadMeshType::SubdivideBottomLeftToUpperRight: - materialIndex0 = currentSample.m_materialIndex; - materialIndex1 = samples[GetIndex(row + 1, col + 1)].m_materialIndex; - break; - case Physics::QuadMeshType::Hole: - materialIndex0 = physx::PxHeightFieldMaterial::eHOLE; - materialIndex1 = physx::PxHeightFieldMaterial::eHOLE; - break; - default: - AZ_Assert(false, "Unhandled case in GetPhysXMaterialIndicesFromHeightfieldSamples"); - break; - } + return { materialIndex0, materialIndex1 }; } + + auto GetIndex = [numCols](int32_t row, int32_t col) + { + return (row * numCols) + col; + }; + + // Our source data is providing one material index per vertex, but PhysX wants one material index + // per triangle. The heuristic that we'll go with for selecting the material index is to choose + // the material for the vertex that's not on the diagonal of each triangle. + // Ex: A *---* B + // | / | For this, we'll use A for index0 and D for index1. + // C *---* D + // + // Ex: A *---* B + // | \ | For this, we'll use C for index0 and B for index1. + // C *---* D + // + // This is a pretty arbitrary choice, so the heuristic might need to be revisited over time if this + // causes incorrect or unpredictable physics material mappings. + + const Physics::HeightMaterialPoint& currentSample = samples[GetIndex(row, col)]; + + switch (currentSample.m_quadMeshType) + { + case Physics::QuadMeshType::SubdivideUpperLeftToBottomRight: + materialIndex0 = samples[GetIndex(row + 1, col)].m_materialIndex; + materialIndex1 = samples[GetIndex(row, col + 1)].m_materialIndex; + break; + case Physics::QuadMeshType::SubdivideBottomLeftToUpperRight: + materialIndex0 = currentSample.m_materialIndex; + materialIndex1 = samples[GetIndex(row + 1, col + 1)].m_materialIndex; + break; + case Physics::QuadMeshType::Hole: + materialIndex0 = physx::PxHeightFieldMaterial::eHOLE; + materialIndex1 = physx::PxHeightFieldMaterial::eHOLE; + break; + default: + AZ_Assert(false, "Unhandled case in GetPhysXMaterialIndicesFromHeightfieldSamples"); + break; + } + return { materialIndex0, materialIndex1 }; } diff --git a/Gems/PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp b/Gems/PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp index 9bdc63e60d..9a216b7d80 100644 --- a/Gems/PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp +++ b/Gems/PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp @@ -139,9 +139,9 @@ namespace PhysXEditorTests // Create an asset out of our Script Event Physics::MaterialLibraryAsset* matLibAsset = aznew Physics::MaterialLibraryAsset; { - AZStd::vector matIds = GetMaterialList(); + const AZStd::vector matIds = GetMaterialList(); - for (Physics::MaterialId matId : matIds) + for (const Physics::MaterialId& matId : matIds) { Physics::MaterialFromAssetConfiguration matConfig; matConfig.m_id = matId; @@ -336,7 +336,7 @@ namespace PhysXEditorTests // PhysX Heightfield cooking doesn't map 1-1 sample material indices to triangle material indices // Hence hardcoding the expected material indices in the test - const int physicsMaterialsValidationDataIndex[] = {0, 2, 1, 1}; + const AZStd::array physicsMaterialsValidationDataIndex = {0, 2, 1, 1}; for (int sampleRow = 0; sampleRow < numRows; ++sampleRow) { @@ -364,8 +364,11 @@ namespace PhysXEditorTests Physics::Material* mat2 = GetMaterialFromRaycast(rayX + secondRayOffset, rayY + secondRayOffset); EXPECT_NE(mat2, nullptr); - AZStd::string expectedMaterialName = physicsSurfaceTypes[physicsMaterialsValidationDataIndex[sampleRow * 2 + sampleColumn]]; - EXPECT_EQ(mat1->GetSurfaceTypeName(), expectedMaterialName); + if (mat1) + { + AZStd::string expectedMaterialName = physicsSurfaceTypes[physicsMaterialsValidationDataIndex[sampleRow * 2 + sampleColumn]]; + EXPECT_EQ(mat1->GetSurfaceTypeName(), expectedMaterialName); + } } } } From 9328f053bd40c2012bf7c06f94d479c3813c05af Mon Sep 17 00:00:00 2001 From: Nicholas Lawson <70027408+lawsonamzn@users.noreply.github.com> Date: Fri, 21 Jan 2022 08:00:45 -0800 Subject: [PATCH 061/136] Updates EXPAT to use the latest packages (#7053) * Update EXPAT to be latest package version Signed-off-by: lawsonamzn <70027408+lawsonamzn@users.noreply.github.com> --- Code/Legacy/CrySystem/XML/xml.cpp | 1 - cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake | 2 +- cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake | 2 +- cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake | 2 +- cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake | 2 +- cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake | 2 +- 6 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Code/Legacy/CrySystem/XML/xml.cpp b/Code/Legacy/CrySystem/XML/xml.cpp index 95755d78fe..fb0714500c 100644 --- a/Code/Legacy/CrySystem/XML/xml.cpp +++ b/Code/Legacy/CrySystem/XML/xml.cpp @@ -11,7 +11,6 @@ #include -#define XML_STATIC // Alternative to defining this here would be setting it project-wide #include #include "xml.h" #include diff --git a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake index c6a262926c..d231954c49 100644 --- a/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake +++ b/cmake/3rdParty/Platform/Android/BuiltInPackages_android.cmake @@ -11,7 +11,7 @@ ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform TARGETS RapidJSON PACKAGE_HASH 2f5e26ecf86c3b7a262753e7da69ac59928e78e9534361f3d00c1ad5879e4023) ly_associate_package(PACKAGE_NAME RapidXML-1.13-rev1-multiplatform TARGETS RapidXML PACKAGE_HASH 4b7b5651e47cfd019b6b295cc17bb147b65e53073eaab4a0c0d20a37ab74a246) ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2) -ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418) +ly_associate_package(PACKAGE_NAME expat-2.4.2-rev1-android TARGETS expat PACKAGE_HASH 8c626bd58c2f9bb82cb654c2483be60e67f3a601547dee43686638a5e662bf3e) ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665) ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) diff --git a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake index 8db3099a5c..ee91415a6d 100644 --- a/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake +++ b/cmake/3rdParty/Platform/Linux/BuiltInPackages_linux.cmake @@ -13,7 +13,7 @@ ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform ly_associate_package(PACKAGE_NAME RapidXML-1.13-rev1-multiplatform TARGETS RapidXML PACKAGE_HASH 4b7b5651e47cfd019b6b295cc17bb147b65e53073eaab4a0c0d20a37ab74a246) ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev3-multiplatform TARGETS pybind11 PACKAGE_HASH dccb5546607b8b31cd207033aaf24ab044ce6e188a9f12411236a010f9e0c4ff) ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2) -ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418) +ly_associate_package(PACKAGE_NAME expat-2.4.2-rev1-linux TARGETS expat PACKAGE_HASH 07621d684fd909e2768e696a2652cfb1e975093f738193cfdcb60a016a9a9d4e) ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665) ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) ly_associate_package(PACKAGE_NAME xxhash-0.7.4-rev1-multiplatform TARGETS xxhash PACKAGE_HASH e81f3e6c4065975833996dd1fcffe46c3cf0f9e3a4207ec5f4a1b564ba75861e) diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index 95f7c89930..1bcad01c1d 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -13,7 +13,7 @@ ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform ly_associate_package(PACKAGE_NAME RapidXML-1.13-rev1-multiplatform TARGETS RapidXML PACKAGE_HASH 4b7b5651e47cfd019b6b295cc17bb147b65e53073eaab4a0c0d20a37ab74a246) ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev3-multiplatform TARGETS pybind11 PACKAGE_HASH dccb5546607b8b31cd207033aaf24ab044ce6e188a9f12411236a010f9e0c4ff) ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2) -ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418) +ly_associate_package(PACKAGE_NAME expat-2.4.2-rev1-mac TARGETS expat PACKAGE_HASH 231ec2cb8ef9ddeef891e5bd7215ad91864e3410a22fad5ab8355e7bf53621fe) ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665) ly_associate_package(PACKAGE_NAME SQLite-3.32.2-rev3-multiplatform TARGETS SQLite PACKAGE_HASH dd4d3de6cbb4ce3d15fc504ba0ae0587e515dc89a25228037035fc0aef4831f4) ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) diff --git a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake index 1f7cb8d28f..c872708a3a 100644 --- a/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake +++ b/cmake/3rdParty/Platform/Windows/BuiltInPackages_windows.cmake @@ -13,7 +13,7 @@ ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform ly_associate_package(PACKAGE_NAME RapidXML-1.13-rev1-multiplatform TARGETS RapidXML PACKAGE_HASH 4b7b5651e47cfd019b6b295cc17bb147b65e53073eaab4a0c0d20a37ab74a246) ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev3-multiplatform TARGETS pybind11 PACKAGE_HASH dccb5546607b8b31cd207033aaf24ab044ce6e188a9f12411236a010f9e0c4ff) ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2) -ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418) +ly_associate_package(PACKAGE_NAME expat-2.4.2-rev1-windows TARGETS expat PACKAGE_HASH 123d81dcd0e30306fdb0d062348b992e68358cc31f0a15a98c4c04fc68dc437e) ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665) ly_associate_package(PACKAGE_NAME SQLite-3.32.2-rev3-multiplatform TARGETS SQLite PACKAGE_HASH dd4d3de6cbb4ce3d15fc504ba0ae0587e515dc89a25228037035fc0aef4831f4) ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) diff --git a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake index 4b99efc9d0..3f1bb204f7 100644 --- a/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake +++ b/cmake/3rdParty/Platform/iOS/BuiltInPackages_ios.cmake @@ -11,7 +11,7 @@ ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform TARGETS RapidJSON PACKAGE_HASH 2f5e26ecf86c3b7a262753e7da69ac59928e78e9534361f3d00c1ad5879e4023) ly_associate_package(PACKAGE_NAME RapidXML-1.13-rev1-multiplatform TARGETS RapidXML PACKAGE_HASH 4b7b5651e47cfd019b6b295cc17bb147b65e53073eaab4a0c0d20a37ab74a246) ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2) -ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418) +ly_associate_package(PACKAGE_NAME expat-2.4.2-rev1-ios TARGETS expat PACKAGE_HASH 2e4f1ecaa9d7e9eb2f6f3b4a32d1b1a12605accf0ab3975175553b90917eb2d5) ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665) ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee) From 145e3646a49fab1e3594d95c157e2f7ced824e24 Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Fri, 21 Jan 2022 10:34:00 -0600 Subject: [PATCH 062/136] Asset catalog lock inversion fix. (#7045) * Fix lock inversion. This method was calling AssetCatalog->AssetManager at the same time that loading threads are calling AssetManager->AssetCatalog, causing a deadlock due to lock inversion. The fix is to make this method call AssetManager *outside* of the AssetCatalog call. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Fixing the root cause in EnumerateAssets. Also added a unit test that failed with the previous EnumerateAssets logic, and succeeds with the new logic. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Make sure not to hold the secondary mutex lock either. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Remove unused alias. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> --- .../AzFramework/Asset/AssetCatalog.cpp | 29 ++++- .../AzFramework/Tests/AssetCatalog.cpp | 105 ++++++++++++++++++ 2 files changed, 132 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp b/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp index 0c6b195434..a0f6b0608c 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp +++ b/Code/Framework/AzFramework/AzFramework/Asset/AssetCatalog.cpp @@ -489,6 +489,21 @@ namespace AzFramework //========================================================================= void AssetCatalog::EnumerateAssets(BeginAssetEnumerationCB beginCB, AssetEnumerationCB enumerateCB, EndAssetEnumerationCB endCB) { + using AssetCatalogRequestBusContext = typename AZ::Data::AssetCatalogRequestBus::Context; + + // Setting trackCallstack to true causes the context mutex to attempt to re-lock. + // That is being avoided here as the code only wants to unlock the Context mutex if it is in a dispatch. + constexpr bool trackCallstack = false; + AssetCatalogRequestBusContext* assetCatalogContext = AZ::Data::AssetCatalogRequestBus::GetContext(trackCallstack); + + bool hasAssetCatalogMutex = false; + if (assetCatalogContext != nullptr && AZ::Data::AssetCatalogRequestBus::IsInDispatchThisThread(assetCatalogContext)) + { + hasAssetCatalogMutex = true; + // Unlock the dispatch mutex for the AssetCatalogRequestBus + assetCatalogContext->m_contextMutex.unlock(); + } + if (beginCB) { beginCB(); @@ -496,9 +511,13 @@ namespace AzFramework if (enumerateCB) { - AZStd::lock_guard lock(m_registryMutex); + // Make sure we don't hold on to any locks during the enumerateCB, so copy the registry info to a local variable + // and unlock the registryMutex before calling the callback. + m_registryMutex.lock(); + auto assetIdToInfoCopy = m_registry->m_assetIdToInfo; + m_registryMutex.unlock(); - for (auto& it : m_registry->m_assetIdToInfo) + for (auto& it : assetIdToInfoCopy) { enumerateCB(it.first, it.second); } @@ -508,6 +527,12 @@ namespace AzFramework { endCB(); } + + if (hasAssetCatalogMutex) + { + // Relock the mutex if it was unlocked earlier + assetCatalogContext->m_contextMutex.lock(); + } } //========================================================================= diff --git a/Code/Framework/AzFramework/Tests/AssetCatalog.cpp b/Code/Framework/AzFramework/Tests/AssetCatalog.cpp index 8a24d164cd..e731b633f0 100644 --- a/Code/Framework/AzFramework/Tests/AssetCatalog.cpp +++ b/Code/Framework/AzFramework/Tests/AssetCatalog.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -931,6 +933,109 @@ namespace UnitTest EXPECT_FALSE(m_assetCatalog->DoesAssetIdMatchWildcardPattern(m_firstAssetId, "")); } + TEST_F(AssetCatalogAPITest, EnumerateAssetsListsCorrectAssets) + { + AZStd::vector foundAssets; + + AZ::Data::AssetCatalogRequestBus::Broadcast( + &AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets, nullptr, + [&foundAssets](const AZ::Data::AssetId assetId, [[maybe_unused]] const AZ::Data::AssetInfo& assetInfo) + { + foundAssets.emplace_back(assetId); + }, + nullptr); + + ASSERT_EQ(foundAssets.size(), 2); + EXPECT_EQ(foundAssets[0], m_firstAssetId); + EXPECT_EQ(foundAssets[1], m_secondAssetId); + } + + TEST_F(AssetCatalogAPITest, EnumerateAssetsDoesNotBlockMutex) + { + // This test simulates a previously-occurring deadlock bug caused by having the main thread call AssetCatalog::EnumerateAssets + // with a callback that calls the AssetManager, and a loading thread running underneath the AssetManager that calls the + // AssetCatalog. + // To reproduce this state, we will do the following: + // Main Thread Job Thread + // wait on mainToJobSync + // call EnumerateAssets + // unblock mainToJobSync + // wait on jobToMainSync call AssetCatalog::X + // unblock jobToMainSync + // + // These steps should ensure that we create a theoretical "lock inversion", if EnumerateAssets locked an AssetCatalog mutex. + // Even though we're using binary semaphores instead of mutexes, we're creating the same blocking situation. + // EnumerateAssets itself should no longer lock the AssetCatalog mutex, so this test should succeed since there won't be any + // actual lock inversion. + + // Set up job manager with one thread that we can use to set up the concurrent mutex access. + AZ::AllocatorInstance::Create(); + AZ::JobManagerDesc desc; + AZ::JobManagerThreadDesc threadDesc; + desc.m_workerThreads.push_back(threadDesc); + auto jobManager = aznew AZ::JobManager(desc); + auto jobContext = aznew AZ::JobContext(*jobManager); + AZ::JobContext::SetGlobalContext(jobContext); + + AZStd::binary_semaphore mainToJobSync; + AZStd::binary_semaphore jobToMainSync; + + // Create a job whose sole purpose is to wait for EnumerateAssets to get called, call AssetCatalog, then tell EnumerateAssets + // to finish. If EnumerateAssets has a mutex held, this will deadlock. + auto job = AZ::CreateJobFunction( + [&mainToJobSync, &jobToMainSync]() mutable + { + // wait for the main thread to be inside the EnumerateAssets callback. + mainToJobSync.acquire(); + + // call AssetCatalog::X. This will deadlock if EnumerateAssets is holding an AssetCatalog mutex. + [[maybe_unused]] AZStd::string assetPath; + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + assetPath, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetPathById, AZ::Data::AssetId()); + + // signal the main thread to continue + jobToMainSync.release(); + }, + true); + job->Start(); + + bool testCompletedSuccessfully = false; + + // Call EnumerateAssets with a callback that also tries to lock the mutex. + AZ::Data::AssetCatalogRequestBus::Broadcast( + &AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets, nullptr, + [this, &mainToJobSync, &jobToMainSync, &testCompletedSuccessfully] + (const AZ::Data::AssetId assetId, [[maybe_unused]] const AZ::Data::AssetInfo& assetInfo) + { + // Only run this logic on the first assetId. + if (assetId == m_firstAssetId) + { + // Tell the job it can continue + mainToJobSync.release(); + + // Wait for the job to finish calling AssetCatalog::X. This will deadlock if EnumerateAssets is holding an + // AssetCatalog mutex. + if (jobToMainSync.try_acquire_for(AZStd::chrono::seconds(5))) + { + // Only mark the test as completed successfully if we ran this logic and didn't deadlock. + testCompletedSuccessfully = true; + } + + } + }, + nullptr); + + EXPECT_TRUE(testCompletedSuccessfully); + + // Clean up the job manager + AZ::JobContext::SetGlobalContext(nullptr); + delete jobContext; + delete jobManager; + AZ::AllocatorInstance::Destroy(); + } + + + class AssetType1 : public AssetData { From 526ee7644a86ad6c2c2c4cfbc3d00ef3e0b02946 Mon Sep 17 00:00:00 2001 From: Scott Romero <24445312+AMZN-ScottR@users.noreply.github.com> Date: Fri, 21 Jan 2022 09:04:33 -0800 Subject: [PATCH 063/136] [development] fixed configure error with monolithic builds (#7057) The AWSNativeSDKTestLibs target is now only defined when tests are enabled Signed-off-by: AMZN-ScottR 24445312+AMZN-ScottR@users.noreply.github.com --- Code/Tools/AWSNativeSDKInit/CMakeLists.txt | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Code/Tools/AWSNativeSDKInit/CMakeLists.txt b/Code/Tools/AWSNativeSDKInit/CMakeLists.txt index de3e0008c2..7f04262781 100644 --- a/Code/Tools/AWSNativeSDKInit/CMakeLists.txt +++ b/Code/Tools/AWSNativeSDKInit/CMakeLists.txt @@ -25,28 +25,28 @@ ly_add_target( AZ::AzCore ) -ly_add_target( - NAME AWSNativeSDKTestLibs STATIC - NAMESPACE AZ - FILES_CMAKE - aws_native_sdk_test_files.cmake - INCLUDE_DIRECTORIES - PUBLIC - include - tests/libs - PRIVATE - source - BUILD_DEPENDENCIES - PRIVATE - 3rdParty::AWSNativeSDK::Core - AZ::AzCore - AZ::AzTest -) - ################################################################################ # Tests ################################################################################ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) + ly_add_target( + NAME AWSNativeSDKTestLibs STATIC + NAMESPACE AZ + FILES_CMAKE + aws_native_sdk_test_files.cmake + INCLUDE_DIRECTORIES + PUBLIC + include + tests/libs + PRIVATE + source + BUILD_DEPENDENCIES + PRIVATE + 3rdParty::AWSNativeSDK::Core + AZ::AzCore + AZ::AzTest + ) + ly_add_target( NAME AWSNativeSDKInit.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} NAMESPACE AZ From 09dd3a87299c20b7c27da52f8f866f7ea9b7098f Mon Sep 17 00:00:00 2001 From: Scott Romero <24445312+AMZN-ScottR@users.noreply.github.com> Date: Fri, 21 Jan 2022 09:06:14 -0800 Subject: [PATCH 064/136] [development] patch fix for launcher exit crash (#7050) The launcher will crash on exit due to an access violation when clearing the BudgetTracker after CrySystem is unloaded. This is from a recent change to how the budget pointers are tracked making the BudgetTracker responsible for clearing them so the system can be re-entrant. Unfortunately, an assumption was made that all modules that use Budgets are managed by the ComponentApplication so they can be cleared prior to being unloaded. This is a patch to manually reset the BudgetTracker prior to unloading CrySystem until the legacy system can be removed (or converted to an AZ-like module). Signed-off-by: AMZN-ScottR 24445312+AMZN-ScottR@users.noreply.github.com --- Code/LauncherUnified/Launcher.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Code/LauncherUnified/Launcher.cpp b/Code/LauncherUnified/Launcher.cpp index 9dfd6213c4..7b681c5208 100644 --- a/Code/LauncherUnified/Launcher.cpp +++ b/Code/LauncherUnified/Launcher.cpp @@ -10,14 +10,17 @@ #include #include +#include +#include #include +#include #include #include #include -#include #include #include #include + #include #include #include @@ -571,6 +574,17 @@ namespace O3DELauncher } #if !defined(AZ_MONOLITHIC_BUILD) + + #if !defined(_RELEASE) + // until CrySystem can be removed (or made to be managed by the component application), + // we need to manually clear the BudgetTracker before CrySystem is unloaded so the Budget + // pointer(s) it has references to are cleared properly + if (auto budgetTracker = AZ::Interface::Get(); budgetTracker) + { + budgetTracker->Reset(); + } + #endif // !defined(_RELEASE) + delete systemInitParams.pSystem; crySystemLibrary.reset(nullptr); #endif // !defined(AZ_MONOLITHIC_BUILD) From 807464c58d29fa3c6afde1a12551b0f4ed2b7750 Mon Sep 17 00:00:00 2001 From: Scott Romero <24445312+AMZN-ScottR@users.noreply.github.com> Date: Fri, 21 Jan 2022 09:08:24 -0800 Subject: [PATCH 065/136] [development] updated Android build node configuration (#7007) Added the NDK to the install list Removed Android Java APIs prior to 28 from package list as they are unnecessary Updated LY_NDK_DIR to point to the SDK manager version Updated some inconsistencies in how the min Android native API is handled Signed-off-by: AMZN-ScottR 24445312+AMZN-ScottR@users.noreply.github.com --- cmake/Platform/Android/Toolchain_android.cmake | 10 +++++++++- .../Tools/Platform/Android/generate_android_project.py | 2 +- scripts/build/Platform/Android/build_config.json | 10 +++++----- scripts/build/Platform/Android/pipeline.json | 4 ++-- .../build_node/Platform/Windows/install_android.ps1 | 6 +++--- 5 files changed, 20 insertions(+), 12 deletions(-) diff --git a/cmake/Platform/Android/Toolchain_android.cmake b/cmake/Platform/Android/Toolchain_android.cmake index 974eb33681..23b51a4c70 100644 --- a/cmake/Platform/Android/Toolchain_android.cmake +++ b/cmake/Platform/Android/Toolchain_android.cmake @@ -36,9 +36,17 @@ endif() if(NOT ANDROID_ABI MATCHES "^arm64-") message(FATAL_ERROR "Only the 64-bit ANDROID_ABI's are supported. arm64-v8a can be used if not set") endif() + +set(MIN_NATIVE_API_LEVEL 24) + if(NOT ANDROID_NATIVE_API_LEVEL) - set(ANDROID_NATIVE_API_LEVEL 24) + set(ANDROID_NATIVE_API_LEVEL ${MIN_NATIVE_API_LEVEL}) endif() + +if(${ANDROID_NATIVE_API_LEVEL} VERSION_LESS ${MIN_NATIVE_API_LEVEL}) + message(FATAL_ERROR "Unsupported Android native API version ${ANDROID_NATIVE_API_LEVEL}. Must be ${MIN_NATIVE_API_LEVEL} or above") +endif() + set(ANDROID_PLATFORM android-${ANDROID_NATIVE_API_LEVEL}) # Make a backup of the CMAKE_FIND_ROOT_PATH since it will be altered by the NDK toolchain file and needs to be restored after the input diff --git a/cmake/Tools/Platform/Android/generate_android_project.py b/cmake/Tools/Platform/Android/generate_android_project.py index 5e414e7738..a12006bd53 100755 --- a/cmake/Tools/Platform/Android/generate_android_project.py +++ b/cmake/Tools/Platform/Android/generate_android_project.py @@ -181,7 +181,7 @@ def main(args): default=-1) parser.add_argument(ANDROID_NATIVE_API_LEVEL, - help=f'The android native API level to use for the APK. If not set, this will default to the android SDK platform. (Minimum {MIN_ANDROID_SDK_PLATFORM})', + help=f'The android native API level to use for the APK. If not set, this will default to the android SDK platform. (Minimum {MIN_NATIVE_API_LEVEL})', type=int, default=-1) diff --git a/scripts/build/Platform/Android/build_config.json b/scripts/build/Platform/Android/build_config.json index c505d8e940..da538b22ec 100644 --- a/scripts/build/Platform/Android/build_config.json +++ b/scripts/build/Platform/Android/build_config.json @@ -35,7 +35,7 @@ "PARAMETERS": { "CONFIGURATION":"debug", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_NDK_DIR!\"", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_NATIVE_API_LEVEL=24 -DLY_NDK_DIR=\"!LY_NDK_DIR!\"", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -50,7 +50,7 @@ "PARAMETERS": { "CONFIGURATION":"profile", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_NDK_DIR!\"", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_NATIVE_API_LEVEL=24 -DLY_NDK_DIR=\"!LY_NDK_DIR!\"", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -66,7 +66,7 @@ "PARAMETERS": { "CONFIGURATION":"profile", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_NDK_DIR!\" -DLY_UNITY_BUILD=FALSE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_NATIVE_API_LEVEL=24 -DLY_NDK_DIR=\"!LY_NDK_DIR!\" -DLY_UNITY_BUILD=FALSE", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -102,7 +102,7 @@ "PARAMETERS": { "CONFIGURATION":"release", "OUTPUT_DIRECTORY":"build\\android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_NDK_DIR!\"", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_NATIVE_API_LEVEL=24 -DLY_NDK_DIR=\"!LY_NDK_DIR!\"", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" @@ -118,7 +118,7 @@ "PARAMETERS": { "CONFIGURATION":"release", "OUTPUT_DIRECTORY":"build\\mono_android", - "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_NATIVE_API_LEVEL=21 -DLY_NDK_DIR=\"!LY_NDK_DIR!\" -DLY_MONOLITHIC_GAME=TRUE", + "CMAKE_OPTIONS":"-G \"Ninja Multi-Config\" -DCMAKE_TOOLCHAIN_FILE=cmake\\Platform\\Android\\Toolchain_android.cmake -DANDROID_NATIVE_API_LEVEL=24 -DLY_NDK_DIR=\"!LY_NDK_DIR!\" -DLY_MONOLITHIC_GAME=TRUE", "CMAKE_LY_PROJECTS":"AutomatedTesting", "CMAKE_TARGET":"all", "CMAKE_BUILD_ARGS":"-j!NUMBER_OF_PROCESSORS!" diff --git a/scripts/build/Platform/Android/pipeline.json b/scripts/build/Platform/Android/pipeline.json index f0292f4501..2e426c7891 100644 --- a/scripts/build/Platform/Android/pipeline.json +++ b/scripts/build/Platform/Android/pipeline.json @@ -1,9 +1,9 @@ { "ENV": { "GRADLE_HOME": "C:/Gradle/gradle-7.0", - "NODE_LABEL": "windows-b3c8994f1", + "NODE_LABEL": "windows-a4a28adb2", "LY_3RDPARTY_PATH": "D:/workspace/3rdParty", - "LY_NDK_DIR": "C:/ly/3rdParty/android-ndk/r21d", + "LY_NDK_DIR": "C:/Android/android-sdk/ndk/21.4.7075529", "TIMEOUT": 30, "WORKSPACE": "D:/workspace", "MOUNT_VOLUME": true diff --git a/scripts/build/build_node/Platform/Windows/install_android.ps1 b/scripts/build/build_node/Platform/Windows/install_android.ps1 index 0a725af573..497ec508cc 100644 --- a/scripts/build/build_node/Platform/Windows/install_android.ps1 +++ b/scripts/build/build_node/Platform/Windows/install_android.ps1 @@ -10,16 +10,16 @@ choco install -y android-sdk $Env:ANDROID_HOME = "C:\Android\android-sdk" setx ANDROID_HOME "C:\Android\android-sdk" -$apis_packages = '"add-ons;addon-google_apis-google-19" "add-ons;addon-google_apis-google-21" "add-ons;addon-google_apis-google-22" "add-ons;addon-google_apis-google-23" "add-ons;addon-google_apis-google-24"' -$android_packages = '"platforms;android-19" "platforms;android-21" "platforms;android-22" "platforms;android-23" "platforms;android-24" "platforms;android-25" "platforms;android-26" "platforms;android-27" "platforms;android-28" "platforms;android-29" "platforms;android-30"' +$android_packages = '"platforms;android-28" "platforms;android-29" "platforms;android-30"' $googleplay_packages = '"extras;google;market_apk_expansion" "extras;google;market_licensing"' $build_tools = '"build-tools;30.0.2" "tools"' +$ndk = '"ndk;21.4.7075529"' $sdkmanager = "C:\Android\android-sdk\tools\bin\sdkmanager.bat" -Start-Process -FilePath $sdkmanager -ArgumentList $apis_packages -NoNewWindow -Wait Start-Process -FilePath $sdkmanager -ArgumentList $android_packages -NoNewWindow -Wait Start-Process -FilePath $sdkmanager -ArgumentList $googleplay_packages -NoNewWindow -Wait Start-Process -FilePath $sdkmanager -ArgumentList $build_tools -NoNewWindow -Wait +Start-Process -FilePath $sdkmanager -ArgumentList $ndk -NoNewWindow -Wait Write-Host "Installing Gradle and Ninja" Import-Module C:\ProgramData\chocolatey\helpers\chocolateyInstaller.psm1 #Grade needs a custom installer due to being hardcoded to C:\Programdata in Chocolatey From edbebb5f477f14dfc86535800201c50ca7781400 Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Fri, 21 Jan 2022 09:19:54 -0800 Subject: [PATCH 066/136] Minor class definition updates for AWSGem (#7056) * Move the queued-events constructors for AWSApiClientJob and ServiceRequestJob from public to protected, and add short description for them Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> --- .../Code/Include/Framework/AWSApiRequestJob.h | 37 ++++++++---------- .../Include/Framework/ServiceRequestJob.h | 38 ++++++++----------- 2 files changed, 30 insertions(+), 45 deletions(-) diff --git a/Gems/AWSCore/Code/Include/Framework/AWSApiRequestJob.h b/Gems/AWSCore/Code/Include/Framework/AWSApiRequestJob.h index 33c7e1ad29..816e9bc4b4 100644 --- a/Gems/AWSCore/Code/Include/Framework/AWSApiRequestJob.h +++ b/Gems/AWSCore/Code/Include/Framework/AWSApiRequestJob.h @@ -188,28 +188,6 @@ namespace AWSCore { } - AwsApiRequestJob(bool queueOnSuccess, - OnSuccessFunction onSuccess, - bool queueOnFailure, - OnFailureFunction onFailure, - bool queueDelete, - IConfig* config = GetDefaultConfig() - ) : AwsApiClientJobType(false, config) - , m_queueOnSuccess{ queueOnSuccess } - , m_onSuccess{ onSuccess } - , m_queueOnFailure{ queueOnFailure } - , m_onFailure{ onFailure } - , m_queueDelete{ queueDelete } - { - } - - AwsApiRequestJob(OnSuccessFunction onSuccess, - OnFailureFunction onFailure, - IConfig* config = GetDefaultConfig() - ) : AwsApiRequestJob(true, onSuccess, true, onFailure, true, config) - { - } - RequestType request; ResultType result; ErrorType error; @@ -232,6 +210,21 @@ namespace AWSCore } protected: + + /// Constructor for creating AwsApiRequestJob Jobs that can handle queued responses + /// for OnSuccess, OnFailure, and DoCleanup + AwsApiRequestJob(OnSuccessFunction onSuccess, + OnFailureFunction onFailure, + IConfig* config = GetDefaultConfig() + ) : AwsApiClientJobType(false, config) + , m_queueOnSuccess{ true } + , m_onSuccess{ onSuccess } + , m_queueOnFailure{ true } + , m_onFailure{ onFailure } + , m_queueDelete{ true } + { + } + bool m_wasSuccess{ false }; // Flag and optional function call to queue for onSuccess events diff --git a/Gems/AWSCore/Code/Include/Framework/ServiceRequestJob.h b/Gems/AWSCore/Code/Include/Framework/ServiceRequestJob.h index 6d00122d99..d3eac4983a 100644 --- a/Gems/AWSCore/Code/Include/Framework/ServiceRequestJob.h +++ b/Gems/AWSCore/Code/Include/Framework/ServiceRequestJob.h @@ -178,29 +178,6 @@ namespace AWSCore } } - ServiceRequestJob(bool queueOnSuccess, - OnSuccessFunction onSuccess, - bool queueOnFailure, - OnFailureFunction onFailure, - bool queueDelete, - IConfig* config = GetDefaultConfig() - ) : ServiceClientJobType{ false, config } - , m_requestUrl{ config->GetRequestUrl() } - , m_queueOnSuccess{ queueOnSuccess } - , m_onSuccess{ onSuccess } - , m_queueOnFailure{ queueOnFailure } - , m_onFailure{ onFailure } - , m_queueDelete{ queueDelete } - { - } - - ServiceRequestJob(OnSuccessFunction onSuccess, - OnFailureFunction onFailure, - IConfig* config = GetDefaultConfig() - ) : ServiceRequestJob(true, onSuccess, true, onFailure, true, config) - { - } - bool HasCredentials(IConfig* config) { if (config == nullptr) @@ -241,6 +218,21 @@ namespace AWSCore /// for replacing these parts of the url. const Aws::String& m_requestUrl; + /// Constructor for creating ServiceRequestJob Jobs that can handle queued responses + /// for OnSuccess, OnFailure, and DoCleanup + ServiceRequestJob(OnSuccessFunction onSuccess, + OnFailureFunction onFailure, + IConfig* config = GetDefaultConfig() + ) : ServiceClientJobType{ false, config } + , m_requestUrl{ config->GetRequestUrl() } + , m_queueOnSuccess{ true } + , m_onSuccess{ onSuccess } + , m_queueOnFailure{ true } + , m_onFailure{ onFailure } + , m_queueDelete{ true } + { + } + // Flag and optional function call to queue for onSuccess events bool m_queueOnSuccess{ false }; OnSuccessFunction m_onSuccess{}; From 1d3b675f889a742ea577aa73edbdc694975a5d56 Mon Sep 17 00:00:00 2001 From: lsemp3d <58790905+lsemp3d@users.noreply.github.com> Date: Fri, 21 Jan 2022 09:35:42 -0800 Subject: [PATCH 067/136] Regenerated the Input handler .names file Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> --- .../Nodes/Input_InputHandler.names | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/Nodes/Input_InputHandler.names b/Gems/ScriptCanvas/Assets/TranslationAssets/Nodes/Input_InputHandler.names index 8ce3fd36df..120c8f8ef3 100644 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/Nodes/Input_InputHandler.names +++ b/Gems/ScriptCanvas/Assets/TranslationAssets/Nodes/Input_InputHandler.names @@ -1,7 +1,7 @@ { "entries": [ { - "base": "{0B0AC61B-4BBA-42BF-BDCD-DAF2D3CA41A8}", + "base": "{0A2EB488-5A6A-E166-BB62-23FF81499E33}", "context": "ScriptCanvas::Node", "variant": "", "details": { @@ -10,6 +10,13 @@ "tooltip": "Handle processed input events found in input binding assets" }, "slots": [ + { + "base": "Input_Connect Event_0", + "details": { + "name": "Connect Event", + "tooltip": "Connect to input event name as defined in an input binding asset." + } + }, { "base": "DataInput_Event Name_0", "details": { @@ -17,27 +24,34 @@ } }, { - "base": "DataOutput_Value_0", + "base": "Output_On Connect Event_0", "details": { - "name": "Value" + "name": "On Connect Event", + "tooltip": "Connect to input event name as defined in an input binding asset." } }, { - "base": "Output_Pressed_0", + "base": "Output_Pressed_1", "details": { "name": "Pressed", "tooltip": "Signaled when the input event begins." } }, { - "base": "Output_Held_1", + "base": "DataOutput_value_0", + "details": { + "name": "value" + } + }, + { + "base": "Output_Held_2", "details": { "name": "Held", "tooltip": "Signaled while the input event is active." } }, { - "base": "Output_Released_2", + "base": "Output_Released_3", "details": { "name": "Released", "tooltip": "Signaled when the input event ends." From be2241bda956d286fbf0161600d84422635f1a15 Mon Sep 17 00:00:00 2001 From: lsemp3d <58790905+lsemp3d@users.noreply.github.com> Date: Fri, 21 Jan 2022 09:41:37 -0800 Subject: [PATCH 068/136] Navigate to file after generating translation (only 1) Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> --- .../ScriptCanvasNodePaletteDockWidget.cpp | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp index 60d903d748..4b622bc025 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp @@ -894,6 +894,26 @@ namespace ScriptCanvasEditor GraphCanvas::NodePaletteTreeItem* nodePaletteItem = static_cast(sourceIndex.internalPointer()); nodePaletteItem->GenerateTranslationData(); } + + if (indexList.size() == 1) + { + AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); + QModelIndex sourceIndex = filterModel->mapToSource(indexList[0]); + if (sourceIndex.isValid()) + { + GraphCanvas::NodePaletteTreeItem* nodePaletteItem = static_cast(sourceIndex.internalPointer()); + + AZ::IO::Path gemPath = GetGemPath("ScriptCanvas.Editor"); + gemPath = gemPath / AZ::IO::Path("TranslationAssets"); + gemPath = gemPath / nodePaletteItem->GetTranslationDataPath(); + gemPath.ReplaceExtension(".names"); + + if (fileIO->Exists(gemPath.c_str())) + { + AzQtComponents::ShowFileOnDesktop(gemPath.c_str()); + } + } + } } void NodePaletteDockWidget::OpenTranslationData() From f684fe14ff81d329e1ae90e434710a0418a5d8f7 Mon Sep 17 00:00:00 2001 From: lsemp3d <58790905+lsemp3d@users.noreply.github.com> Date: Fri, 21 Jan 2022 09:45:27 -0800 Subject: [PATCH 069/136] Categorized Material Data under Rendering Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> --- .../Assets/TranslationAssets/Classes/MaterialData.names | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/MaterialData.names b/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/MaterialData.names index 9f6af426d0..72e48aa400 100644 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/MaterialData.names +++ b/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/MaterialData.names @@ -5,7 +5,8 @@ "context": "BehaviorClass", "variant": "", "details": { - "name": "Material Data" + "name": "Material Data", + "category": "Rendering" }, "methods": [ { From 238962be739fe2dda678b92342d528e390675e7b Mon Sep 17 00:00:00 2001 From: Mikhail Naumov <82239319+AMZN-mnaumov@users.noreply.github.com> Date: Fri, 21 Jan 2022 12:02:40 -0600 Subject: [PATCH 070/136] fixing crash when opening different level during simulation mode (#6762) Signed-off-by: Mikhail Naumov --- Code/Editor/CryEdit.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 3beaf4d438..8789b31fdc 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -3363,6 +3363,10 @@ CCryEditDoc* CCryEditApp::OpenDocumentFile(const char* filename, bool addToMostR return GetIEditor()->GetDocument(); } + bool usePrefabSystemForLevels = false; + AzFramework::ApplicationRequests::Bus::BroadcastResult( + usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled); + // If we are loading and we're in simulate mode, then switch it off before we do anything else if (GetIEditor()->GetGameEngine() && GetIEditor()->GetGameEngine()->GetSimulationMode()) { @@ -3370,6 +3374,15 @@ CCryEditDoc* CCryEditApp::OpenDocumentFile(const char* filename, bool addToMostR bool bIsDocModified = GetIEditor()->GetDocument()->IsModified(); OnSwitchPhysics(); GetIEditor()->GetDocument()->SetModifiedFlag(bIsDocModified); + + if (usePrefabSystemForLevels) + { + auto* rootSpawnableInterface = AzFramework::RootSpawnableInterface::Get(); + if (rootSpawnableInterface) + { + rootSpawnableInterface->ProcessSpawnableQueue(); + } + } } // We're about to start loading a level, so start recording errors to display at the end. From d5f7bc7c9beeaeceac4c01ed2e9c86c943978162 Mon Sep 17 00:00:00 2001 From: lsemp3d <58790905+lsemp3d@users.noreply.github.com> Date: Fri, 21 Jan 2022 10:03:02 -0800 Subject: [PATCH 071/136] Consolidated navigation to file code Signed-off-by: lsemp3d <58790905+lsemp3d@users.noreply.github.com> --- .../ScriptCanvasNodePaletteDockWidget.cpp | 43 ++++++++----------- .../ScriptCanvasNodePaletteDockWidget.h | 1 + 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp index 4b622bc025..9387b58c71 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.cpp @@ -881,6 +881,23 @@ namespace ScriptCanvasEditor return ""; } + void NodePaletteDockWidget::NavigateToTranslationFile(GraphCanvas::NodePaletteTreeItem* nodePaletteItem) + { + if (nodePaletteItem) + { + AZ::IO::Path gemPath = GetGemPath("ScriptCanvas.Editor"); + gemPath = gemPath / AZ::IO::Path("TranslationAssets"); + gemPath = gemPath / nodePaletteItem->GetTranslationDataPath(); + gemPath.ReplaceExtension(".names"); + + AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); + if (fileIO && fileIO->Exists(gemPath.c_str())) + { + AzQtComponents::ShowFileOnDesktop(gemPath.c_str()); + } + } + } + void NodePaletteDockWidget::GenerateTranslation() { QModelIndexList indexList = GetTreeView()->selectionModel()->selectedRows(); @@ -897,21 +914,11 @@ namespace ScriptCanvasEditor if (indexList.size() == 1) { - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); QModelIndex sourceIndex = filterModel->mapToSource(indexList[0]); if (sourceIndex.isValid()) { GraphCanvas::NodePaletteTreeItem* nodePaletteItem = static_cast(sourceIndex.internalPointer()); - - AZ::IO::Path gemPath = GetGemPath("ScriptCanvas.Editor"); - gemPath = gemPath / AZ::IO::Path("TranslationAssets"); - gemPath = gemPath / nodePaletteItem->GetTranslationDataPath(); - gemPath.ReplaceExtension(".names"); - - if (fileIO->Exists(gemPath.c_str())) - { - AzQtComponents::ShowFileOnDesktop(gemPath.c_str()); - } + NavigateToTranslationFile(nodePaletteItem); } } } @@ -929,19 +936,7 @@ namespace ScriptCanvasEditor QModelIndex sourceIndex = filterModel->mapToSource(index); GraphCanvas::NodePaletteTreeItem* nodePaletteItem = static_cast(sourceIndex.internalPointer()); - if (nodePaletteItem) - { - AZ::IO::Path gemPath = GetGemPath("ScriptCanvas.Editor"); - gemPath = gemPath / AZ::IO::Path("TranslationAssets"); - gemPath = gemPath / nodePaletteItem->GetTranslationDataPath(); - gemPath.ReplaceExtension(".names"); - - AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); - if (fileIO->Exists(gemPath.c_str())) - { - AzQtComponents::ShowFileOnDesktop(gemPath.c_str()); - } - } + NavigateToTranslationFile(nodePaletteItem); } } } diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h b/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h index 9f5fa0511f..3ee26e3f71 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/ScriptCanvasNodePaletteDockWidget.h @@ -209,6 +209,7 @@ namespace ScriptCanvasEditor void HandleTreeItemDoubleClicked(GraphCanvas::GraphCanvasTreeItem* treeItem); void OpenTranslationData(); void GenerateTranslation(); + void NavigateToTranslationFile(GraphCanvas::NodePaletteTreeItem*); void ConfigureHelper(); void ParseCycleTargets(GraphCanvas::GraphCanvasTreeItem* treeItem); From d918991e273c982ac9d3bb0405453b1471d64d3a Mon Sep 17 00:00:00 2001 From: Mikhail Naumov <82239319+AMZN-mnaumov@users.noreply.github.com> Date: Fri, 21 Jan 2022 12:04:47 -0600 Subject: [PATCH 072/136] Allowing instantiating of prefab without selecting an entity in outliner (#6763) * Allowing instantiating of prefab without selecting an entity in outliner Signed-off-by: Mikhail Naumov * PR feedback Signed-off-by: Mikhail Naumov --- .../AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index bc65b9088b..d61efe0b6d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -341,7 +341,8 @@ namespace AzToolsFramework } // Instantiate Prefab - if (selectedEntities.size() == 1 && !readOnlyEntityInSelection && !onlySelectedEntityIsClosedPrefabContainer) + if (selectedEntities.size() == 0 || + selectedEntities.size() == 1 && !readOnlyEntityInSelection && !onlySelectedEntityIsClosedPrefabContainer) { QAction* instantiateAction = menu->addAction(QObject::tr("Instantiate Prefab...")); instantiateAction->setToolTip(QObject::tr("Instantiates a prefab file in the scene.")); From 05bf066c5afadbfc44d5dfac10bd191e127799d4 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Fri, 21 Jan 2022 10:28:22 -0800 Subject: [PATCH 073/136] Removed commented out py code Signed-off-by: Gene Walters --- .../tests/Multiplayer_SimpleNetworkLevelEntity.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py index aadf12d7e3..4548dff0b8 100644 --- a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py +++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py @@ -61,12 +61,9 @@ def Multiplayer_SimpleNetworkLevelEntity(): ATTEMPTING_INVALID_NETSPAWN_WAIT_TIME_SECONDS = 1.0 # The editor will try to net-spawn its networked level entity before it's even a client. Make sure this doesn't happen. helper.fail_if_log_line_found('NetworkEntityManager', "RequestNetSpawnableInstantiation: Requested spawnable Root.network.spawnable doesn't exist in the NetworkSpawnableLibrary. Please make sure it is a network spawnable", section_tracer.errors, ATTEMPTING_INVALID_NETSPAWN_WAIT_TIME_SECONDS) - # 5) Ensure the script graph attached to the level entity is running on both client and server + # 5) Ensure the script graph attached to the level entity is running on the server SCRIPTGRAPH_ENABLED_WAIT_TIME_SECONDS = 0.25 - # Check Server helper.succeed_if_log_line_found('EditorServer', "Script: SimpleNetworkLevelEntity: On Graph Start", section_tracer.prints, SCRIPTGRAPH_ENABLED_WAIT_TIME_SECONDS) - # Check Editor/Client (Uncomment once script asset preload is working properly LYN-9136) - # helper.succeed_if_log_line_found('Script', "SimpleNetworkLevelEntity: On Graph Start", section_tracer.prints, SCRIPTGRAPH_ENABLED_WAIT_TIME_SECONDS) # Client # Exit game mode From f93a22cdcc0853df6ebfc77b9c912d438be799b3 Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Fri, 21 Jan 2022 11:11:39 -0800 Subject: [PATCH 074/136] EntityReference P1 case udpates Signed-off-by: Scott Murray --- ...omEditorComponents_EntityReferenceAdded.py | 71 +++++++++++++------ 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py index 9dc4869f66..464f2a1892 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py @@ -58,6 +58,9 @@ class Tests: container_reset = ( "EntityIdReferences reset succeeded", "P1: EntityIdReferences reset did not succeed") + entity_reference_component_removed = ( + "Entity Reference component removed from entity", + "P1: Entity Reference component NOT removed from entity") def AtomEditorComponents_EntityReference_AddedToEntity(): @@ -78,13 +81,21 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): 2) Add Entity Reference component to Entity Reference entity. 3) UNDO the entity creation and component addition. 4) REDO the entity creation and component addition. - 5) Enter/Exit game mode. - 6) Test IsHidden. - 7) Test IsVisible. - 8) Delete Entity Reference entity. - 9) UNDO deletion. - 10) REDO deletion. - 11) Look for errors. + 5) 'EntityIdReferences' is a container property + 6) Append item to 'EntityIdReferences' + 7) Add item to 'EntityIdReferences' + 8) Update item in 'EntityIdReferences' + 9) Remove item from 'EntityIdReferences' + 10) Rest the container property then put one entity reference back for further tests + 11) Remove component + 12) Undo component remove + 13) Enter/Exit game mode. + 14) Test IsHidden. + 15) Test IsVisible. + 16) Delete Entity Reference entity. + 17) UNDO deletion. + 18) REDO deletion. + 19) Look for errors. :return: None """ @@ -142,13 +153,13 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): test_2 = EditorEntity.create_editor_entity('test_2') test_3 = EditorEntity.create_editor_entity('test_3') - # is container property + # 5. 'EntityIdReferences' is a container property Report.result( Tests.entity_id_references_is_container, entity_reference_component.is_property_container( AtomComponentProperties.entity_reference('EntityIdReferences'))) - # Append entity reference to container + # 6. Append item to 'EntityIdReferences' entity_reference_component.append_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), test_1.id) Report.result( @@ -156,7 +167,7 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): entity_reference_component.get_container_item( AtomComponentProperties.entity_reference('EntityIdReferences'), 0) == test_1.id) - # Add entity reference to container + # 7. Add item to 'EntityIdReferences' entity_reference_component.add_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), 1, test_1.id) Report.result( @@ -165,7 +176,7 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): AtomComponentProperties.entity_reference('EntityIdReferences')) == 2 ) - # Update entity reference + # 8. Update item in 'EntityIdReferences' entity_reference_component.update_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), 1, test_2.id) Report.result( @@ -173,7 +184,7 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): entity_reference_component.get_container_item( AtomComponentProperties.entity_reference('EntityIdReferences'), 1) == test_2.id) - # Remove entity reference + # 9. Remove item from 'EntityIdReferences' entity_reference_component.append_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), test_3.id) count_before = entity_reference_component.get_container_count( @@ -190,41 +201,57 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): AtomComponentProperties.entity_reference('EntityIdReferences'), 1) == test_3.id)) ) - # Reset + # 10. Rest the container property then put one entity reference back for further tests entity_reference_component.reset_container(AtomComponentProperties.entity_reference('EntityIdReferences')) + general.idle_wait_frames(1) Report.result( Tests.container_reset, entity_reference_component.get_container_count( - AtomComponentProperties.entity_reference('EntityIdReferences')) == 0 - ) + AtomComponentProperties.entity_reference('EntityIdReferences')) == 0) + entity_reference_component.append_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), + test_1.id) - # 5. Enter/Exit game mode. + # 11. Remove component + entity_reference_entity.remove_component(AtomComponentProperties.entity_reference()) + general.idle_wait_frames(1) + Report.result(Tests.entity_reference_component_removed, not entity_reference_entity.has_component( + AtomComponentProperties.entity_reference())) + + # 12. Undo component remove + general.undo() + general.idle_wait_frames(1) + Report.result(Tests.entity_reference_component, entity_reference_entity.has_component( + AtomComponentProperties.entity_reference())) + + # 13. Enter/Exit game mode. TestHelper.enter_game_mode(Tests.enter_game_mode) general.idle_wait_frames(1) TestHelper.exit_game_mode(Tests.exit_game_mode) - # 6. Test IsHidden. + # 14. Test IsHidden. entity_reference_entity.set_visibility_state(False) Report.result(Tests.is_hidden, entity_reference_entity.is_hidden() is True) - # 7. Test IsVisible. + # 15. Test IsVisible. entity_reference_entity.set_visibility_state(True) general.idle_wait_frames(1) Report.result(Tests.is_visible, entity_reference_entity.is_visible() is True) - # 8. Delete Entity Reference entity. + # 16. Delete Entity Reference entity. entity_reference_entity.delete() Report.result(Tests.entity_deleted, not entity_reference_entity.exists()) - # 9. UNDO deletion. + # 17. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, entity_reference_entity.exists()) - # 10. REDO deletion. + # 18. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not entity_reference_entity.exists()) - # 11. Look for errors and asserts. + # 19. Look for errors and asserts. TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) for error_info in error_tracer.errors: Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") From 42b7f21689e99298df71c1591162509be73994ca Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Fri, 21 Jan 2022 11:55:02 -0800 Subject: [PATCH 075/136] Fixed a place where GetFullName was still being used. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../Code/Source/Material/EditorMaterialComponentUtil.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index f46876fdfb..d4dd4f3a0e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -134,7 +134,7 @@ namespace AZ propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second); } - if (!AtomToolsFramework::ConvertToExportFormat(path, propertyId.GetFullName(), propertyDefinition, propertyValue)) + if (!AtomToolsFramework::ConvertToExportFormat(path, propertyId, propertyDefinition, propertyValue)) { AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str()); result = false; From 2c33240b72f22494c4361157b7ac6a1c39aeb323 Mon Sep 17 00:00:00 2001 From: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> Date: Fri, 21 Jan 2022 13:55:19 -0600 Subject: [PATCH 076/136] Converting Dynamic Vegetation and Gradient Signal tests to utilize prefab system (#7034) * Adding on-disk prefabs for automated tests Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> * Resolving import conflict with cherrypick Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> * Updating DynVeg tests to use open_base_level function Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> * Converting initial set of DynVeg tests to utilize prefab system Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> * Finalizing DynVeg test conversion to use prefab system Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> * Removing old test runners Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> * Removing optimized suffix from optimized test runners Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> * Removing unoptimized test runner Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> * Removing optimized suffix from optimized test runner Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> * Adding wait_for_condition on level save for E2E tests Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com> --- AutomatedTesting/Assets/Prefabs/Bush.prefab | 129 + .../Assets/Prefabs/BushFlowerBlender.prefab | 2249 +++++++++++++++++ .../Assets/Prefabs/PurpleFlower.prefab | 129 + .../flower_pink.vegdescriptorlist | 6 +- .../hydra_editor_utils.py | 2 +- .../PythonTests/largeworlds/CMakeLists.txt | 6 +- ...rides_InstancesPlantAtSpecifiedAltitude.py | 10 +- .../AltitudeFilter_FilterStageToggle.py | 9 +- ...ample_InstancesPlantAtSpecifiedAltitude.py | 7 +- ...binedDescriptorsExpressInConfiguredArea.py | 44 +- ...tSelector_InstancesExpressBasedOnWeight.py | 12 +- ...errides_InstancesPlantAtSpecifiedRadius.py | 11 +- ...nFilter_InstancesPlantAtSpecifiedRadius.py | 11 +- .../DynVegUtils_TempPrefabCreationWorks.py | 10 +- ...nstanceSpawner_DynamicSliceSpawnerWorks.py | 3 +- .../EmptyInstanceSpawner_EmptySpawnerWorks.py | 3 +- ...anceSpawnerPriority_LayerAndSubPriority.py | 10 +- .../EditorScripts/LayerBlender_E2E_Editor.py | 31 +- ...locker_InstancesBlockedInConfiguredArea.py | 11 +- .../LayerSpawner_FilterStageToggle.py | 9 +- .../LayerSpawner_InheritBehaviorFlag.py | 25 +- ...wner_InstancesPlantInAllSupportedShapes.py | 12 +- ...tancesRefreshUsingCorrectViewportCamera.py | 15 +- .../MeshBlocker_InstancesBlockedByMesh.py | 12 +- ...cker_InstancesBlockedByMeshHeightTuning.py | 12 +- ...faceTagEmitter_DependentOnMeshComponent.py | 3 +- ...mitter_SurfaceTagsAddRemoveSuccessfully.py | 3 +- ...ysXColliderSurfaceTagEmitter_E2E_Editor.py | 9 +- ...PositionModifier_AutoSnapToSurfaceWorks.py | 10 +- ...rrides_InstancesPlantAtSpecifiedOffsets.py | 9 +- ... => PrefabInstanceSpawner_Embedded_E2E.py} | 16 +- ... => PrefabInstanceSpawner_External_E2E.py} | 7 +- ...ierOverrides_InstancesRotateWithinRange.py | 9 +- ...tionModifier_InstancesRotateWithinRange.py | 9 +- ...odifierOverrides_InstancesProperlyScale.py | 9 +- .../ScaleModifier_InstancesProperlyScale.py | 10 +- ...apeIntersectionFilter_FilterStageToggle.py | 9 +- ...ionFilter_InstancesPlantInAssignedShape.py | 10 +- ...ifierOverrides_InstanceSurfaceAlignment.py | 9 +- ...gnmentModifier_InstanceSurfaceAlignment.py | 9 +- ...AndOverrides_InstancesPlantOnValidSlope.py | 9 +- ...PrefabCreationAndVisibilityToggleWorks.py} | 79 +- .../SurfaceDataRefreshes_RemainsStable.py | 5 +- ...tipleDescriptorOverridesPlantAsExpected.py | 10 +- ...rfaceMaskFilter_BasicSurfaceTagCreation.py | 6 +- .../SurfaceMaskFilter_ExclusionList.py | 12 +- .../SurfaceMaskFilter_InclusionList.py | 12 +- .../SystemSettings_SectorPointDensity.py | 9 +- .../SystemSettings_SectorSize.py | 9 +- ...getationInstances_DespawnWhenOutOfRange.py | 10 +- .../largeworlds/dyn_veg/TestSuite_Main.py | 166 +- .../dyn_veg/TestSuite_Main_Optimized.py | 192 -- .../largeworlds/dyn_veg/TestSuite_Periodic.py | 270 +- .../dyn_veg/TestSuite_Periodic_Optimized.py | 23 - .../GradientGenerators_Incompatibilities.py | 3 +- .../GradientModifiers_Incompatibilities.py | 3 +- ...ClearingPinnedEntitySetsPreviewToOrigin.py | 3 +- ...eviewSettings_DefaultPinnedEntityIsSelf.py | 3 +- ...GradientReferencesAddRemoveSuccessfully.py | 3 +- ...SurfaceTagEmitter_ComponentDependencies.py | 3 +- ...mitter_SurfaceTagsAddRemoveSuccessfully.py | 3 +- ...ponentIncompatibleWithExpectedGradients.py | 3 +- ...sform_ComponentIncompatibleWithSpawners.py | 3 +- ..._FrequencyZoomCanBeSetBeyondSliderRange.py | 3 +- .../GradientTransform_RequiresShape.py | 3 +- ...ient_ProcessedImageAssignedSuccessfully.py | 3 +- .../ImageGradient_RequiresShape.py | 3 +- .../gradient_signal/TestSuite_Periodic.py | 64 +- .../TestSuite_Periodic_Optimized.py | 57 - .../editor_dynveg_test_helper.py | 45 +- .../instance_counter.scriptcanvas | 39 +- 71 files changed, 3049 insertions(+), 916 deletions(-) create mode 100644 AutomatedTesting/Assets/Prefabs/Bush.prefab create mode 100644 AutomatedTesting/Assets/Prefabs/BushFlowerBlender.prefab create mode 100644 AutomatedTesting/Assets/Prefabs/PurpleFlower.prefab rename AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/{DynamicSliceInstanceSpawner_Embedded_E2E.py => PrefabInstanceSpawner_Embedded_E2E.py} (87%) rename AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/{DynamicSliceInstanceSpawner_External_E2E.py => PrefabInstanceSpawner_External_E2E.py} (96%) rename AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/{SpawnerSlices_SliceCreationAndVisibilityToggleWorks.py => SpawnerPrefabs_PrefabCreationAndVisibilityToggleWorks.py} (52%) delete mode 100644 AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main_Optimized.py delete mode 100644 AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Periodic_Optimized.py delete mode 100644 AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic_Optimized.py diff --git a/AutomatedTesting/Assets/Prefabs/Bush.prefab b/AutomatedTesting/Assets/Prefabs/Bush.prefab new file mode 100644 index 0000000000..ef497bdcd0 --- /dev/null +++ b/AutomatedTesting/Assets/Prefabs/Bush.prefab @@ -0,0 +1,129 @@ +{ + "ContainerEntity": { + "Id": "ContainerEntity", + "Name": "Bush", + "Components": { + "Component_[1140272189295067758]": { + "$type": "EditorInspectorComponent", + "Id": 1140272189295067758 + }, + "Component_[13437832196484687256]": { + "$type": "EditorOnlyEntityComponent", + "Id": 13437832196484687256 + }, + "Component_[1553903646452669645]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 1553903646452669645 + }, + "Component_[15914009348632444632]": { + "$type": "EditorEntitySortComponent", + "Id": 15914009348632444632, + "Child Entity Order": [ + "Entity_[7511491868318]" + ] + }, + "Component_[18046340308818780248]": { + "$type": "EditorPrefabComponent", + "Id": 18046340308818780248 + }, + "Component_[1948833233489872938]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 1948833233489872938, + "Parent Entity": "" + }, + "Component_[2903632350157981339]": { + "$type": "SelectionComponent", + "Id": 2903632350157981339 + }, + "Component_[48827510535192710]": { + "$type": "EditorPendingCompositionComponent", + "Id": 48827510535192710 + }, + "Component_[5609536793322429681]": { + "$type": "EditorLockComponent", + "Id": 5609536793322429681 + }, + "Component_[5859168386298620990]": { + "$type": "EditorEntityIconComponent", + "Id": 5859168386298620990 + }, + "Component_[6604616929271524505]": { + "$type": "EditorVisibilityComponent", + "Id": 6604616929271524505 + } + } + }, + "Entities": { + "Entity_[7511491868318]": { + "Id": "Entity_[7511491868318]", + "Name": "Bush", + "Components": { + "Component_[10227459330338484901]": { + "$type": "EditorInspectorComponent", + "Id": 10227459330338484901, + "ComponentOrderEntryArray": [ + { + "ComponentId": 4998941225335869157 + }, + { + "ComponentId": 9922994635792843826, + "SortIndex": 1 + } + ] + }, + "Component_[10972351222359420947]": { + "$type": "EditorOnlyEntityComponent", + "Id": 10972351222359420947 + }, + "Component_[12101122374155214392]": { + "$type": "EditorPendingCompositionComponent", + "Id": 12101122374155214392 + }, + "Component_[1535264614652988260]": { + "$type": "SelectionComponent", + "Id": 1535264614652988260 + }, + "Component_[16367811417907891218]": { + "$type": "EditorVisibilityComponent", + "Id": 16367811417907891218 + }, + "Component_[17044216787716682880]": { + "$type": "EditorEntitySortComponent", + "Id": 17044216787716682880 + }, + "Component_[2129822594969629430]": { + "$type": "EditorEntityIconComponent", + "Id": 2129822594969629430 + }, + "Component_[2838015156782745450]": { + "$type": "EditorLockComponent", + "Id": 2838015156782745450 + }, + "Component_[4998941225335869157]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 4998941225335869157, + "Parent Entity": "ContainerEntity" + }, + "Component_[8773358049076362578]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 8773358049076362578 + }, + "Component_[9922994635792843826]": { + "$type": "AZ::Render::EditorMeshComponent", + "Id": 9922994635792843826, + "Controller": { + "Configuration": { + "ModelAsset": { + "assetId": { + "guid": "{1201406D-FB20-5B5F-B9B5-6A6E8DE00A14}", + "subId": 276506120 + }, + "assetHint": "assets/objects/foliage/bush_privet_01.azmodel" + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/AutomatedTesting/Assets/Prefabs/BushFlowerBlender.prefab b/AutomatedTesting/Assets/Prefabs/BushFlowerBlender.prefab new file mode 100644 index 0000000000..b938701b6a --- /dev/null +++ b/AutomatedTesting/Assets/Prefabs/BushFlowerBlender.prefab @@ -0,0 +1,2249 @@ +{ + "ContainerEntity": { + "Id": "ContainerEntity", + "Name": "BushFlowerBlender", + "Components": { + "Component_[10351434005293588180]": { + "$type": "EditorLockComponent", + "Id": 10351434005293588180 + }, + "Component_[10967554916960846519]": { + "$type": "EditorOnlyEntityComponent", + "Id": 10967554916960846519 + }, + "Component_[14400678265986305456]": { + "$type": "EditorEntityIconComponent", + "Id": 14400678265986305456 + }, + "Component_[15365520792759708998]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 15365520792759708998 + }, + "Component_[16281192066639198814]": { + "$type": "EditorEntitySortComponent", + "Id": 16281192066639198814, + "Child Entity Order": [ + "Entity_[263598916892318]" + ] + }, + "Component_[16356049875968660722]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 16356049875968660722, + "Parent Entity": "" + }, + "Component_[16391695178646515457]": { + "$type": "SelectionComponent", + "Id": 16391695178646515457 + }, + "Component_[16407238476365087382]": { + "$type": "EditorVisibilityComponent", + "Id": 16407238476365087382 + }, + "Component_[3542701736829700396]": { + "$type": "EditorPendingCompositionComponent", + "Id": 3542701736829700396 + }, + "Component_[5160094530340900971]": { + "$type": "EditorInspectorComponent", + "Id": 5160094530340900971 + }, + "Component_[6432428663776737136]": { + "$type": "EditorPrefabComponent", + "Id": 6432428663776737136 + } + } + }, + "Entities": { + "Entity_[263573147088542]": { + "Id": "Entity_[263573147088542]", + "Name": "BushSpawner", + "Components": { + "Component_[11886309121583108836]": { + "$type": "EditorPositionModifierComponent", + "Id": 11886309121583108836, + "Configuration": { + "GradientX": { + "GradientId": "Entity_[263590326957726]" + }, + "GradientY": { + "GradientId": "Entity_[263590326957726]" + }, + "GradientZ": { + "GradientId": "" + } + } + }, + "Component_[1240444912193942742]": { + "$type": "{DD96FD51-A86B-48BC-A6AB-89183B538269} EditorSpawnerComponent", + "Id": 1240444912193942742, + "PreviewEntity": "Entity_[263573147088542]" + }, + "Component_[12813702285187817973]": { + "$type": "EditorInspectorComponent", + "Id": 12813702285187817973, + "ComponentOrderEntryArray": [ + { + "ComponentId": 18133156195370267728 + }, + { + "ComponentId": 13450250419263773680, + "SortIndex": 1 + }, + { + "ComponentId": 8841963751527151666, + "SortIndex": 2 + }, + { + "ComponentId": 1240444912193942742, + "SortIndex": 3 + }, + { + "ComponentId": 17991239182321715249, + "SortIndex": 4 + }, + { + "ComponentId": 14175761523159824993, + "SortIndex": 5 + }, + { + "ComponentId": 2884829698060689565, + "SortIndex": 6 + }, + { + "ComponentId": 11886309121583108836, + "SortIndex": 7 + } + ] + }, + "Component_[13179606361687972691]": { + "$type": "EditorEntityIconComponent", + "Id": 13179606361687972691 + }, + "Component_[13450250419263773680]": { + "$type": "EditorReferenceShapeComponent", + "Id": 13450250419263773680, + "Configuration": { + "ShapeEntityId": "Entity_[263607506826910]" + } + }, + "Component_[13688014277574607552]": { + "$type": "EditorOnlyEntityComponent", + "Id": 13688014277574607552 + }, + "Component_[14175761523159824993]": { + "$type": "EditorDistributionFilterComponent", + "Id": 14175761523159824993, + "Configuration": { + "ThresholdMin": 0.289000004529953, + "ThresholdMax": 0.5690000057220459, + "Gradient": { + "GradientId": "Entity_[263603211859614]" + } + } + }, + "Component_[14232774271081092639]": { + "$type": "EditorLockComponent", + "Id": 14232774271081092639 + }, + "Component_[14811533745267383811]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 14811533745267383811 + }, + "Component_[17540078415915694273]": { + "$type": "EditorVisibilityComponent", + "Id": 17540078415915694273 + }, + "Component_[17991239182321715249]": { + "$type": "EditorRotationModifierComponent", + "Id": 17991239182321715249, + "Configuration": { + "GradientX": { + "GradientId": "" + }, + "GradientY": { + "GradientId": "" + }, + "GradientZ": { + "GradientId": "Entity_[263590326957726]" + } + } + }, + "Component_[18133156195370267728]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 18133156195370267728, + "Parent Entity": "Entity_[263607506826910]" + }, + "Component_[2884829698060689565]": { + "$type": "EditorScaleModifierComponent", + "Id": 2884829698060689565, + "Configuration": { + "RangeMin": 0.75, + "RangeMax": 1.25, + "Gradient": { + "GradientId": "Entity_[263590326957726]" + } + } + }, + "Component_[50628676751372416]": { + "$type": "EditorEntitySortComponent", + "Id": 50628676751372416, + "Child Entity Order": [ + "Entity_[263603211859614]", + "Entity_[263590326957726]" + ] + }, + "Component_[5689270312836823309]": { + "$type": "SelectionComponent", + "Id": 5689270312836823309 + }, + "Component_[7105803915999711758]": { + "$type": "EditorPendingCompositionComponent", + "Id": 7105803915999711758 + }, + "Component_[8841963751527151666]": { + "$type": "EditorDescriptorListComponent", + "Id": 8841963751527151666, + "Configuration": { + "Descriptors": [ + { + "SpawnerType": "{74BEEDB5-81CF-409F-B375-0D93D81EF2E3}", + "InstanceSpawner": { + "$type": "PrefabInstanceSpawner", + "SpawnableAsset": { + "assetId": { + "guid": "{EE51E73C-D753-54AC-A1C0-4F29844FB6C3}", + "subId": 2740536329 + }, + "assetHint": "assets/prefabs/bush.spawnable" + } + } + } + ] + } + } + } + }, + "Entity_[263577442055838]": { + "Id": "Entity_[263577442055838]", + "Name": "RandomNoise", + "Components": { + "Component_[13412023990029767074]": { + "$type": "EditorRandomGradientComponent", + "Id": 13412023990029767074, + "PreviewEntity": "Entity_[263577442055838]" + }, + "Component_[14048059127502350032]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 14048059127502350032, + "Parent Entity": "Entity_[263581737023134]" + }, + "Component_[15585968636846328006]": { + "$type": "EditorEntitySortComponent", + "Id": 15585968636846328006 + }, + "Component_[17356242264256499333]": { + "$type": "EditorOnlyEntityComponent", + "Id": 17356242264256499333 + }, + "Component_[2157320692130316849]": { + "$type": "EditorLockComponent", + "Id": 2157320692130316849 + }, + "Component_[2167582872687341084]": { + "$type": "EditorReferenceShapeComponent", + "Id": 2167582872687341084, + "Configuration": { + "ShapeEntityId": "Entity_[263607506826910]" + } + }, + "Component_[2794166072748175035]": { + "$type": "SelectionComponent", + "Id": 2794166072748175035 + }, + "Component_[4784966656524567789]": { + "$type": "EditorVisibilityComponent", + "Id": 4784966656524567789 + }, + "Component_[6185400249317227261]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 6185400249317227261 + }, + "Component_[639949486729001685]": { + "$type": "EditorGradientTransformComponent", + "Id": 639949486729001685, + "Configuration": { + "ShapeReference": "", + "Bounds": [ + 50.0, + 50.0, + 1.0 + ] + } + }, + "Component_[7347819195697153472]": { + "$type": "EditorEntityIconComponent", + "Id": 7347819195697153472 + }, + "Component_[9225409585951117678]": { + "$type": "EditorInspectorComponent", + "Id": 9225409585951117678, + "ComponentOrderEntryArray": [ + { + "ComponentId": 14048059127502350032 + }, + { + "ComponentId": 2167582872687341084, + "SortIndex": 1 + }, + { + "ComponentId": 639949486729001685, + "SortIndex": 2 + }, + { + "ComponentId": 13412023990029767074, + "SortIndex": 3 + } + ] + }, + "Component_[9667056664436803603]": { + "$type": "EditorPendingCompositionComponent", + "Id": 9667056664436803603 + } + } + }, + "Entity_[263581737023134]": { + "Id": "Entity_[263581737023134]", + "Name": "FlowerSpawner", + "Components": { + "Component_[10064436441176637741]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 10064436441176637741 + }, + "Component_[10418076448308581948]": { + "$type": "EditorRotationModifierComponent", + "Id": 10418076448308581948, + "Configuration": { + "GradientX": { + "GradientId": "" + }, + "GradientY": { + "GradientId": "" + }, + "GradientZ": { + "GradientId": "Entity_[263577442055838]" + } + } + }, + "Component_[12484622175138429315]": { + "$type": "EditorOnlyEntityComponent", + "Id": 12484622175138429315 + }, + "Component_[12590590072231203407]": { + "$type": "EditorLockComponent", + "Id": 12590590072231203407 + }, + "Component_[13079591667184987458]": { + "$type": "EditorScaleModifierComponent", + "Id": 13079591667184987458, + "Configuration": { + "RangeMin": 0.75, + "RangeMax": 1.25, + "Gradient": { + "GradientId": "Entity_[263577442055838]" + } + } + }, + "Component_[13174773394274524631]": { + "$type": "EditorInspectorComponent", + "Id": 13174773394274524631, + "ComponentOrderEntryArray": [ + { + "ComponentId": 1915862229814997128 + }, + { + "ComponentId": 582800388831726963, + "SortIndex": 1 + }, + { + "ComponentId": 18006385801184712266, + "SortIndex": 2 + }, + { + "ComponentId": 6902499453501456890, + "SortIndex": 3 + }, + { + "ComponentId": 10418076448308581948, + "SortIndex": 4 + }, + { + "ComponentId": 13983302912005698250, + "SortIndex": 5 + }, + { + "ComponentId": 13079591667184987458, + "SortIndex": 6 + }, + { + "ComponentId": 7912787520673119502, + "SortIndex": 7 + } + ] + }, + "Component_[13200009872392504010]": { + "$type": "EditorEntitySortComponent", + "Id": 13200009872392504010, + "Child Entity Order": [ + "Entity_[263594621925022]", + "Entity_[263577442055838]" + ] + }, + "Component_[13983302912005698250]": { + "$type": "EditorDistributionFilterComponent", + "Id": 13983302912005698250, + "Configuration": { + "ThresholdMin": 0.2879999876022339, + "ThresholdMax": 0.5680000185966492, + "Gradient": { + "GradientId": "Entity_[263586031990430]" + } + } + }, + "Component_[14726174657215669218]": { + "$type": "EditorPendingCompositionComponent", + "Id": 14726174657215669218 + }, + "Component_[18006385801184712266]": { + "$type": "EditorDescriptorListComponent", + "Id": 18006385801184712266, + "Configuration": { + "Descriptors": [ + { + "SpawnerType": "{74BEEDB5-81CF-409F-B375-0D93D81EF2E3}", + "InstanceSpawner": { + "$type": "PrefabInstanceSpawner", + "SpawnableAsset": { + "assetId": { + "guid": "{80C0CF4E-9A5E-544B-B89E-BC980175A259}", + "subId": 3875079122 + }, + "assetHint": "assets/prefabs/pinkflower.spawnable" + } + } + }, + { + "SpawnerType": "{74BEEDB5-81CF-409F-B375-0D93D81EF2E3}", + "InstanceSpawner": { + "$type": "PrefabInstanceSpawner", + "SpawnableAsset": { + "assetId": { + "guid": "{20DD1202-A434-5482-9FB9-AED4C78F6CBF}", + "subId": 2669863854 + }, + "assetHint": "assets/prefabs/purpleflower.spawnable" + } + } + }, + { + "SpawnerType": "{23C40FD4-A55F-4BD3-BE5B-DC5423F217C2}", + "InstanceSpawner": { + "$type": "EmptyInstanceSpawner" + } + } + ] + } + }, + "Component_[1915862229814997128]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 1915862229814997128, + "Parent Entity": "Entity_[263607506826910]" + }, + "Component_[2123416208548010747]": { + "$type": "SelectionComponent", + "Id": 2123416208548010747 + }, + "Component_[4172073657954183661]": { + "$type": "EditorVisibilityComponent", + "Id": 4172073657954183661 + }, + "Component_[4297556504463195307]": { + "$type": "EditorEntityIconComponent", + "Id": 4297556504463195307 + }, + "Component_[582800388831726963]": { + "$type": "EditorReferenceShapeComponent", + "Id": 582800388831726963, + "Configuration": { + "ShapeEntityId": "Entity_[263607506826910]" + } + }, + "Component_[6902499453501456890]": { + "$type": "{DD96FD51-A86B-48BC-A6AB-89183B538269} EditorSpawnerComponent", + "Id": 6902499453501456890, + "PreviewEntity": "Entity_[263581737023134]" + }, + "Component_[7912787520673119502]": { + "$type": "EditorPositionModifierComponent", + "Id": 7912787520673119502, + "Configuration": { + "GradientX": { + "GradientId": "Entity_[263577442055838]" + }, + "GradientY": { + "GradientId": "Entity_[263577442055838]" + }, + "GradientZ": { + "GradientId": "" + } + } + } + } + }, + "Entity_[263586031990430]": { + "Id": "Entity_[263586031990430]", + "Name": "Invert", + "Components": { + "Component_[11123278080744920525]": { + "$type": "EditorEntitySortComponent", + "Id": 11123278080744920525 + }, + "Component_[1199715693160400161]": { + "$type": "EditorInspectorComponent", + "Id": 1199715693160400161, + "ComponentOrderEntryArray": [ + { + "ComponentId": 7438979211266329827 + }, + { + "ComponentId": 6027557066164356793, + "SortIndex": 1 + }, + { + "ComponentId": 8903771095804438921, + "SortIndex": 2 + } + ] + }, + "Component_[12162816428693886169]": { + "$type": "EditorEntityIconComponent", + "Id": 12162816428693886169 + }, + "Component_[14493180089799969074]": { + "$type": "EditorVisibilityComponent", + "Id": 14493180089799969074 + }, + "Component_[16206759293595766479]": { + "$type": "EditorPendingCompositionComponent", + "Id": 16206759293595766479 + }, + "Component_[17566144032052847628]": { + "$type": "SelectionComponent", + "Id": 17566144032052847628 + }, + "Component_[17784057508127919200]": { + "$type": "EditorLockComponent", + "Id": 17784057508127919200 + }, + "Component_[18377773171420051348]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 18377773171420051348 + }, + "Component_[6027557066164356793]": { + "$type": "EditorReferenceShapeComponent", + "Id": 6027557066164356793, + "Configuration": { + "ShapeEntityId": "Entity_[263607506826910]" + } + }, + "Component_[7438979211266329827]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 7438979211266329827, + "Parent Entity": "Entity_[263594621925022]" + }, + "Component_[8421650081106982664]": { + "$type": "EditorOnlyEntityComponent", + "Id": 8421650081106982664 + }, + "Component_[8903771095804438921]": { + "$type": "EditorInvertGradientComponent", + "Id": 8903771095804438921, + "Configuration": { + "Gradient": { + "GradientId": "Entity_[263594621925022]" + } + }, + "PreviewEntity": "Entity_[263586031990430]" + } + } + }, + "Entity_[263590326957726]": { + "Id": "Entity_[263590326957726]", + "Name": "RandomNoise", + "Components": { + "Component_[10420548607186596407]": { + "$type": "SelectionComponent", + "Id": 10420548607186596407 + }, + "Component_[11351507264577024072]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 11351507264577024072, + "Parent Entity": "Entity_[263573147088542]" + }, + "Component_[11576941520191560445]": { + "$type": "EditorEntityIconComponent", + "Id": 11576941520191560445 + }, + "Component_[11787535428542045683]": { + "$type": "EditorPendingCompositionComponent", + "Id": 11787535428542045683 + }, + "Component_[11946132649485953311]": { + "$type": "EditorEntitySortComponent", + "Id": 11946132649485953311 + }, + "Component_[11970417753234451570]": { + "$type": "EditorOnlyEntityComponent", + "Id": 11970417753234451570 + }, + "Component_[13743879269876214143]": { + "$type": "EditorVisibilityComponent", + "Id": 13743879269876214143 + }, + "Component_[15614946697365576378]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 15614946697365576378 + }, + "Component_[17045174842161759045]": { + "$type": "EditorLockComponent", + "Id": 17045174842161759045 + }, + "Component_[3107716031616536910]": { + "$type": "EditorInspectorComponent", + "Id": 3107716031616536910, + "ComponentOrderEntryArray": [ + { + "ComponentId": 11351507264577024072 + }, + { + "ComponentId": 6316453818295975755, + "SortIndex": 1 + }, + { + "ComponentId": 4846745402056100407, + "SortIndex": 2 + }, + { + "ComponentId": 8967153379180885152, + "SortIndex": 3 + } + ] + }, + "Component_[4846745402056100407]": { + "$type": "EditorGradientTransformComponent", + "Id": 4846745402056100407, + "Configuration": { + "ShapeReference": "", + "Bounds": [ + 50.0, + 50.0, + 1.0 + ] + } + }, + "Component_[6316453818295975755]": { + "$type": "EditorReferenceShapeComponent", + "Id": 6316453818295975755, + "Configuration": { + "ShapeEntityId": "Entity_[263573147088542]" + } + }, + "Component_[8967153379180885152]": { + "$type": "EditorRandomGradientComponent", + "Id": 8967153379180885152, + "PreviewEntity": "Entity_[263590326957726]" + } + } + }, + "Entity_[263594621925022]": { + "Id": "Entity_[263594621925022]", + "Name": "PerlinNoise", + "Components": { + "Component_[15798567753940523121]": { + "$type": "EditorPerlinGradientComponent", + "Id": 15798567753940523121, + "Configuration": { + "randomSeed": 33, + "frequency": 0.25 + }, + "PreviewEntity": "Entity_[263594621925022]" + }, + "Component_[16035848776632936419]": { + "$type": "EditorPendingCompositionComponent", + "Id": 16035848776632936419 + }, + "Component_[16434108759160050253]": { + "$type": "EditorVisibilityComponent", + "Id": 16434108759160050253 + }, + "Component_[16805003046507210760]": { + "$type": "EditorReferenceShapeComponent", + "Id": 16805003046507210760, + "Configuration": { + "ShapeEntityId": "Entity_[263607506826910]" + } + }, + "Component_[17679463569742913027]": { + "$type": "EditorOnlyEntityComponent", + "Id": 17679463569742913027 + }, + "Component_[18285870860955961523]": { + "$type": "SelectionComponent", + "Id": 18285870860955961523 + }, + "Component_[2330427084045350198]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 2330427084045350198 + }, + "Component_[5921906930080711994]": { + "$type": "EditorEntitySortComponent", + "Id": 5921906930080711994, + "Child Entity Order": [ + "Entity_[263586031990430]" + ] + }, + "Component_[764117453152842781]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 764117453152842781, + "Parent Entity": "Entity_[263581737023134]" + }, + "Component_[7701931249281891300]": { + "$type": "EditorEntityIconComponent", + "Id": 7701931249281891300 + }, + "Component_[7967070680905543315]": { + "$type": "EditorInspectorComponent", + "Id": 7967070680905543315, + "ComponentOrderEntryArray": [ + { + "ComponentId": 764117453152842781 + }, + { + "ComponentId": 16805003046507210760, + "SortIndex": 1 + }, + { + "ComponentId": 8029154041194694200, + "SortIndex": 2 + }, + { + "ComponentId": 15798567753940523121, + "SortIndex": 3 + } + ] + }, + "Component_[8029154041194694200]": { + "$type": "EditorGradientTransformComponent", + "Id": 8029154041194694200, + "Configuration": { + "ShapeReference": "", + "Bounds": [ + 50.0, + 50.0, + 1.0 + ] + } + }, + "Component_[8660028910391135744]": { + "$type": "EditorLockComponent", + "Id": 8660028910391135744 + } + } + }, + "Entity_[263598916892318]": { + "Id": "Entity_[263598916892318]", + "Name": "LandscapeCanvas", + "Components": { + "Component_[12967746135199800648]": { + "$type": "EditorVisibilityComponent", + "Id": 12967746135199800648 + }, + "Component_[13081062505162225823]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 13081062505162225823 + }, + "Component_[16021195931295059075]": { + "$type": "EditorPendingCompositionComponent", + "Id": 16021195931295059075 + }, + "Component_[16134261272053586014]": { + "$type": "EditorEntityIconComponent", + "Id": 16134261272053586014 + }, + "Component_[17500735767968801510]": { + "$type": "EditorLandscapeCanvasComponent", + "Id": 17500735767968801510, + "Graph": { + "m_nodes": [ + { + "Key": 1, + "Value": { + "$type": "CylinderShapeNode", + "m_propertySlots": [ + { + "Key": { + "m_name": "EntityName" + }, + "Value": { + "m_value": { + "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", + "Value": "BushFlowerBlender" + } + } + } + ], + "m_vegetationEntityId": "Entity_[263607506826910]", + "m_componentId": 6683290476113150719 + } + }, + { + "Key": 2, + "Value": { + "$type": "RandomNoiseGradientNode", + "m_propertySlots": [ + { + "Key": { + "m_name": "EntityName" + }, + "Value": { + "m_value": { + "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", + "Value": "RandomNoise" + } + } + } + ], + "m_inputDataSlots": [ + { + "Key": { + "m_name": "PreviewBounds" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + } + ], + "m_vegetationEntityId": "Entity_[263590326957726]", + "m_componentId": 8967153379180885152 + } + }, + { + "Key": 3, + "Value": { + "$type": "SpawnerAreaNode", + "m_propertySlots": [ + { + "Key": { + "m_name": "EntityName" + }, + "Value": { + "m_value": { + "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", + "Value": "BushSpawner" + } + } + } + ], + "m_inputDataSlots": [ + { + "Key": { + "m_name": "PlacementBounds" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + } + ], + "m_vegetationEntityId": "Entity_[263573147088542]", + "m_componentId": 1240444912193942742 + } + }, + { + "Key": 4, + "Value": { + "$type": "PerlinNoiseGradientNode", + "m_propertySlots": [ + { + "Key": { + "m_name": "EntityName" + }, + "Value": { + "m_value": { + "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", + "Value": "PerlinNoise" + } + } + } + ], + "m_inputDataSlots": [ + { + "Key": { + "m_name": "PreviewBounds" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + } + ], + "m_vegetationEntityId": "Entity_[263603211859614]", + "m_componentId": 10160640699095155981 + } + }, + { + "Key": 5, + "Value": { + "$type": "RandomNoiseGradientNode", + "m_propertySlots": [ + { + "Key": { + "m_name": "EntityName" + }, + "Value": { + "m_value": { + "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", + "Value": "RandomNoise" + } + } + } + ], + "m_inputDataSlots": [ + { + "Key": { + "m_name": "PreviewBounds" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + } + ], + "m_vegetationEntityId": "Entity_[263577442055838]", + "m_componentId": 13412023990029767074 + } + }, + { + "Key": 6, + "Value": { + "$type": "SpawnerAreaNode", + "m_propertySlots": [ + { + "Key": { + "m_name": "EntityName" + }, + "Value": { + "m_value": { + "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", + "Value": "FlowerSpawner" + } + } + } + ], + "m_inputDataSlots": [ + { + "Key": { + "m_name": "PlacementBounds" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + } + ], + "m_vegetationEntityId": "Entity_[263581737023134]", + "m_componentId": 6902499453501456890 + } + }, + { + "Key": 7, + "Value": { + "$type": "AreaBlenderNode", + "m_propertySlots": [ + { + "Key": { + "m_name": "EntityName" + }, + "Value": { + "m_value": { + "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", + "Value": "BushFlowerBlender" + } + } + } + ], + "m_extendableSlots": { + "InboundArea": [ + { + "m_value": { + "$type": "EntityId", + "Value": "" + } + }, + { + "m_value": { + "$type": "EntityId", + "Value": "" + }, + "m_subId": 1 + } + ] + }, + "m_vegetationEntityId": "Entity_[263607506826910]", + "m_componentId": 7229206794941734410 + } + }, + { + "Key": 8, + "Value": { + "$type": "PerlinNoiseGradientNode", + "m_propertySlots": [ + { + "Key": { + "m_name": "EntityName" + }, + "Value": { + "m_value": { + "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", + "Value": "PerlinNoise" + } + } + } + ], + "m_inputDataSlots": [ + { + "Key": { + "m_name": "PreviewBounds" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + } + ], + "m_vegetationEntityId": "Entity_[263594621925022]", + "m_componentId": 15798567753940523121 + } + }, + { + "Key": 9, + "Value": { + "$type": "InvertGradientModifierNode", + "m_propertySlots": [ + { + "Key": { + "m_name": "EntityName" + }, + "Value": { + "m_value": { + "$type": "{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9} AZStd::string", + "Value": "Invert" + } + } + } + ], + "m_inputDataSlots": [ + { + "Key": { + "m_name": "InboundGradient" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + }, + { + "Key": { + "m_name": "PreviewBounds" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + } + ], + "m_vegetationEntityId": "Entity_[263586031990430]", + "m_componentId": 8903771095804438921 + } + }, + { + "Key": 10, + "Value": { + "$type": "RotationModifierNode", + "m_inputDataSlots": [ + { + "Key": { + "m_name": "InboundGradientX" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + }, + { + "Key": { + "m_name": "InboundGradientY" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + }, + { + "Key": { + "m_name": "InboundGradientZ" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + } + ], + "m_vegetationEntityId": "Entity_[263573147088542]", + "m_componentId": 17991239182321715249 + } + }, + { + "Key": 11, + "Value": { + "$type": "DistributionFilterNode", + "m_inputDataSlots": [ + { + "Key": { + "m_name": "InboundGradient" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + } + ], + "m_vegetationEntityId": "Entity_[263573147088542]", + "m_componentId": 14175761523159824993 + } + }, + { + "Key": 12, + "Value": { + "$type": "ScaleModifierNode", + "m_inputDataSlots": [ + { + "Key": { + "m_name": "InboundGradient" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + } + ], + "m_vegetationEntityId": "Entity_[263573147088542]", + "m_componentId": 2884829698060689565 + } + }, + { + "Key": 13, + "Value": { + "$type": "PositionModifierNode", + "m_inputDataSlots": [ + { + "Key": { + "m_name": "InboundGradientX" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + }, + { + "Key": { + "m_name": "InboundGradientY" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + }, + { + "Key": { + "m_name": "InboundGradientZ" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + } + ], + "m_vegetationEntityId": "Entity_[263573147088542]", + "m_componentId": 11886309121583108836 + } + }, + { + "Key": 14, + "Value": { + "$type": "RotationModifierNode", + "m_inputDataSlots": [ + { + "Key": { + "m_name": "InboundGradientX" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + }, + { + "Key": { + "m_name": "InboundGradientY" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + }, + { + "Key": { + "m_name": "InboundGradientZ" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + } + ], + "m_vegetationEntityId": "Entity_[263581737023134]", + "m_componentId": 10418076448308581948 + } + }, + { + "Key": 15, + "Value": { + "$type": "DistributionFilterNode", + "m_inputDataSlots": [ + { + "Key": { + "m_name": "InboundGradient" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + } + ], + "m_vegetationEntityId": "Entity_[263581737023134]", + "m_componentId": 13983302912005698250 + } + }, + { + "Key": 16, + "Value": { + "$type": "ScaleModifierNode", + "m_inputDataSlots": [ + { + "Key": { + "m_name": "InboundGradient" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + } + ], + "m_vegetationEntityId": "Entity_[263581737023134]", + "m_componentId": 13079591667184987458 + } + }, + { + "Key": 17, + "Value": { + "$type": "PositionModifierNode", + "m_inputDataSlots": [ + { + "Key": { + "m_name": "InboundGradientX" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + }, + { + "Key": { + "m_name": "InboundGradientY" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + }, + { + "Key": { + "m_name": "InboundGradientZ" + }, + "Value": { + "m_value": { + "$type": "EntityId", + "Value": "" + } + } + } + ], + "m_vegetationEntityId": "Entity_[263581737023134]", + "m_componentId": 7912787520673119502 + } + } + ], + "m_connections": [ + { + "m_sourceEndpoint": [ + 8, + { + "m_name": "OutboundGradient" + } + ], + "m_targetEndpoint": [ + 9, + { + "m_name": "InboundGradient" + } + ] + }, + { + "m_sourceEndpoint": [ + 3, + { + "m_name": "OutboundArea" + } + ], + "m_targetEndpoint": [ + 7, + { + "m_name": "InboundArea" + } + ] + }, + { + "m_sourceEndpoint": [ + 6, + { + "m_name": "OutboundArea" + } + ], + "m_targetEndpoint": [ + 7, + { + "m_name": "InboundArea", + "m_subId": 1 + } + ] + }, + { + "m_sourceEndpoint": [ + 1, + { + "m_name": "Bounds" + } + ], + "m_targetEndpoint": [ + 3, + { + "m_name": "PlacementBounds" + } + ] + }, + { + "m_sourceEndpoint": [ + 1, + { + "m_name": "Bounds" + } + ], + "m_targetEndpoint": [ + 6, + { + "m_name": "PlacementBounds" + } + ] + }, + { + "m_sourceEndpoint": [ + 2, + { + "m_name": "OutboundGradient" + } + ], + "m_targetEndpoint": [ + 10, + { + "m_name": "InboundGradientZ" + } + ] + }, + { + "m_sourceEndpoint": [ + 4, + { + "m_name": "OutboundGradient" + } + ], + "m_targetEndpoint": [ + 11, + { + "m_name": "InboundGradient" + } + ] + }, + { + "m_sourceEndpoint": [ + 2, + { + "m_name": "OutboundGradient" + } + ], + "m_targetEndpoint": [ + 12, + { + "m_name": "InboundGradient" + } + ] + }, + { + "m_sourceEndpoint": [ + 2, + { + "m_name": "OutboundGradient" + } + ], + "m_targetEndpoint": [ + 13, + { + "m_name": "InboundGradientX" + } + ] + }, + { + "m_sourceEndpoint": [ + 2, + { + "m_name": "OutboundGradient" + } + ], + "m_targetEndpoint": [ + 13, + { + "m_name": "InboundGradientY" + } + ] + }, + { + "m_sourceEndpoint": [ + 5, + { + "m_name": "OutboundGradient" + } + ], + "m_targetEndpoint": [ + 14, + { + "m_name": "InboundGradientZ" + } + ] + }, + { + "m_sourceEndpoint": [ + 9, + { + "m_name": "OutboundGradient" + } + ], + "m_targetEndpoint": [ + 15, + { + "m_name": "InboundGradient" + } + ] + }, + { + "m_sourceEndpoint": [ + 5, + { + "m_name": "OutboundGradient" + } + ], + "m_targetEndpoint": [ + 16, + { + "m_name": "InboundGradient" + } + ] + }, + { + "m_sourceEndpoint": [ + 5, + { + "m_name": "OutboundGradient" + } + ], + "m_targetEndpoint": [ + 17, + { + "m_name": "InboundGradientX" + } + ] + }, + { + "m_sourceEndpoint": [ + 5, + { + "m_name": "OutboundGradient" + } + ], + "m_targetEndpoint": [ + 17, + { + "m_name": "InboundGradientY" + } + ] + } + ], + "m_uiMetadata": { + "m_sceneMetadata": { + "ComponentData": { + "{5F84B500-8C45-40D1-8EFC-A5306B241444}": { + "$type": "SceneComponentSaveData", + "ViewParams": { + "Scale": 0.3771495156249999, + "AnchorX": -498.4760437011719, + "AnchorY": 808.6978149414063 + } + } + } + }, + "m_nodeMetadata": [ + { + "Key": 2, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "GradientNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 100.0, + 580.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{2D583FA2-5659-491F-8914-6302420E3F0B}" + } + } + } + }, + { + "Key": 3, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "VegetationAreaNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 480.0, + 600.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{A26480C4-A80B-4B36-ADE1-918E4541EA2B}" + } + } + } + }, + { + "Key": 5, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "GradientNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 100.0, + 1540.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{6CE9EA8B-85E7-4E17-B1D6-CA97D9D65276}" + } + } + } + }, + { + "Key": 6, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "VegetationAreaNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 480.0, + 1560.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{8FABE49F-1D73-46FE-8616-A982EEE46DDD}" + } + } + } + }, + { + "Key": 7, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "VegetationAreaNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 840.0, + 1580.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{C5EEBC1D-B91B-4852-A41D-425C6FED3FB9}" + } + } + } + }, + { + "Key": 9, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "GradientModifierNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 480.0, + 2060.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{5EB76670-0CBE-4F2A-9AE7-F65709D0BE92}" + } + } + } + }, + { + "Key": 10, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "VegetationAreaNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 6.0, + 147.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{5CB69A73-F7BA-4F76-AB86-F343052C3D7D}" + } + } + } + }, + { + "Key": 11, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "VegetationAreaNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 6.0, + 367.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{235DEBEC-E3F8-43C1-BA7E-41475B834D70}" + } + } + } + }, + { + "Key": 12, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "VegetationAreaNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 6.0, + 288.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{9E56E7B6-2ECE-42F9-9A23-FF7D192209D2}" + } + } + } + }, + { + "Key": 13, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "VegetationAreaNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 6.0, + 6.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{61759FE6-E6F7-4F4B-819B-FBFE125D7389}" + } + } + } + }, + { + "Key": 14, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "VegetationAreaNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 6.0, + 147.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{0AC1C6C8-7CC1-4068-A87D-F4B92AE8FCAF}" + } + } + } + }, + { + "Key": 15, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "VegetationAreaNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 6.0, + 367.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{5D698B90-830F-46FE-ADD8-6164EA098C3E}" + } + } + } + }, + { + "Key": 16, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "VegetationAreaNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 6.0, + 288.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{9DE6DE4A-2E6F-44BA-B292-3CD2215C1D5B}" + } + } + } + }, + { + "Key": 17, + "Value": { + "ComponentData": { + "{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": { + "$type": "NodeSaveData" + }, + "{328FF15C-C302-458F-A43D-E1794DE0904E}": { + "$type": "GeneralNodeTitleComponentSaveData", + "PaletteOverride": "VegetationAreaNodeTitlePalette" + }, + "{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": { + "$type": "GeometrySaveData", + "Position": [ + 6.0, + 6.0 + ] + }, + "{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": { + "$type": "StylingComponentSaveData" + }, + "{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": { + "$type": "PersistentIdComponentSaveData", + "PersistentId": "{57FA822D-629F-4949-A8D7-D675544EBC0A}" + } + } + } + } + ] + }, + "m_nodeWrappings": [ + { + "Key": 10, + "Value": [ + 3, + 1 + ] + }, + { + "Key": 11, + "Value": [ + 3, + 6 + ] + }, + { + "Key": 12, + "Value": [ + 3, + 2 + ] + }, + { + "Key": 13, + "Value": [ + 3, + {} + ] + }, + { + "Key": 14, + "Value": [ + 6, + 1 + ] + }, + { + "Key": 15, + "Value": [ + 6, + 6 + ] + }, + { + "Key": 16, + "Value": [ + 6, + 2 + ] + }, + { + "Key": 17, + "Value": [ + 6, + {} + ] + } + ] + } + }, + "Component_[17574651838531525263]": { + "$type": "EditorEntitySortComponent", + "Id": 17574651838531525263, + "Child Entity Order": [ + "Entity_[263607506826910]" + ] + }, + "Component_[3086205760978540160]": { + "$type": "EditorLockComponent", + "Id": 3086205760978540160 + }, + "Component_[3102230753208284750]": { + "$type": "EditorInspectorComponent", + "Id": 3102230753208284750, + "ComponentOrderEntryArray": [ + { + "ComponentId": 5796173638130327223 + }, + { + "ComponentId": 17500735767968801510, + "SortIndex": 1 + } + ] + }, + "Component_[4695341524212000585]": { + "$type": "EditorOnlyEntityComponent", + "Id": 4695341524212000585 + }, + "Component_[5796173638130327223]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 5796173638130327223, + "Parent Entity": "ContainerEntity" + }, + "Component_[8278362871021770878]": { + "$type": "SelectionComponent", + "Id": 8278362871021770878 + } + } + }, + "Entity_[263603211859614]": { + "Id": "Entity_[263603211859614]", + "Name": "PerlinNoise", + "Components": { + "Component_[10006546776757889020]": { + "$type": "EditorVisibilityComponent", + "Id": 10006546776757889020 + }, + "Component_[10160640699095155981]": { + "$type": "EditorPerlinGradientComponent", + "Id": 10160640699095155981, + "Configuration": { + "randomSeed": 33, + "frequency": 0.25 + }, + "PreviewEntity": "Entity_[263603211859614]" + }, + "Component_[11506183926478566822]": { + "$type": "EditorEntitySortComponent", + "Id": 11506183926478566822 + }, + "Component_[13160180411150366392]": { + "$type": "EditorLockComponent", + "Id": 13160180411150366392 + }, + "Component_[15083697380300161163]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 15083697380300161163 + }, + "Component_[15404456223257061245]": { + "$type": "EditorInspectorComponent", + "Id": 15404456223257061245, + "ComponentOrderEntryArray": [ + { + "ComponentId": 6484803030406851652 + }, + { + "ComponentId": 4912800286535654244, + "SortIndex": 1 + }, + { + "ComponentId": 2395166459126906105, + "SortIndex": 2 + }, + { + "ComponentId": 10160640699095155981, + "SortIndex": 3 + } + ] + }, + "Component_[2395166459126906105]": { + "$type": "EditorGradientTransformComponent", + "Id": 2395166459126906105, + "Configuration": { + "ShapeReference": "", + "Bounds": [ + 50.0, + 50.0, + 1.0 + ] + } + }, + "Component_[4417011400526470160]": { + "$type": "EditorEntityIconComponent", + "Id": 4417011400526470160 + }, + "Component_[4601061670472962302]": { + "$type": "EditorPendingCompositionComponent", + "Id": 4601061670472962302 + }, + "Component_[4912800286535654244]": { + "$type": "EditorReferenceShapeComponent", + "Id": 4912800286535654244, + "Configuration": { + "ShapeEntityId": "Entity_[263607506826910]" + } + }, + "Component_[6233982345083723563]": { + "$type": "SelectionComponent", + "Id": 6233982345083723563 + }, + "Component_[6484803030406851652]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 6484803030406851652, + "Parent Entity": "Entity_[263573147088542]" + }, + "Component_[6813813525871080299]": { + "$type": "EditorOnlyEntityComponent", + "Id": 6813813525871080299 + } + } + }, + "Entity_[263607506826910]": { + "Id": "Entity_[263607506826910]", + "Name": "BushFlowerBlender", + "Components": { + "Component_[13725600808872754587]": { + "$type": "EditorEntityIconComponent", + "Id": 13725600808872754587 + }, + "Component_[15959807606564505710]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 15959807606564505710, + "Parent Entity": "Entity_[263598916892318]" + }, + "Component_[1596826146661515925]": { + "$type": "EditorPendingCompositionComponent", + "Id": 1596826146661515925 + }, + "Component_[4525591661239956058]": { + "$type": "EditorVisibilityComponent", + "Id": 4525591661239956058 + }, + "Component_[6683290476113150719]": { + "$type": "EditorCylinderShapeComponent", + "Id": 6683290476113150719, + "CylinderShape": { + "Configuration": { + "Radius": 25.0 + } + } + }, + "Component_[6879394931668195375]": { + "$type": "EditorEntitySortComponent", + "Id": 6879394931668195375, + "Child Entity Order": [ + "Entity_[263573147088542]", + "Entity_[263581737023134]" + ] + }, + "Component_[7229206794941734410]": { + "$type": "EditorAreaBlenderComponent", + "Id": 7229206794941734410, + "Configuration": { + "Operations": [ + "Entity_[263573147088542]", + "Entity_[263581737023134]" + ] + }, + "PreviewEntity": "Entity_[263607506826910]" + }, + "Component_[8772711204845372843]": { + "$type": "EditorLockComponent", + "Id": 8772711204845372843 + }, + "Component_[8959345022109725835]": { + "$type": "SelectionComponent", + "Id": 8959345022109725835 + }, + "Component_[9094488642973843583]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 9094488642973843583 + }, + "Component_[9112960617967513749]": { + "$type": "EditorInspectorComponent", + "Id": 9112960617967513749, + "ComponentOrderEntryArray": [ + { + "ComponentId": 15959807606564505710 + }, + { + "ComponentId": 7229206794941734410, + "SortIndex": 1 + }, + { + "ComponentId": 6683290476113150719, + "SortIndex": 2 + } + ] + }, + "Component_[9541665258597207652]": { + "$type": "EditorOnlyEntityComponent", + "Id": 9541665258597207652 + } + } + } + } +} \ No newline at end of file diff --git a/AutomatedTesting/Assets/Prefabs/PurpleFlower.prefab b/AutomatedTesting/Assets/Prefabs/PurpleFlower.prefab new file mode 100644 index 0000000000..a8716ec099 --- /dev/null +++ b/AutomatedTesting/Assets/Prefabs/PurpleFlower.prefab @@ -0,0 +1,129 @@ +{ + "ContainerEntity": { + "Id": "ContainerEntity", + "Name": "PurpleFlower", + "Components": { + "Component_[10519928302743666073]": { + "$type": "EditorPrefabComponent", + "Id": 10519928302743666073 + }, + "Component_[13894087802180240181]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 13894087802180240181, + "Parent Entity": "" + }, + "Component_[15788541052719571801]": { + "$type": "EditorEntityIconComponent", + "Id": 15788541052719571801 + }, + "Component_[15842981265136092481]": { + "$type": "SelectionComponent", + "Id": 15842981265136092481 + }, + "Component_[16360384897559021149]": { + "$type": "EditorInspectorComponent", + "Id": 16360384897559021149 + }, + "Component_[16713545675046303279]": { + "$type": "EditorVisibilityComponent", + "Id": 16713545675046303279 + }, + "Component_[1806734194268113785]": { + "$type": "EditorPendingCompositionComponent", + "Id": 1806734194268113785 + }, + "Component_[5392020700593853313]": { + "$type": "EditorEntitySortComponent", + "Id": 5392020700593853313, + "Child Entity Order": [ + "Entity_[14335611090324]" + ] + }, + "Component_[5995854518752659458]": { + "$type": "EditorLockComponent", + "Id": 5995854518752659458 + }, + "Component_[6963022284400845376]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 6963022284400845376 + }, + "Component_[8055275578170091546]": { + "$type": "EditorOnlyEntityComponent", + "Id": 8055275578170091546 + } + } + }, + "Entities": { + "Entity_[14335611090324]": { + "Id": "Entity_[14335611090324]", + "Name": "PurpleFlower", + "Components": { + "Component_[10887353073528055802]": { + "$type": "EditorPendingCompositionComponent", + "Id": 10887353073528055802 + }, + "Component_[12641127425852859189]": { + "$type": "AZ::Render::EditorMeshComponent", + "Id": 12641127425852859189, + "Controller": { + "Configuration": { + "ModelAsset": { + "assetId": { + "guid": "{D493A670-6D82-5AE9-A2C8-A2EB02684F71}", + "subId": 284799939 + }, + "assetHint": "assets/objects/foliage/grass_flower_purple.azmodel" + } + } + } + }, + "Component_[14406733303466080015]": { + "$type": "EditorInspectorComponent", + "Id": 14406733303466080015, + "ComponentOrderEntryArray": [ + { + "ComponentId": 9231452352781000222 + }, + { + "ComponentId": 12641127425852859189, + "SortIndex": 1 + } + ] + }, + "Component_[1452384341905923012]": { + "$type": "EditorLockComponent", + "Id": 1452384341905923012 + }, + "Component_[2215454016415585892]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 2215454016415585892 + }, + "Component_[4104108067383423623]": { + "$type": "EditorVisibilityComponent", + "Id": 4104108067383423623 + }, + "Component_[4197335450471807917]": { + "$type": "SelectionComponent", + "Id": 4197335450471807917 + }, + "Component_[6877680739064997650]": { + "$type": "EditorOnlyEntityComponent", + "Id": 6877680739064997650 + }, + "Component_[7372550507186490390]": { + "$type": "EditorEntityIconComponent", + "Id": 7372550507186490390 + }, + "Component_[7673532337364366244]": { + "$type": "EditorEntitySortComponent", + "Id": 7673532337364366244 + }, + "Component_[9231452352781000222]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 9231452352781000222, + "Parent Entity": "ContainerEntity" + } + } + } + } +} \ No newline at end of file diff --git a/AutomatedTesting/Assets/VegDescriptorLists/flower_pink.vegdescriptorlist b/AutomatedTesting/Assets/VegDescriptorLists/flower_pink.vegdescriptorlist index 372cafbdce..9120d992c7 100644 --- a/AutomatedTesting/Assets/VegDescriptorLists/flower_pink.vegdescriptorlist +++ b/AutomatedTesting/Assets/VegDescriptorLists/flower_pink.vegdescriptorlist @@ -2,11 +2,11 @@ - + - + - + diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/hydra_editor_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/hydra_editor_utils.py index 36fc6003f7..ac74c611a2 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/hydra_editor_utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/hydra_editor_utils.py @@ -5,9 +5,9 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ +import collections.abc from typing import List from math import isclose -import collections.abc import azlmbr.bus as bus import azlmbr.editor as editor diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt index ba607ede32..2e3e72883c 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt @@ -14,7 +14,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ NAME AutomatedTesting::DynamicVegetationTests_Main_Optimized TEST_SERIAL TEST_SUITE main - PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg/TestSuite_Main_Optimized.py + PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg/TestSuite_Main.py RUNTIME_DEPENDENCIES AZ::AssetProcessor Legacy::Editor @@ -27,7 +27,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ NAME AutomatedTesting::DynamicVegetationTests_Periodic_Optimized TEST_SERIAL TEST_SUITE periodic - PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg/TestSuite_Periodic_Optimized.py + PATH ${CMAKE_CURRENT_LIST_DIR}/dyn_veg/TestSuite_Periodic.py RUNTIME_DEPENDENCIES AZ::AssetProcessor Legacy::Editor @@ -58,7 +58,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_ NAME AutomatedTesting::GradientSignalTests_Periodic_Optimized TEST_SERIAL TEST_SUITE periodic - PATH ${CMAKE_CURRENT_LIST_DIR}/gradient_signal/TestSuite_Periodic_Optimized.py + PATH ${CMAKE_CURRENT_LIST_DIR}/gradient_signal/TestSuite_Periodic.py RUNTIME_DEPENDENCIES AZ::AssetProcessor Legacy::Editor diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude.py index 66aa6d27ad..aa5e5e4f9c 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude.py @@ -51,22 +51,18 @@ def AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude(): import os - import azlmbr.asset as asset import azlmbr.editor as editor import azlmbr.legacy.general as general import azlmbr.bus as bus import azlmbr.math as math - import azlmbr.prefab as prefab import editor_python_test_tools.hydra_editor_utils as hydra - from editor_python_test_tools.prefab_utils import Prefab from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg from editor_python_test_tools.utils import Report from editor_python_test_tools.utils import TestHelper as helper # 1) Open an existing simple level - helper.init_idle() - helper.open_level("", "Base") + hydra.open_base_level() # Set view of planting area for visual debugging general.set_current_view_position(512.0, 500.0, 38.0) @@ -76,9 +72,9 @@ def AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude(): center_point = math.Vector3(512.0, 512.0, 32.0) flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") - flower_prefab = dynveg.create_temp_mesh_prefab(flower_asset_path, "PinkFlower")[0] + flower_prefab = dynveg.create_temp_mesh_prefab(flower_asset_path, "AltFilter_PinkFlower")[0] - spawner_entity = dynveg.create_prefab_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, flower_prefab) + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, flower_prefab) # Add a Vegetation Altitude Filter spawner_entity.add_component("Vegetation Altitude Filter") diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_FilterStageToggle.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_FilterStageToggle.py index 06f6c2a7b4..be2c5e4d8c 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_FilterStageToggle.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_FilterStageToggle.py @@ -32,9 +32,7 @@ def AltitudeFilter_FilterStageToggle(): import os import azlmbr.legacy.general as general - import azlmbr.bus as bus import azlmbr.math as math - import azlmbr.prefab as prefab import editor_python_test_tools.hydra_editor_utils as hydra from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg @@ -45,17 +43,16 @@ def AltitudeFilter_FilterStageToggle(): POSTPROCESS_INSTANCE_COUNT = 34 # Open an existing simple level - helper.init_idle() - helper.open_level("", "Base") + hydra.open_base_level() general.set_current_view_position(512.0, 480.0, 38.0) # Create basic vegetation entity position = math.Vector3(512.0, 512.0, 32.0) flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") - flower_prefab = dynveg.create_temp_mesh_prefab(flower_asset_path, "PinkFlower")[0] + flower_prefab = dynveg.create_temp_mesh_prefab(flower_asset_path, "AltFilter_PinkFlower2")[0] - vegetation = dynveg.create_prefab_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, flower_prefab) + vegetation = dynveg.create_temp_prefab_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, flower_prefab) # Add a Vegetation Altitude Filter to the vegetation area entity vegetation.add_component("Vegetation Altitude Filter") diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude.py index 544a58e242..1e9762d7d8 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude.py @@ -56,8 +56,7 @@ def AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude(): from editor_python_test_tools.utils import TestHelper as helper # 1) Open an existing simple level - helper.init_idle() - helper.open_level("", "Base") + hydra.open_base_level() # Set view of planting area for visual debugging general.set_current_view_position(512.0, 500.0, 38.0) @@ -67,9 +66,9 @@ def AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude(): center_point = math.Vector3(512.0, 512.0, 32.0) flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") - flower_prefab = dynveg.create_temp_mesh_prefab(flower_asset_path, "PinkFlower")[0] + flower_prefab = dynveg.create_temp_mesh_prefab(flower_asset_path, "AltFilter_PinkFlower3")[0] - spawner_entity = dynveg.create_prefab_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 16.0, flower_prefab) + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 16.0, flower_prefab) # Add a Vegetation Altitude Filter spawner_entity.add_component("Vegetation Altitude Filter") diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea.py index a856256929..7242b0b629 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea.py @@ -56,19 +56,21 @@ def AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea(): """ import os + from pathlib import Path import azlmbr.bus as bus import azlmbr.editor as editor import azlmbr.legacy.general as general import azlmbr.math as math import azlmbr.vegetation as vegetation + import azlmbr.prefab as prefab import editor_python_test_tools.hydra_editor_utils as hydra from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg from editor_python_test_tools.utils import Report from editor_python_test_tools.utils import TestHelper as helper - def create_asset_list_entity(name, center, dynamic_slice_asset_path): + def create_asset_list_entity(name, center, target_prefab): asset_list_entity = hydra.Entity(name) asset_list_entity.create_entity( center, @@ -77,18 +79,34 @@ def AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea(): if asset_list_entity.id.IsValid(): print(f"'{asset_list_entity.name}' created") - # Set the Asset List to a Dynamic Slice spawner with a specific slice asset selected - dynamic_slice_spawner = vegetation.DynamicSliceInstanceSpawner() - dynamic_slice_spawner.SetSliceAssetPath(dynamic_slice_asset_path) + if target_prefab: + # Get the in-memory spawnable asset id if exists + spawnable_name = Path(target_prefab.file_path).stem + spawnable_asset_id = prefab.PrefabPublicRequestBus(bus.Broadcast, 'GetInMemorySpawnableAssetId', + spawnable_name) + + # Create the in-memory spawnable asset from given prefab if the spawnable does not exist + if not spawnable_asset_id.is_valid(): + create_spawnable_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'CreateInMemorySpawnableAsset', + target_prefab.file_path, + spawnable_name) + assert create_spawnable_result.IsSuccess(), \ + f"Prefab operation 'CreateInMemorySpawnableAssets' failed. Error: {create_spawnable_result.GetError()}" + spawnable_asset_id = create_spawnable_result.GetValue() + else: + spawnable_asset_id = None + + # Set the vegetation area to a prefab instance spawner with a specific prefab asset selected descriptor = hydra.get_component_property_value(asset_list_entity.components[0], - "Configuration|Embedded Assets|[0]") - descriptor.spawner = dynamic_slice_spawner + 'Configuration|Embedded Assets|[0]') + prefab_spawner = vegetation.PrefabInstanceSpawner() + prefab_spawner.SetPrefabAssetId(spawnable_asset_id) + descriptor.spawner = prefab_spawner asset_list_entity.get_set_test(0, "Configuration|Embedded Assets|[0]", descriptor) return asset_list_entity # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Set view of planting area for visual debugging general.set_current_view_position(512.0, 500.0, 38.0) @@ -96,11 +114,13 @@ def AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea(): # 2) Create 3 entities with Vegetation Asset List components set to spawn different descriptors center_point = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - asset_path2 = os.path.join("Slices", "PurpleFlower.dynamicslice") - asset_list_entity = create_asset_list_entity("Asset List 1", center_point, asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "AssetList_PinkFlower")[0] + purple_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + purple_flower_prefab = dynveg.create_temp_mesh_prefab(purple_flower_asset_path, "AssetList_PurpleFlower")[0] + asset_list_entity = create_asset_list_entity("Asset List 1", center_point, pink_flower_prefab) asset_list_entity2 = create_asset_list_entity("Asset List 2", center_point, None) - asset_list_entity3 = create_asset_list_entity("Asset List 3", center_point, asset_path2) + asset_list_entity3 = create_asset_list_entity("Asset List 3", center_point, purple_flower_prefab) # 3) Create a planting surface and add a Vegetation System Settings level component with instances set to spawn # on center instead of corner diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetWeightSelector_InstancesExpressBasedOnWeight.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetWeightSelector_InstancesExpressBasedOnWeight.py index b8b50f8110..8ea0b6b23d 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetWeightSelector_InstancesExpressBasedOnWeight.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/AssetWeightSelector_InstancesExpressBasedOnWeight.py @@ -56,8 +56,7 @@ def AssetWeightSelector_InstancesExpressBasedOnWeight(): from editor_python_test_tools.utils import TestHelper as helper # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Set view of planting area for visual debugging general.set_current_view_position(512.0, 500.0, 38.0) @@ -66,14 +65,15 @@ def AssetWeightSelector_InstancesExpressBasedOnWeight(): # 2) Create a new instance spawner entity with multiple Dynamic Slice Instance Spawner descriptors, one set to a # valid slice entity, and one set to None spawner_center_point = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0, - asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "AssetWeight_PinkFlower")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0, + pink_flower_prefab) desc_asset = hydra.get_component_property_value(spawner_entity.components[2], "Configuration|Embedded Assets")[0] desc_list = [desc_asset, desc_asset] spawner_entity.get_set_test(2, "Configuration|Embedded Assets", desc_list) - spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[1]|Instance|Slice Asset", None) + spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[1]|Instance|Prefab Asset", None) # Add an Asset Weight Selector component to the spawner entity spawner_entity.add_component("Vegetation Asset Weight Selector") diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius.py index ed5501d719..be0fe8dba7 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius.py @@ -64,16 +64,15 @@ def DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius(): instance_query_point_c = math.Vector3(515.0, 512.5, 32.0) # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") - + hydra.open_base_level() general.set_current_view_position(512.0, 480.0, 38.0) # 2) Create a new entity with required vegetation area components spawner_center_point = math.Vector3(520.0, 520.0, 32.0) - asset_path = os.path.join("Slices", "1m_cube.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0, - asset_path) + cube_asset_path = os.path.join("testdata", "multi-mat_fbx", "multi-mat_1m_cube.azmodel") + cube_prefab = dynveg.create_temp_mesh_prefab(cube_asset_path, "DistanceBetween_1m_cube2")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0, + cube_prefab) # 3) Create a surface to plant on surface_center_point = math.Vector3(512.0, 512.0, 32.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius.py index c24ec3c314..b2244fdfa7 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius.py @@ -62,16 +62,15 @@ def DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius(): instance_query_point_c = math.Vector3(515.0, 512.5, 32.0) # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") - + hydra.open_base_level() general.set_current_view_position(512.0, 480.0, 38.0) # 2) Create a new entity with required vegetation area components spawner_center_point = math.Vector3(520.0, 520.0, 32.0) - asset_path = os.path.join("Slices", "1m_cube.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0, - asset_path) + cube_asset_path = os.path.join("testdata", "multi-mat_fbx", "multi-mat_1m_cube.azmodel") + cube_prefab = dynveg.create_temp_mesh_prefab(cube_asset_path, "DistanceBetween_1m_cube")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", spawner_center_point, + 16.0, 16.0, 16.0, cube_prefab) # 3) Create a surface to plant on surface_center_point = math.Vector3(512.0, 512.0, 32.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynVegUtils_TempPrefabCreationWorks.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynVegUtils_TempPrefabCreationWorks.py index d016473d5e..c1ca3cbfc6 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynVegUtils_TempPrefabCreationWorks.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynVegUtils_TempPrefabCreationWorks.py @@ -39,11 +39,11 @@ def DynVegUtils_TempPrefabCreationWorks(): with Tracer() as error_tracer: # Create dictionary for prefab filenames and paths to create using helper function mesh_prefabs = { - "PinkFlower": os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel"), - "PurpleFlower": os.path.join("assets", "objects", "foliage", "grass_flower_purple.azmodel"), - "1m_Cube": os.path.join("objects", "_primitives", "_box_1x1.azmodel"), - "CedarTree": os.path.join("assets", "objects", "foliage", "cedar.azmodel"), - "Bush": os.path.join("assets", "objects", "foliage", "bush_privet_01.azmodel"), + "UtilsTest_PinkFlower": os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel"), + "UtilsTest_PurpleFlower": os.path.join("assets", "objects", "foliage", "grass_flower_purple.azmodel"), + "UtilsTest_1m_Cube": os.path.join("objects", "_primitives", "_box_1x1.azmodel"), + "UtilsTest_CedarTree": os.path.join("assets", "objects", "foliage", "cedar.azmodel"), + "UtilsTest_Bush": os.path.join("assets", "objects", "foliage", "bush_privet_01.azmodel"), } # 1) Open an existing simple level diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks.py index fcbf85c59d..c8581ad275 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks.py @@ -71,8 +71,7 @@ def DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks(): from editor_python_test_tools.utils import TestHelper as helper # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(512.0, 480.0, 38.0) # Grab the UUID that we need for creating an Dynamic Slice Instance Spawner diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/EmptyInstanceSpawner_EmptySpawnerWorks.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/EmptyInstanceSpawner_EmptySpawnerWorks.py index d0a51809b4..91315a6971 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/EmptyInstanceSpawner_EmptySpawnerWorks.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/EmptyInstanceSpawner_EmptySpawnerWorks.py @@ -57,8 +57,7 @@ def EmptyInstanceSpawner_EmptySpawnerWorks(): from editor_python_test_tools.utils import TestHelper as helper # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(512.0, 480.0, 38.0) # Grab the UUID that we need for creating an Empty Spawner diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/InstanceSpawnerPriority_LayerAndSubPriority.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/InstanceSpawnerPriority_LayerAndSubPriority.py index 471c8862fd..f83807a62b 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/InstanceSpawnerPriority_LayerAndSubPriority.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/InstanceSpawnerPriority_LayerAndSubPriority.py @@ -60,8 +60,7 @@ def InstanceSpawnerPriority_LayerAndSubPriority(): from editor_python_test_tools.utils import TestHelper as helper # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Set view of planting area for visual debugging general.set_current_view_position(512.0, 500.0, 38.0) @@ -69,9 +68,10 @@ def InstanceSpawnerPriority_LayerAndSubPriority(): # 2) Create overlapping areas: 1 instance spawner area, and 1 blocker area spawner_center_point = math.Vector3(508.0, 508.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 1.0, - asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "Priority_PinkFlower")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 1.0, + pink_flower_prefab) blocker_center_point = math.Vector3(516.0, 516.0, 32.0) blocker_entity = dynveg.create_blocker_area("Instance Blocker", blocker_center_point, 16.0, 16.0, 1.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py index 6b5a80ee8e..79f2e4169b 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py @@ -85,18 +85,14 @@ def LayerBlender_E2E_Editor(): # 2) Create 2 vegetation areas with different meshes purple_position = math.Vector3(504.0, 512.0, 32.0) - purple_asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice") - spawner_entity_1 = dynveg.create_dynamic_slice_vegetation_area("Purple Spawner", - purple_position, - 16.0, 16.0, 1.0, - purple_asset_path) + purple_flower_prefab_path = os.path.join("assets", "prefabs", "PurpleFlower.spawnable") + spawner_entity_1 = dynveg.create_prefab_vegetation_area("Purple Spawner", purple_position, 16.0, 16.0, 1.0, + purple_flower_prefab_path) pink_position = math.Vector3(520.0, 512.0, 32.0) - pink_asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - spawner_entity_2 = dynveg.create_dynamic_slice_vegetation_area("Pink Spawner", - pink_position, - 16.0, 16.0, 1.0, - pink_asset_path) + pink_flower_prefab_path = os.path.join("assets", "prefabs", "PinkFlower.spawnable") + spawner_entity_2 = dynveg.create_prefab_vegetation_area("Pink Spawner", pink_position, 16.0, 16.0, 1.0, + pink_flower_prefab_path) base_position = math.Vector3(512.0, 512.0, 32.0) dynveg.create_surface_entity("Surface Entity", @@ -135,11 +131,11 @@ def LayerBlender_E2E_Editor(): pink_count = 0 purple_count = 0 for instance in instances: - purple_asset_path = purple_asset_path.replace("\\", "/").lower() - pink_asset_path = pink_asset_path.replace("\\", "/").lower() - if instance.descriptor.spawner.GetSliceAssetPath() == pink_asset_path: + purple_flower_prefab_path = purple_flower_prefab_path.replace("\\", "/").lower() + pink_flower_prefab_path = pink_flower_prefab_path.replace("\\", "/").lower() + if instance.descriptor.spawner.GetPrefabAssetPath() == pink_flower_prefab_path: pink_count += 1 - elif instance.descriptor.spawner.GetSliceAssetPath() == purple_asset_path: + elif instance.descriptor.spawner.GetPrefabAssetPath() == purple_flower_prefab_path: purple_count += 1 Report.result(Tests.instances_blended, pink_count == purple_count and (pink_count + purple_count == num_expected)) @@ -152,11 +148,10 @@ def LayerBlender_E2E_Editor(): components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position) azlmbr.components.TransformBus(bus.Event, "SetLocalRotation", search_entity_ids[0], cam_rot_degrees_vector) - # 6) Save and export to engine + # 6) Save the created level general.save_level() - general.export_to_engine() - pak_path = os.path.join(paths.products, "levels", lvl_name, "level.pak") - success = helper.wait_for_condition(lambda: os.path.exists(pak_path), 10.0) + level_prefab_path = os.path.join(paths.products, "levels", lvl_name, f"{lvl_name}.spawnable") + success = helper.wait_for_condition(lambda: os.path.exists(level_prefab_path), 5.0) Report.result(Tests.saved_and_exported, success) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlocker_InstancesBlockedInConfiguredArea.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlocker_InstancesBlockedInConfiguredArea.py index b89edcdeb7..5c3083ee3d 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlocker_InstancesBlockedInConfiguredArea.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlocker_InstancesBlockedInConfiguredArea.py @@ -17,7 +17,6 @@ class Tests: ) - def LayerBlocker_InstancesBlockedInConfiguredArea(): """ Summary: @@ -58,8 +57,7 @@ def LayerBlocker_InstancesBlockedInConfiguredArea(): from editor_python_test_tools.utils import TestHelper as helper # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Set view of planting area for visual debugging general.set_current_view_position(512.0, 500.0, 38.0) @@ -67,9 +65,10 @@ def LayerBlocker_InstancesBlockedInConfiguredArea(): # 2) Create a new instance spawner entity spawner_center_point = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0, - asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "Blocker_PinkFlower")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", spawner_center_point, + 16.0, 16.0, 16.0, pink_flower_prefab) # 3) Create surface for planting on dynveg.create_surface_entity("Surface Entity", spawner_center_point, 32.0, 32.0, 1.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_FilterStageToggle.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_FilterStageToggle.py index 6796f56b11..a277f14a41 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_FilterStageToggle.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_FilterStageToggle.py @@ -42,16 +42,17 @@ def LayerSpawner_FilterStageToggle(): POSTPROCESS_INSTANCE_COUNT = 19 # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(500.49, 498.69, 46.66) general.set_current_view_rotation(-42.05, 0.00, -36.33) # Create a vegetation area with all needed components position = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - vegetation_entity = dynveg.create_dynamic_slice_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SpawnerFilter_PinkFlower")[0] + vegetation_entity = dynveg.create_temp_prefab_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, + pink_flower_prefab) vegetation_entity.add_component("Vegetation Altitude Filter") vegetation_entity.add_component("Vegetation Position Modifier") diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InheritBehaviorFlag.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InheritBehaviorFlag.py index 1153ae2657..dc06c298d1 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InheritBehaviorFlag.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InheritBehaviorFlag.py @@ -42,19 +42,16 @@ def LayerSpawner_InheritBehaviorFlag(): SURFACE_TAG = "test_tag" - def set_dynamic_slice_asset(entity_obj, component_index, dynamic_slice_asset_path): - dynamic_slice_spawner = vegetation.DynamicSliceInstanceSpawner() - dynamic_slice_spawner.SetSliceAssetPath(dynamic_slice_asset_path) - descriptor = hydra.get_component_property_value( - entity_obj.components[component_index], "Configuration|Embedded Assets|[0]" - ) - descriptor.spawner = dynamic_slice_spawner + def set_prefab_asset(entity_obj, component_index, spawnable_prefab): + descriptor = hydra.get_component_property_value(entity_obj.components[component_index], + "Configuration|Embedded Assets|[0]") + prefab_spawner = vegetation.PrefabInstanceSpawner() + prefab_spawner.SetPrefabAssetId(spawnable_prefab) + descriptor.spawner = prefab_spawner entity_obj.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor) # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") - + hydra.open_base_level() general.set_current_view_position(512.0, 480.0, 38.0) # Create Emitter entity and add the required components @@ -80,7 +77,9 @@ def LayerSpawner_InheritBehaviorFlag(): veg_1.create_entity( position, ["Vegetation Layer Spawner", "Shape Reference", "Vegetation Asset List"] ) - set_dynamic_slice_asset(veg_1, 2, os.path.join("Slices", "PinkFlower.dynamicslice")) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SpawnerInheritBehavior_PinkFlower")[0] + set_prefab_asset(veg_1, 2, pink_flower_prefab) veg_1.get_set_test(1, "Configuration|Shape Entity Id", blender_entity.id) # Create second vegetation area and assign a valid asset @@ -88,7 +87,9 @@ def LayerSpawner_InheritBehaviorFlag(): veg_2.create_entity( position, ["Vegetation Layer Spawner", "Shape Reference", "Vegetation Asset List"] ) - set_dynamic_slice_asset(veg_2, 2, os.path.join("Slices", "PurpleFlower.dynamicslice")) + purple_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + purple_flower_prefab = dynveg.create_temp_mesh_prefab(purple_flower_asset_path, "temp_PurpleFlower")[0] + set_prefab_asset(veg_2, 2, purple_flower_prefab) veg_2.get_set_test(1, "Configuration|Shape Entity Id", blender_entity.id) # Assign the vegetation areas to the Blender entity diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesPlantInAllSupportedShapes.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesPlantInAllSupportedShapes.py index beec54b4eb..662ac63714 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesPlantInAllSupportedShapes.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesPlantInAllSupportedShapes.py @@ -56,16 +56,14 @@ def LayerSpawner_InstancesPlantInAllSupportedShapes(): Report.result(success, result) # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # 2) Create basic vegetation area entity and set the properties entity_position = math.Vector3(125.0, 136.0, 32.0) - asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice") - vegetation = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", - entity_position, - 10.0, 10.0, 10.0, - asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SpawnerShapePlant_PinkFlower")[0] + vegetation = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_position, 10.0, 10.0, 10.0, + pink_flower_prefab) vegetation.remove_component("Box Shape") vegetation.add_component("Shape Reference") diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesRefreshUsingCorrectViewportCamera.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesRefreshUsingCorrectViewportCamera.py index fe8863c625..deb0376c9b 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesRefreshUsingCorrectViewportCamera.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerSpawner_InstancesRefreshUsingCorrectViewportCamera.py @@ -43,13 +43,13 @@ def LayerSpawner_InstancesRefreshUsingCorrectViewportCamera(): import azlmbr.legacy.general as general import azlmbr.math as math + import editor_python_test_tools.hydra_editor_utils as hydra from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg from editor_python_test_tools.utils import Report from editor_python_test_tools.utils import TestHelper as helper # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Set up a test environment to validate that switching viewports correctly changes which camera # the vegetation system uses. @@ -100,11 +100,12 @@ def LayerSpawner_InstancesRefreshUsingCorrectViewportCamera(): surface_height) # Create the two vegetation areas - test_slice_asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice") - first_veg_entity = dynveg.create_dynamic_slice_vegetation_area("Veg Area 1", first_entity_center_point, box_size, box_size, - box_size, test_slice_asset_path) - second_veg_entity = dynveg.create_dynamic_slice_vegetation_area("Veg Area 2", second_entity_center_point, box_size, box_size, - box_size, test_slice_asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SpawnerViewportRefresh_PinkFlower")[0] + first_veg_entity = dynveg.create_temp_prefab_vegetation_area("Veg Area 1", first_entity_center_point, box_size, box_size, + box_size, pink_flower_prefab) + second_veg_entity = dynveg.create_temp_prefab_vegetation_area("Veg Area 2", second_entity_center_point, box_size, box_size, + box_size, pink_flower_prefab) # When the first viewport is active, the first area should be full of instances, and the second should be empty general.set_active_viewport(0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMesh.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMesh.py index 9777a52c82..7c365d0ee5 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMesh.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMesh.py @@ -50,19 +50,17 @@ def MeshBlocker_InstancesBlockedByMesh(): from editor_python_test_tools.utils import TestHelper as helper # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(500.49, 498.69, 46.66) general.set_current_view_rotation(-42.05, 0.00, -36.33) # Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape" entity_position = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", - entity_position, - 10.0, 10.0, 10.0, - asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "MeshBlocker_PinkFlower")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_position, 10.0, 10.0, 10.0, + pink_flower_prefab) # Create surface entity to plant on dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMeshHeightTuning.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMeshHeightTuning.py index 3c47edeb91..a54a8653f0 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMeshHeightTuning.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshBlocker_InstancesBlockedByMeshHeightTuning.py @@ -53,19 +53,17 @@ def MeshBlocker_InstancesBlockedByMeshHeightTuning(): from editor_python_test_tools.utils import TestHelper as helper # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(500.49, 498.69, 46.66) general.set_current_view_rotation(-42.05, 0.00, -36.33) # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape" entity_position = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", - entity_position, - 10.0, 10.0, 10.0, - asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "MeshBlocker_PinkFlower2")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_position, 10.0, 10.0, 10.0, + pink_flower_prefab) # 3) Create surface entity to plant on dynveg.create_surface_entity("Surface Entity", entity_position, 10.0, 10.0, 1.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshSurfaceTagEmitter_DependentOnMeshComponent.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshSurfaceTagEmitter_DependentOnMeshComponent.py index cee8ebe5b6..9af17b0cd5 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshSurfaceTagEmitter_DependentOnMeshComponent.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshSurfaceTagEmitter_DependentOnMeshComponent.py @@ -58,8 +58,7 @@ def MeshSurfaceTagEmitter_DependentOnMeshComponent(): return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair) # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # 2) Create a new entity with component "Mesh Surface Tag Emitter" entity_position = math.Vector3(125.0, 136.0, 32.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py index d7abc66106..cd9963e844 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py @@ -47,8 +47,7 @@ def MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(): from editor_python_test_tools.utils import TestHelper as helper # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # 2) Create a new entity with components "Mesh Surface Tag Emitter", "Mesh" entity_position = math.Vector3(125.0, 136.0, 32.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PhysXColliderSurfaceTagEmitter_E2E_Editor.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PhysXColliderSurfaceTagEmitter_E2E_Editor.py index 6232cd374d..cdb2fac80b 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PhysXColliderSurfaceTagEmitter_E2E_Editor.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PhysXColliderSurfaceTagEmitter_E2E_Editor.py @@ -55,8 +55,7 @@ def PhysXColliderSurfaceTagEmitter_E2E_Editor(): return behavior_context_test_success # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Verify all of the BehaviorContext API: behavior_context = ( @@ -90,8 +89,10 @@ def PhysXColliderSurfaceTagEmitter_E2E_Editor(): dynveg.create_surface_entity("Baseline Surface", entity_center_point, 32.0, 32.0, 1.0) # Create a new entity with required vegetation area components - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Veg Area", entity_center_point, 32.0, 32.0, 32.0, asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "PhysXCollider_PinkFlower")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_center_point, test_box_size, + test_box_size, test_box_size, pink_flower_prefab) # Add a Vegetation Surface Mask Filter component to the spawner entity and set it to include the "test" tag spawner_entity.add_component("Vegetation Surface Mask Filter") diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_AutoSnapToSurfaceWorks.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_AutoSnapToSurfaceWorks.py index be7e8ad754..85a1cddb95 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_AutoSnapToSurfaceWorks.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_AutoSnapToSurfaceWorks.py @@ -64,8 +64,7 @@ def PositionModifier_AutoSnapToSurfaceWorks(): 'Configuration|Position Z|Range Min', 'Configuration|Position Z|Range Max'] # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Set view of planting area for visual debugging general.set_current_view_position(512.0, 500.0, 38.0) @@ -73,9 +72,10 @@ def PositionModifier_AutoSnapToSurfaceWorks(): # 2) Create a new entity with required vegetation area components and a Position Modifier spawner_center_point = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0, - asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "PosMod_PinkFlower")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, + 16.0, pink_flower_prefab) # Add a Vegetation Position Modifier and set offset values to 0 spawner_entity.add_component("Vegetation Position Modifier") diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets.py index 07d4fbd067..6be3dc31f7 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets.py @@ -102,16 +102,17 @@ def PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets(): return offset_success and offset_success2 # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Set view of planting area for visual debugging general.set_current_view_position(16.0, -5.0, 32.0) # 2) Create a new entity with required vegetation area components spawner_center_point = math.Vector3(16.0, 16.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", spawner_center_point, 1.0, 1.0, 1.0, asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "PosMod_PinkFlower2")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", spawner_center_point, 1.0, 1.0, + 1.0, pink_flower_prefab) # Add a Vegetation Position Modifier and set offset values to 0 spawner_entity.add_component("Vegetation Position Modifier") diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PrefabInstanceSpawner_Embedded_E2E.py similarity index 87% rename from AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py rename to AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PrefabInstanceSpawner_Embedded_E2E.py index b4650c782e..8ce865b5d2 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PrefabInstanceSpawner_Embedded_E2E.py @@ -63,12 +63,14 @@ def DynamicSliceInstanceSpawner_Embedded_E2E(): import azlmbr.entity as entity import azlmbr.math as math import azlmbr.paths as paths + import azlmbr.vegetation as vegetation import editor_python_test_tools.hydra_editor_utils as hydra from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg from editor_python_test_tools.utils import Report from editor_python_test_tools.utils import TestHelper as helper + # 1) Create a new, temporary level lvl_name = "tmp_level" helper.init_idle() @@ -79,13 +81,14 @@ def DynamicSliceInstanceSpawner_Embedded_E2E(): # 2) Create a new entity with required vegetation area components and Script Canvas component for launcher test center_point = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0, asset_path) + pink_flower_prefab_path = os.path.join("assets", "prefabs", "PinkFlower.spawnable") + spawner_entity = dynveg.create_prefab_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0, + pink_flower_prefab_path) spawner_entity.add_component("Script Canvas") instance_counter_path = os.path.join("scriptcanvas", "instance_counter.scriptcanvas") instance_counter_script = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", instance_counter_path, math.Uuid(), False) - spawner_entity.get_set_test(3, "Script Canvas Asset|Script Canvas Asset", instance_counter_script) + spawner_entity.get_set_test(3, "Properties", instance_counter_script) Report.result(Tests.spawner_entity_created, spawner_entity.id.IsValid() and hydra.has_components(spawner_entity.id, ["Script Canvas"])) @@ -106,11 +109,10 @@ def DynamicSliceInstanceSpawner_Embedded_E2E(): search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position) - # 6) Save and export to engine + # 6) Save the created level general.save_level() - general.export_to_engine() - pak_path = os.path.join(paths.products, "levels", lvl_name, "level.pak") - success = helper.wait_for_condition(lambda: os.path.exists(pak_path), 10.0) + level_prefab_path = os.path.join(paths.products, "levels", lvl_name, f"{lvl_name}.spawnable") + success = helper.wait_for_condition(lambda: os.path.exists(level_prefab_path), 5.0) Report.result(Tests.saved_and_exported, success) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PrefabInstanceSpawner_External_E2E.py similarity index 96% rename from AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py rename to AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PrefabInstanceSpawner_External_E2E.py index a5e7e90ce2..a3e60f6337 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/PrefabInstanceSpawner_External_E2E.py @@ -128,11 +128,10 @@ def DynamicSliceInstanceSpawner_External_E2E(): search_entity_ids = entity.SearchBus(bus.Broadcast, 'SearchEntities', search_filter) components.TransformBus(bus.Event, "MoveEntity", search_entity_ids[0], cam_position) - # 6) Save and export to engine + # 6) Save the created level general.save_level() - general.export_to_engine() - pak_path = os.path.join(paths.products, "levels", lvl_name, "level.pak") - success = helper.wait_for_condition(lambda: os.path.exists(pak_path), 10.0) + level_prefab_path = os.path.join(paths.products, "levels", lvl_name, f"{lvl_name}.spawnable") + success = helper.wait_for_condition(lambda: os.path.exists(level_prefab_path), 5.0) Report.result(Tests.saved_and_exported, success) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifierOverrides_InstancesRotateWithinRange.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifierOverrides_InstancesRotateWithinRange.py index c1ea8e03d1..877a38c231 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifierOverrides_InstancesRotateWithinRange.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifierOverrides_InstancesRotateWithinRange.py @@ -81,14 +81,15 @@ def RotationModifierOverrides_InstancesRotateWithinRange(): return result # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(512.0, 480.0, 38.0) # 2) Create vegetation entity and add components entity_position = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 16.0, asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "RotMod_PinkFlower2")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_position, 16.0, 16.0, 16.0, + pink_flower_prefab) spawner_entity.add_component("Vegetation Rotation Modifier") # Our default vegetation settings places 20 instances per 16 meters, so we expect 20 * 20 total instances. num_expected = 20 * 20 diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifier_InstancesRotateWithinRange.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifier_InstancesRotateWithinRange.py index 518c11a0cf..b0999f3195 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifier_InstancesRotateWithinRange.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/RotationModifier_InstancesRotateWithinRange.py @@ -120,13 +120,14 @@ def RotationModifier_InstancesRotateWithinRange(): # Main Script # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(512.0, 480.0, 38.0) # 2) Set up vegetation entities - asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Spawner Entity", LEVEL_CENTER, 2.0, 2.0, 2.0, asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "RotMod_PinkFlower")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", LEVEL_CENTER, 2.0, 2.0, 2.0, + pink_flower_prefab) additional_components = [ "Vegetation Rotation Modifier" diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifierOverrides_InstancesProperlyScale.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifierOverrides_InstancesProperlyScale.py index b2ce6d8afa..42b042e26e 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifierOverrides_InstancesProperlyScale.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifierOverrides_InstancesProperlyScale.py @@ -91,16 +91,17 @@ def ScaleModifierOverrides_InstancesProperlyScale(): return False # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(500.49, 498.69, 46.66) general.set_current_view_rotation(-42.05, 0.00, -36.33) # 2) Create a new entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape" entity_position = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 10.0, asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "ScaleMod_PinkFlower2")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_position, 16.0, 16.0, 16.0, + pink_flower_prefab) # Create a surface to plant on and add a Vegetation Debugger Level component to allow refreshes dynveg.create_surface_entity("Surface Entity", entity_position, 20.0, 20.0, 1.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifier_InstancesProperlyScale.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifier_InstancesProperlyScale.py index fd0df1c83d..8008224e3e 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifier_InstancesProperlyScale.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ScaleModifier_InstancesProperlyScale.py @@ -84,8 +84,7 @@ def ScaleModifier_InstancesProperlyScale(): return False # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(500.49, 498.69, 46.66) general.set_current_view_rotation(-42.05, 0.00, -36.33) @@ -93,9 +92,10 @@ def ScaleModifier_InstancesProperlyScale(): # 2) Create a new entity with components Vegetation Layer Spawner, Vegetation Asset List, Box Shape and # Vegetation Scale Modifier entity_position = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Spawner Entity", entity_position, 16.0, 16.0, 16.0, - asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "ScaleMod_PinkFlower")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_position, 16.0, 16.0, 16.0, + pink_flower_prefab) spawner_entity.add_component("Vegetation Scale Modifier") # Create a surface to plant on and add a Vegetation Debugger Level component to allow refreshes diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_FilterStageToggle.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_FilterStageToggle.py index b5c00a53b7..5436855433 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_FilterStageToggle.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_FilterStageToggle.py @@ -49,15 +49,16 @@ def ShapeIntersectionFilter_FilterStageToggle(): from editor_python_test_tools.utils import TestHelper as helper # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(512.0, 480.0, 38.0) # Create basic vegetation entity position = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - vegetation = dynveg.create_dynamic_slice_vegetation_area("vegetation", position, 16.0, 16.0, 16.0, asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "ShapeIntersection_PinkFlower")[0] + vegetation = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", position, 16.0, 16.0, 16.0, + pink_flower_prefab) # Create Surface for instances to plant on dynveg.create_surface_entity("Surface_Entity_Parent", position, 16.0, 16.0, 1.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_InstancesPlantInAssignedShape.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_InstancesPlantInAssignedShape.py index 6678a620af..e9e4c722f1 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_InstancesPlantInAssignedShape.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/ShapeIntersectionFilter_InstancesPlantInAssignedShape.py @@ -60,8 +60,7 @@ def ShapeIntersectionFilter_InstancesPlantInAssignedShape(): from editor_python_test_tools.utils import TestHelper as helper # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Set view of planting area for visual debugging general.set_current_view_position(512.0, 500.0, 38.0) @@ -69,9 +68,10 @@ def ShapeIntersectionFilter_InstancesPlantInAssignedShape(): # 2) Create a new entity with required vegetation area components and Vegetation Shape Intersection Filter center_point = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0, - asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "ShapeIntersection_PinkFlower2")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 1.0, + pink_flower_prefab) spawner_entity.add_component("Vegetation Shape Intersection Filter") # Create a planting surface diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment.py index c9233d15ea..07dbb3f977 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment.py @@ -58,15 +58,16 @@ def SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment(): return False # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(512.0, 480.0, 38.0) # Create a spawner entity setup with all needed components center_point = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0, asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SlopeAlign_PinkFlower2")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0, + pink_flower_prefab) # Create a sloped mesh surface for the instances to plant on center_point = math.Vector3(502.0, 512.0, 24.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifier_InstanceSurfaceAlignment.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifier_InstanceSurfaceAlignment.py index d92babffa4..088728480b 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifier_InstanceSurfaceAlignment.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeAlignmentModifier_InstanceSurfaceAlignment.py @@ -59,15 +59,16 @@ def SlopeAlignmentModifier_InstanceSurfaceAlignment(): return False # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(512.0, 480.0, 38.0) # Create a spawner entity setup with all needed components center_point = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0, asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SlopeAlign_PinkFlower")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", center_point, 16.0, 16.0, 32.0, + pink_flower_prefab) # Create a sloped mesh surface for the instances to plant on center_point = math.Vector3(502.0, 512.0, 24.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope.py index 0f95853156..cc04dc4cb1 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope.py @@ -63,16 +63,17 @@ def SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes(): from editor_python_test_tools.utils import TestHelper as helper # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Set view of planting area for visual debugging general.set_current_view_position(512.0, 475.0, 38.0) # 2) Create a new entity with required vegetation area components center_point = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "Slope_PinkFlower")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", center_point, 32.0, 32.0, 32.0, + pink_flower_prefab) # Add a Vegetation Slope Filter spawner_entity.add_component("Vegetation Slope Filter") diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SpawnerSlices_SliceCreationAndVisibilityToggleWorks.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SpawnerPrefabs_PrefabCreationAndVisibilityToggleWorks.py similarity index 52% rename from AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SpawnerSlices_SliceCreationAndVisibilityToggleWorks.py rename to AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SpawnerPrefabs_PrefabCreationAndVisibilityToggleWorks.py index fc55080cec..182bd5510a 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SpawnerSlices_SliceCreationAndVisibilityToggleWorks.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SpawnerPrefabs_PrefabCreationAndVisibilityToggleWorks.py @@ -7,21 +7,21 @@ SPDX-License-Identifier: Apache-2.0 OR MIT class Tests: - spawner_slice_created = ( - "Spawner slice created successfully", - "Failed to create Spawner slice" + spawner_prefab_created = ( + "Spawner prefab created successfully", + "Failed to create Spawner prefab" ) instance_count_unhidden = ( "Initial instance counts are as expected", "Found an unexpected number of initial instances" ) instance_count_hidden = ( - "Instance counts upon hiding the Spawner slice are as expected", - "Unexpectedly found instances with the Spawner slice hidden" + "Instance counts upon hiding the Spawner prefab are as expected", + "Unexpectedly found instances with the Spawner prefab hidden" ) - blender_slice_created = ( - "Blender slice created successfully", - "Failed to create Blender slice" + blender_prefab_created = ( + "Blender prefab created successfully", + "Failed to create Blender prefab" ) @@ -43,81 +43,76 @@ def SpawnerSlices_SliceCreationAndVisibilityToggleWorks(): import azlmbr.math as math import azlmbr.legacy.general as general - import azlmbr.slice as slice import azlmbr.bus as bus import azlmbr.editor as editor - import azlmbr.asset as asset import editor_python_test_tools.hydra_editor_utils as hydra from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg + from editor_python_test_tools.editor_entity_utils import EditorEntity from editor_python_test_tools.utils import Report from editor_python_test_tools.utils import TestHelper as helper - - def path_is_valid_asset(asset_path): - asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", asset_path, math.Uuid(), False) - return asset_id.invoke("IsValid") + from editor_python_test_tools.prefab_utils import Prefab # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(512.0, 480.0, 38.0) - # 2) C2627900 Verifies if a slice containing the Vegetation Layer Spawner component can be created. + # 2) Verifies if a prefab containing the Vegetation Layer Spawner component can be created. # 2.1) Create basic vegetation entity position = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - veg_1 = dynveg.create_dynamic_slice_vegetation_area("vegetation_1", position, 16.0, 16.0, 16.0, asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SpawnerPrefab_PinkFlower")[0] + veg_1 = dynveg.create_temp_prefab_vegetation_area("vegetation_1", position, 16.0, 16.0, 16.0, + pink_flower_prefab) - # 2.2) Create slice from the entity - slice_path = os.path.join("slices", "TestSlice_1.slice") - slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", veg_1.id, slice_path) + # 2.2) Create prefab from the entity + spawner_prefab_filename = "TestPrefab_1" + spawner_prefab, spawner_prefab_instance = Prefab.create_prefab([veg_1], spawner_prefab_filename) - # 2.3) Verify if the slice has been created successfully - spawner_slice_success = helper.wait_for_condition(lambda: path_is_valid_asset(slice_path), 10.0) - Report.result(Tests.spawner_slice_created, spawner_slice_success) + # Verify if prefab is created + Report.result(Tests.spawner_prefab_created, spawner_prefab.is_prefab_loaded(spawner_prefab_filename)) - # 3) C2627904: Hiding a slice containing the component clears any visuals from the Viewport + # 3) Hiding a prefab containing the component clears any visuals from the Viewport # 3.1) Create Surface for instances to plant on dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0) - # 3.2) Initially verify instance count before hiding slice + # 3.2) Initially verify instance count before hiding prefab initial_count_success = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, 400), 5.0) Report.result(Tests.instance_count_unhidden, initial_count_success) - # 3.3) Hide the slice and verify instance count - editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", veg_1.id, False) + # 3.3) Hide the prefab and verify instance count + editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", spawner_prefab_instance.container_entity.id, False) hidden_instance_count = helper.wait_for_condition(lambda: dynveg.validate_instance_count(position, 16.0, 0), 5.0) Report.result(Tests.instance_count_hidden, hidden_instance_count) # 3.4) Unhide the slice - editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", veg_1.id, True) + editor.EditorEntityAPIBus(bus.Event, "SetVisibilityState", spawner_prefab_instance.container_entity.id, True) - # 4) C2627905 A slice containing the Vegetation Layer Blender component can be created. + # 4) A slice containing the Vegetation Layer Blender component can be created. # 4.1) Create another vegetation entity to add to blender component - veg_2 = dynveg.create_dynamic_slice_vegetation_area("vegetation_2", position, 1.0, 1.0, 1.0, "") + veg_2 = dynveg.create_empty_vegetation_area("vegetation_2", position, 1.0, 1.0, 1.0) # 4.2) Create entity with Vegetation Layer Blender components_to_add = ["Box Shape", "Vegetation Layer Blender"] - blender_entity = hydra.Entity("blender_entity") - blender_entity.create_entity(position, components_to_add) + blender_entity = EditorEntity.create_editor_entity("blender_entity") + blender_entity.add_components(components_to_add) # 4.3) Pin both the vegetation areas to the blender entity - pte = hydra.get_property_tree(blender_entity.components[1]) + pte = blender_entity.components[1].get_property_tree() path = "Configuration|Vegetation Areas" pte.update_container_item(path, 0, veg_1.id) pte.add_container_item(path, 1, veg_2.id) # 4.4) Drag the simple vegetation areas under the Vegetation Layer Blender entity to create an entity hierarchy. veg_1.set_test_parent_entity(blender_entity) - veg_2.set_test_parent_entity(blender_entity) + veg_2.set_parent_entity(blender_entity.id) - # 4.5) Create slice from blender entity - slice_path = os.path.join("slices", "TestSlice_2.slice") - slice.SliceRequestBus(bus.Broadcast, "CreateNewSlice", blender_entity.id, slice_path) + # 4.5) Create prefab from blender entity + blender_prefab_filename = "TestPrefab_2" + blender_prefab, blender_prefab_instance = Prefab.create_prefab([veg_2], blender_prefab_filename) - # 4.6) Verify if the slice has been created successfully - blender_slice_success = helper.wait_for_condition(lambda: path_is_valid_asset(slice_path), 5.0) - Report.result(Tests.blender_slice_created, blender_slice_success) + # 4.6) Verify if the prefab has been created successfully + Report.result(Tests.blender_prefab_created, blender_prefab.is_prefab_loaded(blender_prefab_filename)) if __name__ == "__main__": diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceDataRefreshes_RemainsStable.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceDataRefreshes_RemainsStable.py index 1ad4f305c3..3612e03bcc 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceDataRefreshes_RemainsStable.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceDataRefreshes_RemainsStable.py @@ -34,13 +34,12 @@ def SurfaceDataRefreshes_RemainsStable(): import azlmbr.legacy.general as general import azlmbr.math as math + import editor_python_test_tools.hydra_editor_utils as hydra from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() world_center = math.Vector3(512.0, 512.0, 32.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected.py index 3e76a03c53..b98b0f0546 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected.py @@ -67,8 +67,7 @@ def SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected(): surface_data.SurfaceTag("test_tag3")] # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Set view of planting area for visual debugging general.set_current_view_position(512.0, 500.0, 38.0) @@ -76,9 +75,10 @@ def SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected(): # 2) Create a new instance spawner entity with multiple Dynamic Slice Instance Spawner descriptors spawner_center_point = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, 16.0, - asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SurfaceMaskOverrides_PinkFlower")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", spawner_center_point, 16.0, 16.0, + 16.0, pink_flower_prefab) asset_list_component = spawner_entity.components[2] desc_asset = hydra.get_component_property_value(asset_list_component, "Configuration|Embedded Assets")[0] diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_BasicSurfaceTagCreation.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_BasicSurfaceTagCreation.py index fee62c04d1..fe17b03c6f 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_BasicSurfaceTagCreation.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_BasicSurfaceTagCreation.py @@ -39,12 +39,12 @@ def SurfaceMaskFilter_BasicSurfaceTagCreation(): """ import azlmbr.surface_data as surface_data + + import editor_python_test_tools.hydra_editor_utils as hydra from editor_python_test_tools.utils import Report - from editor_python_test_tools.utils import TestHelper as helper # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() tag1 = surface_data.SurfaceTag() tag2 = surface_data.SurfaceTag() diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_ExclusionList.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_ExclusionList.py index 3f298e793e..f5174af3bb 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_ExclusionList.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_ExclusionList.py @@ -91,18 +91,16 @@ def SurfaceMaskFilter_ExclusionList(): Report.info(f"Failed to add Generated surface tag of {surface_tag}") # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(512.0, 480.0, 38.0) # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape" entity_position = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", - entity_position, - 10.0, 10.0, 10.0, - asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SurfaceMaskTagExclusion_PinkFlower")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_position, 10.0, 10.0, 10.0, + pink_flower_prefab) # 3) Add a Vegetation Surface Mask Filter component to the entity. spawner_entity.add_component("Vegetation Surface Mask Filter") diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_InclusionList.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_InclusionList.py index 39b72ff4a9..34d22d3d9b 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_InclusionList.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_InclusionList.py @@ -92,18 +92,16 @@ def SurfaceMaskFilter_InclusionList(): Report.info(f"Failed to add Generated surface tag of {surface_tag}") # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(512.0, 480.0, 38.0) # 2) Create entity with components "Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape" entity_position = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Instance Spawner", - entity_position, - 10.0, 10.0, 10.0, - asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SurfaceMaskTagInclusion_PinkFlower")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", entity_position, 10.0, 10.0, 10.0, + pink_flower_prefab) # 3) Add a Vegetation Surface Mask Filter component to the entity. spawner_entity.add_component("Vegetation Surface Mask Filter") diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorPointDensity.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorPointDensity.py index 167fb8901c..7516bfb31d 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorPointDensity.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorPointDensity.py @@ -47,15 +47,16 @@ def SystemSettings_SectorPointDensity(): INSTANCE_COUNT_AFTER_DENSITY_CHANGE = 100 # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(512.0, 480.0, 38.0) # Create basic vegetation entity position = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - dynveg.create_dynamic_slice_vegetation_area("vegetation", position, 16.0, 16.0, 1.0, asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SectorPoint_PinkFlower")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", position, 16.0, 16.0, 1.0, + pink_flower_prefab) dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0) # Count the number of vegetation instances in the vegetation area diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorSize.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorSize.py index 7bb78ac3e0..ef7959a3e7 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorSize.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SystemSettings_SectorSize.py @@ -43,15 +43,16 @@ def SystemSettings_SectorSize(): VEGETATION_INSTANCE_COUNT = 400 # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() general.set_current_view_position(512.0, 480.0, 38.0) # Create basic vegetation entity position = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PinkFlower.dynamicslice") - vegetation = dynveg.create_dynamic_slice_vegetation_area("vegetation", position, 16.0, 16.0, 1.0, asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "SectorSize_PinkFlower")[0] + vegetation = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", position, 16.0, 16.0, 1.0, + pink_flower_prefab) dynveg.create_surface_entity("Surface_Entity", position, 16.0, 16.0, 1.0) # Add the Vegetation Debugger component to the Level Inspector diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/VegetationInstances_DespawnWhenOutOfRange.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/VegetationInstances_DespawnWhenOutOfRange.py index 8a6c4d9a17..b6069d1ef5 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/VegetationInstances_DespawnWhenOutOfRange.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/VegetationInstances_DespawnWhenOutOfRange.py @@ -43,18 +43,20 @@ def VegetationInstances_DespawnWhenOutOfRange(): import azlmbr.legacy.general as general import azlmbr.math as math + import editor_python_test_tools.hydra_editor_utils as hydra from largeworlds.large_worlds_utils import editor_dynveg_test_helper as dynveg from editor_python_test_tools.utils import Report from editor_python_test_tools.utils import TestHelper as helper # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Create vegetation layer spawner world_center = math.Vector3(512.0, 512.0, 32.0) - asset_path = os.path.join("Slices", "PurpleFlower.dynamicslice") - spawner_entity = dynveg.create_dynamic_slice_vegetation_area("Spawner Instance", world_center, 16.0, 16.0, 16.0, asset_path) + pink_flower_asset_path = os.path.join("assets", "objects", "foliage", "grass_flower_pink.azmodel") + pink_flower_prefab = dynveg.create_temp_mesh_prefab(pink_flower_asset_path, "RangeDespawn_PinkFlower")[0] + spawner_entity = dynveg.create_temp_prefab_vegetation_area("Instance Spawner", world_center, 16.0, 16.0, 16.0, + pink_flower_prefab) # Create a surface to spawn on dynveg.create_surface_entity("Spawner Entity", world_center, 16.0, 16.0, 1.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main.py index 06c9c5f615..d508e390cb 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main.py @@ -7,21 +7,171 @@ SPDX-License-Identifier: Apache-2.0 OR MIT import os import pytest -import sys -sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../automatedtesting_shared') -from base import TestAutomationBase +import ly_test_tools.environment.file_system as file_system +from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite @pytest.mark.SUITE_main @pytest.mark.parametrize("launcher_platform", ['windows_editor']) @pytest.mark.parametrize("project", ["AutomatedTesting"]) -class TestAutomation(TestAutomationBase): +class TestAutomation(EditorTestSuite): - def test_DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks(self, request, workspace, editor, launcher_platform): + # Helpers for test asset cleanup + def cleanup_test_level(self, workspace): + file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "Levels", "tmp_level")], + True, True) + + class test_AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude(EditorSharedTest): + from .EditorScripts import AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude as test_module + + class test_AltitudeFilter_FilterStageToggle(EditorSharedTest): + from .EditorScripts import AltitudeFilter_FilterStageToggle as test_module + + class test_AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude(EditorSharedTest): + from .EditorScripts import AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude as test_module + + class test_AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea(EditorSharedTest): + from .EditorScripts import AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea as test_module + + class test_AssetWeightSelector_InstancesExpressBasedOnWeight(EditorSharedTest): + from .EditorScripts import AssetWeightSelector_InstancesExpressBasedOnWeight as test_module + + @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/4155") + class test_DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius(EditorSharedTest): + from .EditorScripts import DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius as test_module + + @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/4155") + class test_DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius(EditorSharedTest): + from .EditorScripts import DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius as test_module + + class test_DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks(EditorSharedTest): from .EditorScripts import DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - def test_EmptyInstanceSpawner_EmptySpawnerWorks(self, request, workspace, editor, launcher_platform): + class test_EmptyInstanceSpawner_EmptySpawnerWorks(EditorSharedTest): from .EditorScripts import EmptyInstanceSpawner_EmptySpawnerWorks as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) + + class test_InstanceSpawnerPriority_LayerAndSubPriority_HigherValuesPlantOverLower(EditorSharedTest): + from .EditorScripts import InstanceSpawnerPriority_LayerAndSubPriority as test_module + + class test_LayerBlender_E2E_Editor(EditorSingleTest): + from .EditorScripts import LayerBlender_E2E_Editor as test_module + + # Custom setup/teardown to remove test level created during test + def setup(self, request, workspace, editor, editor_test_results, launcher_platform): + TestAutomation.cleanup_test_level(self, workspace) + + def teardown(self, request, workspace, editor, editor_test_results, launcher_platform): + TestAutomation.cleanup_test_level(self, workspace) + + class test_LayerBlocker_InstancesBlockedInConfiguredArea(EditorSharedTest): + from .EditorScripts import LayerBlocker_InstancesBlockedInConfiguredArea as test_module + + class test_LayerSpawner_FilterStageToggle(EditorSharedTest): + from .EditorScripts import LayerSpawner_FilterStageToggle as test_module + + class test_LayerSpawner_InheritBehaviorFlag(EditorSharedTest): + from .EditorScripts import LayerSpawner_InheritBehaviorFlag as test_module + + class test_LayerSpawner_InstancesPlantInAllSupportedShapes(EditorSharedTest): + from .EditorScripts import LayerSpawner_InstancesPlantInAllSupportedShapes as test_module + + @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/6549") + class test_LayerSpawner_InstancesRefreshUsingCorrectViewportCamera(EditorSharedTest): + from .EditorScripts import LayerSpawner_InstancesRefreshUsingCorrectViewportCamera as test_module + + class test_MeshBlocker_InstancesBlockedByMesh(EditorSharedTest): + from .EditorScripts import MeshBlocker_InstancesBlockedByMesh as test_module + + class test_MeshBlocker_InstancesBlockedByMeshHeightTuning(EditorSharedTest): + from .EditorScripts import MeshBlocker_InstancesBlockedByMeshHeightTuning as test_module + + class test_MeshSurfaceTagEmitter_DependentOnMeshComponent(EditorSharedTest): + from .EditorScripts import MeshSurfaceTagEmitter_DependentOnMeshComponent as test_module + + class test_MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(EditorSharedTest): + from .EditorScripts import MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully as test_module + + class test_PhysXColliderSurfaceTagEmitter_E2E_Editor(EditorSharedTest): + from .EditorScripts import PhysXColliderSurfaceTagEmitter_E2E_Editor as test_module + + class test_PositionModifier_AutoSnapToSurfaceWorks(EditorSharedTest): + from .EditorScripts import PositionModifier_AutoSnapToSurfaceWorks as test_module + + class test_PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets(EditorSharedTest): + from .EditorScripts import \ + PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets as test_module + + class test_PrefabInstanceSpawner_Embedded_E2E_Editor(EditorSingleTest): + from .EditorScripts import PrefabInstanceSpawner_Embedded_E2E as test_module + + # Custom setup/teardown to remove test level created during test + def setup(self, request, workspace, editor, editor_test_results, launcher_platform): + TestAutomation.cleanup_test_level(self, workspace) + + def teardown(self, request, workspace, editor, editor_test_results, launcher_platform): + TestAutomation.cleanup_test_level(self, workspace) + + class test_PrefabInstanceSpawner_External_E2E_Editor(EditorSingleTest): + from .EditorScripts import PrefabInstanceSpawner_External_E2E as test_module + + # Custom setup/teardown to remove test level created during test + def setup(self, request, workspace, editor, editor_test_results, launcher_platform): + TestAutomation.cleanup_test_level(self, workspace) + + def teardown(self, request, workspace, editor, editor_test_results, launcher_platform): + TestAutomation.cleanup_test_level(self, workspace) + + class test_RotationModifier_InstancesRotateWithinRange(EditorSharedTest): + from .EditorScripts import RotationModifier_InstancesRotateWithinRange as test_module + + class test_RotationModifierOverrides_InstancesRotateWithinRange(EditorSharedTest): + from .EditorScripts import RotationModifierOverrides_InstancesRotateWithinRange as test_module + + class test_ScaleModifier_InstancesProperlyScale(EditorSharedTest): + from .EditorScripts import ScaleModifier_InstancesProperlyScale as test_module + + class test_ScaleModifierOverrides_InstancesProperlyScale(EditorSharedTest): + from .EditorScripts import ScaleModifierOverrides_InstancesProperlyScale as test_module + + class test_ShapeIntersectionFilter_FilterStageToggle(EditorSharedTest): + from .EditorScripts import ShapeIntersectionFilter_FilterStageToggle as test_module + + class test_ShapeIntersectionFilter_InstancesPlantInAssignedShape(EditorSharedTest): + from .EditorScripts import ShapeIntersectionFilter_InstancesPlantInAssignedShape as test_module + + class test_SlopeAlignmentModifier_InstanceSurfaceAlignment(EditorSharedTest): + from .EditorScripts import SlopeAlignmentModifier_InstanceSurfaceAlignment as test_module + + class test_SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment(EditorSharedTest): + from .EditorScripts import SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment as test_module + + class test_SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes(EditorSharedTest): + from .EditorScripts import SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope as test_module + + class test_SpawnerPrefabs_PrefabCreationAndVisibilityToggleWorks(EditorSharedTest): + from .EditorScripts import SpawnerPrefabs_PrefabCreationAndVisibilityToggleWorks as test_module + + class test_SurfaceDataRefreshes_RemainsStable(EditorSharedTest): + from .EditorScripts import SurfaceDataRefreshes_RemainsStable as test_module + + class test_SurfaceMaskFilter_BasicSurfaceTagCreation(EditorSharedTest): + from .EditorScripts import SurfaceMaskFilter_BasicSurfaceTagCreation as test_module + + class test_SurfaceMaskFilter_ExclusiveSurfaceTags_Function(EditorSharedTest): + from .EditorScripts import SurfaceMaskFilter_ExclusionList as test_module + + class test_SurfaceMaskFilter_InclusiveSurfaceTags_Function(EditorSharedTest): + from .EditorScripts import SurfaceMaskFilter_InclusionList as test_module + + class test_SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected(EditorSharedTest): + from .EditorScripts import SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected as test_module + + class test_SystemSettings_SectorPointDensity(EditorSharedTest): + from .EditorScripts import SystemSettings_SectorPointDensity as test_module + + class test_SystemSettings_SectorSize(EditorSharedTest): + from .EditorScripts import SystemSettings_SectorSize as test_module + + class test_VegetationInstances_DespawnWhenOutOfRange(EditorSharedTest): + from .EditorScripts import VegetationInstances_DespawnWhenOutOfRange as test_module diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main_Optimized.py deleted file mode 100644 index 5b1e504442..0000000000 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Main_Optimized.py +++ /dev/null @@ -1,192 +0,0 @@ -""" -Copyright (c) Contributors to the Open 3D Engine Project. -For complete copyright and license terms please see the LICENSE at the root of this distribution. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" - -import os -import pytest - -import ly_test_tools.environment.file_system as file_system -from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite - - -@pytest.mark.SUITE_main -@pytest.mark.parametrize("launcher_platform", ['windows_editor']) -@pytest.mark.parametrize("project", ["AutomatedTesting"]) -class TestAutomation(EditorTestSuite): - class test_AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude(EditorParallelTest): - from .EditorScripts import AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude as test_module - - class test_AltitudeFilter_FilterStageToggle(EditorParallelTest): - from .EditorScripts import AltitudeFilter_FilterStageToggle as test_module - - class test_AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude(EditorParallelTest): - from .EditorScripts import AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude as test_module - - -@pytest.mark.SUITE_main -@pytest.mark.parametrize("launcher_platform", ['windows_editor']) -@pytest.mark.parametrize("project", ["AutomatedTesting"]) -class TestAutomation_PrefabNotEnabled(EditorTestSuite): - - enable_prefab_system = False - - # Helpers for test asset cleanup - def cleanup_test_level(self, workspace): - file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "Levels", "tmp_level")], - True, True) - - def cleanup_test_slices(self, workspace): - file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "slices", - "TestSlice_1.slice")], True, True) - file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "slices", - "TestSlice_2.slice")], True, True) - - class test_DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks(EditorParallelTest): - from .EditorScripts import DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks as test_module - - class test_EmptyInstanceSpawner_EmptySpawnerWorks(EditorParallelTest): - from .EditorScripts import EmptyInstanceSpawner_EmptySpawnerWorks as test_module - - class test_SpawnerSlices_SliceCreationAndVisibilityToggleWorks(EditorSingleTest): - # Custom teardown to remove slice asset created during test - def teardown(self, request, workspace, editor, editor_test_results, launcher_platform): - TestAutomation_PrefabNotEnabled.cleanup_test_slices(self, workspace) - from .EditorScripts import SpawnerSlices_SliceCreationAndVisibilityToggleWorks as test_module - - class test_AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea(EditorParallelTest): - from .EditorScripts import AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea as test_module - - class test_AssetWeightSelector_InstancesExpressBasedOnWeight(EditorParallelTest): - from .EditorScripts import AssetWeightSelector_InstancesExpressBasedOnWeight as test_module - - @pytest.mark.skip(reason="https://github.com/o3de/o3de/issues/4155") - class test_DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius(EditorParallelTest): - from .EditorScripts import DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius as test_module - - @pytest.mark.skip(reason="https://github.com/o3de/o3de/issues/4155") - class test_DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius(EditorParallelTest): - from .EditorScripts import DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius as test_module - - class test_SurfaceDataRefreshes_RemainsStable(EditorParallelTest): - from .EditorScripts import SurfaceDataRefreshes_RemainsStable as test_module - - class test_VegetationInstances_DespawnWhenOutOfRange(EditorParallelTest): - from .EditorScripts import VegetationInstances_DespawnWhenOutOfRange as test_module - - class test_InstanceSpawnerPriority_LayerAndSubPriority_HigherValuesPlantOverLower(EditorParallelTest): - from .EditorScripts import InstanceSpawnerPriority_LayerAndSubPriority as test_module - - class test_LayerBlocker_InstancesBlockedInConfiguredArea(EditorParallelTest): - from .EditorScripts import LayerBlocker_InstancesBlockedInConfiguredArea as test_module - - class test_LayerSpawner_InheritBehaviorFlag(EditorParallelTest): - from .EditorScripts import LayerSpawner_InheritBehaviorFlag as test_module - - class test_LayerSpawner_InstancesPlantInAllSupportedShapes(EditorParallelTest): - from .EditorScripts import LayerSpawner_InstancesPlantInAllSupportedShapes as test_module - - class test_LayerSpawner_FilterStageToggle(EditorParallelTest): - from .EditorScripts import LayerSpawner_FilterStageToggle as test_module - - @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2038") - class test_LayerSpawner_InstancesRefreshUsingCorrectViewportCamera(EditorParallelTest): - from .EditorScripts import LayerSpawner_InstancesRefreshUsingCorrectViewportCamera as test_module - - class test_MeshBlocker_InstancesBlockedByMesh(EditorParallelTest): - from .EditorScripts import MeshBlocker_InstancesBlockedByMesh as test_module - - class test_MeshBlocker_InstancesBlockedByMeshHeightTuning(EditorParallelTest): - from .EditorScripts import MeshBlocker_InstancesBlockedByMeshHeightTuning as test_module - - class test_MeshSurfaceTagEmitter_DependentOnMeshComponent(EditorParallelTest): - from .EditorScripts import MeshSurfaceTagEmitter_DependentOnMeshComponent as test_module - - class test_MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(EditorParallelTest): - from .EditorScripts import MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully as test_module - - class test_PhysXColliderSurfaceTagEmitter_E2E_Editor(EditorParallelTest): - from .EditorScripts import PhysXColliderSurfaceTagEmitter_E2E_Editor as test_module - - class test_PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets(EditorParallelTest): - from .EditorScripts import PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets as test_module - - class test_PositionModifier_AutoSnapToSurfaceWorks(EditorParallelTest): - from .EditorScripts import PositionModifier_AutoSnapToSurfaceWorks as test_module - - class test_RotationModifier_InstancesRotateWithinRange(EditorParallelTest): - from .EditorScripts import RotationModifier_InstancesRotateWithinRange as test_module - - class test_RotationModifierOverrides_InstancesRotateWithinRange(EditorParallelTest): - from .EditorScripts import RotationModifierOverrides_InstancesRotateWithinRange as test_module - - class test_ScaleModifier_InstancesProperlyScale(EditorParallelTest): - from .EditorScripts import ScaleModifier_InstancesProperlyScale as test_module - - class test_ScaleModifierOverrides_InstancesProperlyScale(EditorParallelTest): - from .EditorScripts import ScaleModifierOverrides_InstancesProperlyScale as test_module - - class test_ShapeIntersectionFilter_InstancesPlantInAssignedShape(EditorParallelTest): - from .EditorScripts import ShapeIntersectionFilter_InstancesPlantInAssignedShape as test_module - - class test_ShapeIntersectionFilter_FilterStageToggle(EditorParallelTest): - from .EditorScripts import ShapeIntersectionFilter_FilterStageToggle as test_module - - class test_SlopeAlignmentModifier_InstanceSurfaceAlignment(EditorParallelTest): - from .EditorScripts import SlopeAlignmentModifier_InstanceSurfaceAlignment as test_module - - class test_SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment(EditorParallelTest): - from .EditorScripts import SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment as test_module - - class test_SurfaceMaskFilter_BasicSurfaceTagCreation(EditorParallelTest): - from .EditorScripts import SurfaceMaskFilter_BasicSurfaceTagCreation as test_module - - class test_SurfaceMaskFilter_ExclusiveSurfaceTags_Function(EditorParallelTest): - from .EditorScripts import SurfaceMaskFilter_ExclusionList as test_module - - class test_SurfaceMaskFilter_InclusiveSurfaceTags_Function(EditorParallelTest): - from .EditorScripts import SurfaceMaskFilter_InclusionList as test_module - - class test_SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected(EditorParallelTest): - from .EditorScripts import SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected as test_module - - class test_SystemSettings_SectorPointDensity(EditorParallelTest): - from .EditorScripts import SystemSettings_SectorPointDensity as test_module - - class test_SystemSettings_SectorSize(EditorParallelTest): - from .EditorScripts import SystemSettings_SectorSize as test_module - - class test_SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes(EditorParallelTest): - from .EditorScripts import SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope as test_module - - class test_DynamicSliceInstanceSpawner_Embedded_E2E_Editor(EditorSingleTest): - from .EditorScripts import DynamicSliceInstanceSpawner_Embedded_E2E as test_module - - # Custom setup/teardown to remove test level created during test - def setup(self, request, workspace, editor, editor_test_results, launcher_platform): - TestAutomation_PrefabNotEnabled.cleanup_test_level(self, workspace) - - def teardown(self, request, workspace, editor, editor_test_results, launcher_platform): - TestAutomation_PrefabNotEnabled.cleanup_test_level(self, workspace) - - class test_DynamicSliceInstanceSpawner_External_E2E_Editor(EditorSingleTest): - from .EditorScripts import DynamicSliceInstanceSpawner_External_E2E as test_module - - # Custom setup/teardown to remove test level created during test - def setup(self, request, workspace, editor, editor_test_results, launcher_platform): - TestAutomation_PrefabNotEnabled.cleanup_test_level(self, workspace) - - def teardown(self, request, workspace, editor, editor_test_results, launcher_platform): - TestAutomation_PrefabNotEnabled.cleanup_test_level(self, workspace) - - class test_LayerBlender_E2E_Editor(EditorSingleTest): - from .EditorScripts import LayerBlender_E2E_Editor as test_module - - # Custom setup/teardown to remove test level created during test - def setup(self, request, workspace, editor, editor_test_results, launcher_platform): - TestAutomation_PrefabNotEnabled.cleanup_test_level(self, workspace) - - def teardown(self, request, workspace, editor, editor_test_results, launcher_platform): - TestAutomation_PrefabNotEnabled.cleanup_test_level(self, workspace) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Periodic.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Periodic.py index 64f6cfdf30..bf7e76f973 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Periodic.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Periodic.py @@ -7,277 +7,17 @@ SPDX-License-Identifier: Apache-2.0 OR MIT import os import pytest -import sys -import ly_test_tools.environment.waiter as waiter import ly_test_tools.environment.file_system as file_system -import editor_python_test_tools.hydra_test_utils as hydra -from ly_remote_console.remote_console_commands import RemoteConsole as RemoteConsole - -sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../automatedtesting_shared') -from base import TestAutomationBase - - -@pytest.fixture -def remove_test_slice(request, workspace, project): - file_system.delete([os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice_1.slice")], True, - True) - file_system.delete([os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice_2.slice")], True, - True) - - def teardown(): - file_system.delete([os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice_1.slice")], True, - True) - file_system.delete([os.path.join(workspace.paths.engine_root(), project, "slices", "TestSlice_2.slice")], True, - True) - request.addfinalizer(teardown) - - -@pytest.fixture -def remote_console_instance(request): - console = RemoteConsole() - - def teardown(): - if console.connected: - console.stop() - - request.addfinalizer(teardown) - return console +from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite @pytest.mark.SUITE_periodic @pytest.mark.parametrize("launcher_platform", ['windows_editor']) @pytest.mark.parametrize("project", ["AutomatedTesting"]) -class TestAutomation(TestAutomationBase): +class TestAutomation(EditorTestSuite): - def test_AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude(self, request, workspace, editor, launcher_platform): - from .EditorScripts import AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude as test_module - self._run_test(request, workspace, editor, test_module) + global_extra_cmdline_args = ["-BatchMode", "-autotest_mode"] - def test_AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude(self, request, workspace, editor, launcher_platform): - from .EditorScripts import AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude as test_module - self._run_test(request, workspace, editor, test_module) - - def test_AltitudeFilter_FilterStageToggle(self, request, workspace, editor, launcher_platform): - from .EditorScripts import AltitudeFilter_FilterStageToggle as test_module - self._run_test(request, workspace, editor, test_module) - - def test_SpawnerSlices_SliceCreationAndVisibilityToggleWorks(self, request, workspace, editor, remove_test_slice, launcher_platform): - from .EditorScripts import SpawnerSlices_SliceCreationAndVisibilityToggleWorks as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea(self, request, workspace, editor, launcher_platform): - from .EditorScripts import AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_AssetWeightSelector_InstancesExpressBasedOnWeight(self, request, workspace, editor, launcher_platform): - from .EditorScripts import AssetWeightSelector_InstancesExpressBasedOnWeight as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/4155") - def test_DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius(self, request, workspace, editor, launcher_platform): - from .EditorScripts import DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/4155") - def test_DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius(self, request, workspace, editor, launcher_platform): - from .EditorScripts import DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_SurfaceDataRefreshes_RemainsStable(self, request, workspace, editor, launcher_platform): - from .EditorScripts import SurfaceDataRefreshes_RemainsStable as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_VegetationInstances_DespawnWhenOutOfRange(self, request, workspace, editor, launcher_platform): - from .EditorScripts import VegetationInstances_DespawnWhenOutOfRange as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_InstanceSpawnerPriority_LayerAndSubPriority_HigherValuesPlantOverLower(self, request, workspace, editor, launcher_platform): - from .EditorScripts import InstanceSpawnerPriority_LayerAndSubPriority as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LayerBlocker_InstancesBlockedInConfiguredArea(self, request, workspace, editor, launcher_platform): - from .EditorScripts import LayerBlocker_InstancesBlockedInConfiguredArea as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LayerSpawner_InheritBehaviorFlag(self, request, workspace, editor, launcher_platform): - from .EditorScripts import LayerSpawner_InheritBehaviorFlag as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LayerSpawner_InstancesPlantInAllSupportedShapes(self, request, workspace, editor, launcher_platform): - from .EditorScripts import LayerSpawner_InstancesPlantInAllSupportedShapes as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_LayerSpawner_FilterStageToggle(self, request, workspace, editor, launcher_platform): - from .EditorScripts import LayerSpawner_FilterStageToggle as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/2038") - def test_LayerSpawner_InstancesRefreshUsingCorrectViewportCamera(self, request, workspace, editor, launcher_platform): - from .EditorScripts import LayerSpawner_InstancesRefreshUsingCorrectViewportCamera as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_MeshBlocker_InstancesBlockedByMesh(self, request, workspace, editor, launcher_platform): - from .EditorScripts import MeshBlocker_InstancesBlockedByMesh as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_MeshBlocker_InstancesBlockedByMeshHeightTuning(self, request, workspace, editor, launcher_platform): - from .EditorScripts import MeshBlocker_InstancesBlockedByMeshHeightTuning as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_MeshSurfaceTagEmitter_DependentOnMeshComponent(self, request, workspace, editor, launcher_platform): - from .EditorScripts import MeshSurfaceTagEmitter_DependentOnMeshComponent as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(self, request, workspace, editor, launcher_platform): - from .EditorScripts import MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_PhysXColliderSurfaceTagEmitter_E2E_Editor(self, request, workspace, editor, launcher_platform): - from .EditorScripts import PhysXColliderSurfaceTagEmitter_E2E_Editor as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets(self, request, workspace, editor, launcher_platform): - from .EditorScripts import PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_PositionModifier_AutoSnapToSurfaceWorks(self, request, workspace, editor, launcher_platform): - from .EditorScripts import PositionModifier_AutoSnapToSurfaceWorks as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_RotationModifier_InstancesRotateWithinRange(self, request, workspace, editor, launcher_platform): - from .EditorScripts import RotationModifier_InstancesRotateWithinRange as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_RotationModifierOverrides_InstancesRotateWithinRange(self, request, workspace, editor, launcher_platform): - from .EditorScripts import RotationModifierOverrides_InstancesRotateWithinRange as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_ScaleModifier_InstancesProperlyScale(self, request, workspace, editor, launcher_platform): - from .EditorScripts import ScaleModifier_InstancesProperlyScale as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_ScaleModifierOverrides_InstancesProperlyScale(self, request, workspace, editor, launcher_platform): - from .EditorScripts import ScaleModifierOverrides_InstancesProperlyScale as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_ShapeIntersectionFilter_InstancesPlantInAssignedShape(self, request, workspace, editor, launcher_platform): - from .EditorScripts import ShapeIntersectionFilter_InstancesPlantInAssignedShape as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_ShapeIntersectionFilter_FilterStageToggle(self, request, workspace, editor, launcher_platform): - from .EditorScripts import ShapeIntersectionFilter_FilterStageToggle as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_SlopeAlignmentModifier_InstanceSurfaceAlignment(self, request, workspace, editor, launcher_platform): - from .EditorScripts import SlopeAlignmentModifier_InstanceSurfaceAlignment as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment(self, request, workspace, editor, launcher_platform): - from .EditorScripts import SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_SurfaceMaskFilter_BasicSurfaceTagCreation(self, request, workspace, editor, launcher_platform): - from .EditorScripts import SurfaceMaskFilter_BasicSurfaceTagCreation as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_SurfaceMaskFilter_ExclusiveSurfaceTags_Function(self, request, workspace, editor, launcher_platform): - from .EditorScripts import SurfaceMaskFilter_ExclusionList as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_SurfaceMaskFilter_InclusiveSurfaceTags_Function(self, request, workspace, editor, launcher_platform): - from .EditorScripts import SurfaceMaskFilter_InclusionList as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected(self, request, workspace, editor, launcher_platform): - from .EditorScripts import SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_SystemSettings_SectorPointDensity(self, request, workspace, editor, launcher_platform): - from .EditorScripts import SystemSettings_SectorPointDensity as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_SystemSettings_SectorSize(self, request, workspace, editor, launcher_platform): - from .EditorScripts import SystemSettings_SectorSize as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes(self, request, workspace, editor, launcher_platform): - from .EditorScripts import SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlope as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - -@pytest.mark.SUITE_periodic -@pytest.mark.parametrize("project", ["AutomatedTesting"]) -@pytest.mark.parametrize("level", ["tmp_level"]) -class TestAutomationE2E(TestAutomationBase): - - # The following tests must run in order, please do not move tests out of order - - @pytest.mark.parametrize("launcher_platform", ['windows_editor']) - def test_DynamicSliceInstanceSpawner_Embedded_E2E_Editor(self, request, workspace, project, level, editor, launcher_platform): - # Ensure our test level does not already exist - file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True) - - from .EditorScripts import DynamicSliceInstanceSpawner_Embedded_E2E as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - @pytest.mark.parametrize("launcher_platform", ['windows']) - def test_DynamicSliceInstanceSpawner_Embedded_E2E_Launcher(self, workspace, launcher, level, - remote_console_instance, project, launcher_platform): - - expected_lines = [ - "Instances found in area = 400" - ] - - hydra.launch_and_validate_results_launcher(launcher, level, remote_console_instance, expected_lines, launch_ap=False) - - # Cleanup our temp level - file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True) - - @pytest.mark.parametrize("launcher_platform", ['windows_editor']) - def test_DynamicSliceInstanceSpawner_External_E2E_Editor(self, request, workspace, project, level, editor, launcher_platform): - # Ensure our test level does not already exist - file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True) - - from .EditorScripts import DynamicSliceInstanceSpawner_External_E2E as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - @pytest.mark.parametrize("launcher_platform", ['windows']) - def test_DynamicSliceInstanceSpawner_External_E2E_Launcher(self, workspace, launcher, level, - remote_console_instance, project, launcher_platform): - - expected_lines = [ - "Instances found in area = 400" - ] - - hydra.launch_and_validate_results_launcher(launcher, level, remote_console_instance, expected_lines, launch_ap=False) - - # Cleanup our temp level - file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True) - - @pytest.mark.parametrize("launcher_platform", ['windows_editor']) - def test_LayerBlender_E2E_Editor(self, request, workspace, project, level, editor, launcher_platform): - # Ensure our test level does not already exist - file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True) - - from .EditorScripts import LayerBlender_E2E_Editor as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - @pytest.mark.parametrize("launcher_platform", ['windows']) - @pytest.mark.xfail(reason="https://github.com/o3de/o3de/issues/4170") - def test_LayerBlender_E2E_Launcher(self, workspace, launcher, level, - remote_console_instance, project, launcher_platform): - - launcher.args.extend(["-rhi=Null"]) - launcher.start(launch_ap=False) - assert launcher.is_alive(), "Launcher failed to start" - - # Wait for test script to quit the launcher. If wait_for returns exc, test was not successful - waiter.wait_for(lambda: not launcher.is_alive(), timeout=300) - - # Verify launcher quit successfully and did not crash - ret_code = launcher.get_returncode() - assert ret_code == 0, "Test failed. See Game.log for details" - - # Cleanup our temp level - file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True) + class test_DynVegUtils_TempPrefabCreationWorks(EditorSharedTest): + from .EditorScripts import DynVegUtils_TempPrefabCreationWorks as test_module diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Periodic_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Periodic_Optimized.py deleted file mode 100644 index f87d6567ef..0000000000 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/TestSuite_Periodic_Optimized.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -Copyright (c) Contributors to the Open 3D Engine Project. -For complete copyright and license terms please see the LICENSE at the root of this distribution. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" - -import os -import pytest - -import ly_test_tools.environment.file_system as file_system -from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite - - -@pytest.mark.SUITE_main -@pytest.mark.parametrize("launcher_platform", ['windows_editor']) -@pytest.mark.parametrize("project", ["AutomatedTesting"]) -class TestAutomation(EditorTestSuite): - - global_extra_cmdline_args = ["-BatchMode", "-autotest_mode"] - - class test_DynVegUtils_TempPrefabCreationWorks(EditorSharedTest): - from .EditorScripts import DynVegUtils_TempPrefabCreationWorks as test_module diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientGenerators_Incompatibilities.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientGenerators_Incompatibilities.py index 09cd760647..6979ff1dee 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientGenerators_Incompatibilities.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientGenerators_Incompatibilities.py @@ -65,8 +65,7 @@ def GradientGenerators_Incompatibilities(): } # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # For every gradient generator component, verify that they are incompatible # which each vegetation area component diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientModifiers_Incompatibilities.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientModifiers_Incompatibilities.py index a4d9181744..962a0004f9 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientModifiers_Incompatibilities.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientModifiers_Incompatibilities.py @@ -74,8 +74,7 @@ def GradientModifiers_Incompatibilities(): } # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # For every gradient modifier component, verify that they are incompatible # which each vegetation area and gradient generator/modifier component diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin.py index 3749f93bf5..87f9e1a9b1 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin.py @@ -86,8 +86,7 @@ def GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin(): return entity # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # 2) Create entity with Random Noise gradient and verify gradient position after clearing pinned entity clear_entityid_check_position( diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_DefaultPinnedEntityIsSelf.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_DefaultPinnedEntityIsSelf.py index 3756452710..cd3fd7e1ee 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_DefaultPinnedEntityIsSelf.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_DefaultPinnedEntityIsSelf.py @@ -90,8 +90,7 @@ def GradientPreviewSettings_DefaultPinnedEntityIsSelf(): ] # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() for param in param_list: execute_test(param.required_components[param.accessed_component], diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSampling_GradientReferencesAddRemoveSuccessfully.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSampling_GradientReferencesAddRemoveSuccessfully.py index 8e85345a6f..f2980d9634 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSampling_GradientReferencesAddRemoveSuccessfully.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSampling_GradientReferencesAddRemoveSuccessfully.py @@ -61,8 +61,7 @@ def GradientSampling_GradientReferencesAddRemoveSuccessfully(): Report.result(gradient_cleared_from_modifier, entity.Equal(EntityId.EntityId())) # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # 2) Create a new entity with components "Random Noise Gradient", "Gradient Transform Modifier" and "Box Shape" entity_position = math.Vector3(125.0, 136.0, 32.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_ComponentDependencies.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_ComponentDependencies.py index f653515a39..0cc325efd1 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_ComponentDependencies.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_ComponentDependencies.py @@ -42,8 +42,7 @@ def GradientSurfaceTagEmitter_ComponentDependencies(): return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair) # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Create an entity with Gradient Surface Tag Emitter component position = math.Vector3(512.0, 512.0, 32.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py index 90840a135d..cf48096a31 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully.py @@ -36,8 +36,7 @@ def GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(): from editor_python_test_tools.utils import TestHelper as helper # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # 2) Create an entity with Gradient Surface Tag Emitter and Reference Gradient components. entity_position = math.Vector3(125.0, 136.0, 32.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithExpectedGradients.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithExpectedGradients.py index 5e6df4d52f..27ef248d6c 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithExpectedGradients.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithExpectedGradients.py @@ -46,8 +46,7 @@ def GradientTransform_ComponentIncompatibleWithExpectedGradients(): return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair) # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # 2) Create a new entity with components Gradient Transform Modifier and Box Shape entity_position = math.Vector3(125.0, 136.0, 32.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithSpawners.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithSpawners.py index fd65996fdd..9c23cdea75 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithSpawners.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_ComponentIncompatibleWithSpawners.py @@ -44,8 +44,7 @@ def GradientTransform_ComponentIncompatibleWithSpawners(): return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", EntityComponentIdPair) # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # 2) Create a new entity with components Gradient Transform Modifier and Box Shape entity_position = math.Vector3(125.0, 136.0, 32.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange.py index 530503db86..6d6911ff3a 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange.py @@ -54,8 +54,7 @@ def GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange(): from editor_python_test_tools.utils import TestHelper as helper # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # 2) Create entity entity_position = math.Vector3(125.0, 136.0, 32.0) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_RequiresShape.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_RequiresShape.py index 09cce359d5..ec142f92d2 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_RequiresShape.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_RequiresShape.py @@ -47,8 +47,7 @@ def GradientTransform_RequiresShape(): from editor_python_test_tools.utils import TestHelper as helper # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Create a new Entity in the level entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_ProcessedImageAssignedSuccessfully.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_ProcessedImageAssignedSuccessfully.py index 42458665e1..afe0893da9 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_ProcessedImageAssignedSuccessfully.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_ProcessedImageAssignedSuccessfully.py @@ -56,8 +56,7 @@ def ImageGradient_ProcessedImageAssignedSuccessfully(): from editor_python_test_tools.utils import TestHelper as helper # 1) Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # 2) Create an entity with Image Gradient and Gradient Transform Modifier components components_to_add = ["Image Gradient", "Gradient Transform Modifier", "Box Shape"] diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_RequiresShape.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_RequiresShape.py index 3b832d160a..85582d198a 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_RequiresShape.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_RequiresShape.py @@ -47,8 +47,7 @@ def ImageGradient_RequiresShape(): from editor_python_test_tools.utils import TestHelper as helper # Open an existing simple level - helper.init_idle() - helper.open_level("Physics", "Base") + hydra.open_base_level() # Create a new Entity in the level entity_id = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId()) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic.py index 3ad27eb973..d4199c31f6 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic.py @@ -5,67 +5,51 @@ For complete copyright and license terms please see the LICENSE at the root of t SPDX-License-Identifier: Apache-2.0 OR MIT """ -import os import pytest -import sys -sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../automatedtesting_shared') -from base import TestAutomationBase +from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite @pytest.mark.SUITE_periodic @pytest.mark.parametrize("launcher_platform", ['windows_editor']) @pytest.mark.parametrize("project", ["AutomatedTesting"]) -class TestAutomation(TestAutomationBase): +class TestAutomation(EditorTestSuite): - def test_GradientGenerators_Incompatibilities(self, request, workspace, editor, launcher_platform): + class test_GradientGenerators_Incompatibilities(EditorSharedTest): from .EditorScripts import GradientGenerators_Incompatibilities as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - def test_GradientModifiers_Incompatibilities(self, request, workspace, editor, launcher_platform): + class test_GradientModifiers_Incompatibilities(EditorSharedTest): from .EditorScripts import GradientModifiers_Incompatibilities as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - def test_GradientPreviewSettings_DefaultPinnedEntityIsSelf(self, request, workspace, editor, launcher_platform): - from .EditorScripts import GradientPreviewSettings_DefaultPinnedEntityIsSelf as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin(self, request, workspace, editor, launcher_platform): + class test_GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin(EditorSharedTest): from .EditorScripts import GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - def test_GradientSampling_GradientReferencesAddRemoveSuccessfully(self, request, workspace, editor, launcher_platform): + class test_GradientPreviewSettings_DefaultPinnedEntityIsSelf(EditorSharedTest): + from .EditorScripts import GradientPreviewSettings_DefaultPinnedEntityIsSelf as test_module + + class test_GradientSampling_GradientReferencesAddRemoveSuccessfully(EditorSharedTest): from .EditorScripts import GradientSampling_GradientReferencesAddRemoveSuccessfully as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - def test_GradientSurfaceTagEmitter_ComponentDependencies(self, request, workspace, editor, launcher_platform): + class test_GradientSurfaceTagEmitter_ComponentDependencies(EditorSharedTest): from .EditorScripts import GradientSurfaceTagEmitter_ComponentDependencies as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - def test_GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(self, request, workspace, editor, launcher_platform): + class test_GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(EditorSharedTest): from .EditorScripts import GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - def test_GradientTransform_RequiresShape(self, request, workspace, editor, launcher_platform): - from .EditorScripts import GradientTransform_RequiresShape as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange(self, request, workspace, editor, launcher_platform): - from .EditorScripts import GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_GradientTransform_ComponentIncompatibleWithSpawners(self, request, workspace, editor, launcher_platform): - from .EditorScripts import GradientTransform_ComponentIncompatibleWithSpawners as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - - def test_GradientTransform_ComponentIncompatibleWithExpectedGradients(self, request, workspace, editor, launcher_platform): + class test_GradientTransform_ComponentIncompatibleWithExpectedGradients(EditorSharedTest): from .EditorScripts import GradientTransform_ComponentIncompatibleWithExpectedGradients as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) - def test_ImageGradient_RequiresShape(self, request, workspace, editor, launcher_platform): - from .EditorScripts import ImageGradient_RequiresShape as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) + class test_GradientTransform_ComponentIncompatibleWithSpawners(EditorSharedTest): + from .EditorScripts import GradientTransform_ComponentIncompatibleWithSpawners as test_module - def test_ImageGradient_ProcessedImageAssignedSuccessfully(self, request, workspace, editor, launcher_platform): + class test_GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange(EditorSharedTest): + from .EditorScripts import GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange as test_module + + class test_GradientTransform_RequiresShape(EditorSharedTest): + from .EditorScripts import GradientTransform_RequiresShape as test_module + + class test_ImageGradient_ProcessedImageAssignedSuccessfully(EditorSharedTest): from .EditorScripts import ImageGradient_ProcessedImageAssignedSuccessfully as test_module - self._run_test(request, workspace, editor, test_module, enable_prefab_system=False) + + class test_ImageGradient_RequiresShape(EditorSharedTest): + from .EditorScripts import ImageGradient_RequiresShape as test_module diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic_Optimized.py deleted file mode 100644 index 6ac0658b4d..0000000000 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic_Optimized.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Copyright (c) Contributors to the Open 3D Engine Project. -For complete copyright and license terms please see the LICENSE at the root of this distribution. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" - -import pytest - -from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite - - -@pytest.mark.SUITE_periodic -@pytest.mark.parametrize("launcher_platform", ['windows_editor']) -@pytest.mark.parametrize("project", ["AutomatedTesting"]) -class TestAutomation(EditorTestSuite): - - enable_prefab_system = False - - class test_GradientGenerators_Incompatibilities(EditorSharedTest): - from .EditorScripts import GradientGenerators_Incompatibilities as test_module - - class test_GradientModifiers_Incompatibilities(EditorSharedTest): - from .EditorScripts import GradientModifiers_Incompatibilities as test_module - - class test_GradientPreviewSettings_DefaultPinnedEntityIsSelf(EditorSharedTest): - from .EditorScripts import GradientPreviewSettings_DefaultPinnedEntityIsSelf as test_module - - class test_GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin(EditorSharedTest): - from .EditorScripts import GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin as test_module - - class test_GradientSampling_GradientReferencesAddRemoveSuccessfully(EditorSharedTest): - from .EditorScripts import GradientSampling_GradientReferencesAddRemoveSuccessfully as test_module - - class test_GradientSurfaceTagEmitter_ComponentDependencies(EditorSharedTest): - from .EditorScripts import GradientSurfaceTagEmitter_ComponentDependencies as test_module - - class test_GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(EditorSharedTest): - from .EditorScripts import GradientSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully as test_module - - class test_GradientTransform_RequiresShape(EditorSharedTest): - from .EditorScripts import GradientTransform_RequiresShape as test_module - - class test_GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange(EditorSharedTest): - from .EditorScripts import GradientTransform_FrequencyZoomCanBeSetBeyondSliderRange as test_module - - class test_GradientTransform_ComponentIncompatibleWithSpawners(EditorSharedTest): - from .EditorScripts import GradientTransform_ComponentIncompatibleWithSpawners as test_module - - class test_GradientTransform_ComponentIncompatibleWithExpectedGradients(EditorSharedTest): - from .EditorScripts import GradientTransform_ComponentIncompatibleWithExpectedGradients as test_module - - class test_ImageGradient_RequiresShape(EditorSharedTest): - from .EditorScripts import ImageGradient_RequiresShape as test_module - - class test_ImageGradient_ProcessedImageAssignedSuccessfully(EditorSharedTest): - from .EditorScripts import ImageGradient_ProcessedImageAssignedSuccessfully as test_module diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py b/AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py index 37afeff8c0..fd6a907b2e 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py @@ -114,7 +114,8 @@ def create_dynamic_slice_vegetation_area(name, center_point, box_size_x, box_siz return spawner_entity -def create_prefab_vegetation_area(name, center_point, box_size_x, box_size_y, box_size_z, target_prefab): +def create_temp_prefab_vegetation_area(name, center_point, box_size_x, box_size_y, box_size_z, target_prefab): + """Creates a vegetation area using in-memory prefabs. Use when test is solely contained to Editor""" # Create a vegetation area entity to use as our test vegetation spawner spawner_entity = hydra.Entity(name) spawner_entity.create_entity( @@ -148,6 +149,31 @@ def create_prefab_vegetation_area(name, center_point, box_size_x, box_size_y, bo return spawner_entity +def create_prefab_vegetation_area(name, center_point, box_size_x, box_size_y, box_size_z, prefab_path): + """Creates a vegetation area using on-disk spawnable prefabs. Use when test requires saving/loading in Launcher""" + # Create a vegetation area entity to use as our test vegetation spawner + prefab_asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", prefab_path, math.Uuid(), + False) + spawner_entity = hydra.Entity(name) + spawner_entity.create_entity( + center_point, + ["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"] + ) + if spawner_entity.id.IsValid(): + print(f"'{spawner_entity.name}' created") + spawner_entity.get_set_test(1, "Box Shape|Box Configuration|Dimensions", math.Vector3(box_size_x, box_size_y, + box_size_z)) + + # Set the vegetation area to a prefab instance spawner with a specific prefab asset selected + descriptor = hydra.get_component_property_value(spawner_entity.components[2], + 'Configuration|Embedded Assets|[0]') + prefab_spawner = vegetation.PrefabInstanceSpawner() + prefab_spawner.SetPrefabAssetId(prefab_asset_id) + descriptor.spawner = prefab_spawner + spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor) + return spawner_entity + + def create_blocker_area(name, center_point, box_size_x, box_size_y, box_size_z): # Create a Vegetation Layer Blocker area blocker_entity = hydra.Entity(name) @@ -162,6 +188,23 @@ def create_blocker_area(name, center_point, box_size_x, box_size_y, box_size_z): return blocker_entity +def create_empty_vegetation_area(name, center_point, box_size_x, box_size_y, box_size_z): + # Create a vegetation area entity to use as our test vegetation spawner + spawner_entity = EditorEntity.create_editor_entity_at(center_point, name=name) + spawner_entity.add_components(["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"]) + if spawner_entity.id.IsValid(): + print(f"'{spawner_entity.get_name()}' created") + spawner_entity.components[1].set_component_property_value("Box Shape|Box Configuration|Dimensions", + math.Vector3(box_size_x, box_size_y, box_size_z)) + + # Set the vegetation area to an empty spawner + empty_spawner = vegetation.EmptyInstanceSpawner() + descriptor = spawner_entity.components[2].get_component_property_value("Configuration|Embedded Assets|[0]") + descriptor.spawner = empty_spawner + spawner_entity.components[2].set_component_property_value("Configuration|Embedded Assets|[0]", descriptor) + return spawner_entity + + def validate_instance_count(center, radius, num_expected): # Verify that we have the correct number of instances in the given area. This creates a bounding box based on a # sphere radius diff --git a/AutomatedTesting/ScriptCanvas/instance_counter.scriptcanvas b/AutomatedTesting/ScriptCanvas/instance_counter.scriptcanvas index 0e5524273c..4ef5f0a8d5 100644 --- a/AutomatedTesting/ScriptCanvas/instance_counter.scriptcanvas +++ b/AutomatedTesting/ScriptCanvas/instance_counter.scriptcanvas @@ -5,7 +5,7 @@ "ClassData": { "m_scriptCanvas": { "Id": { - "id": 3744110453276 + "id": 337666590525276931 }, "Name": "instance_counter", "Components": { @@ -87,7 +87,6 @@ ], "Datums": [ { - "isOverloadedStorage": false, "scriptCanvasType": { "m_type": 3 }, @@ -228,7 +227,6 @@ ], "Datums": [ { - "isOverloadedStorage": false, "scriptCanvasType": { "m_type": 1 }, @@ -237,7 +235,7 @@ "value": { "id": 2901262558 }, - "label": "Source" + "label": "EntityID: 0" } ], "methodType": 0, @@ -340,7 +338,6 @@ ], "Datums": [ { - "isOverloadedStorage": false, "scriptCanvasType": { "m_type": 3 }, @@ -587,26 +584,10 @@ "m_assetType": "{3E2AC8CD-713F-453E-967F-29517F331784}", "versionData": { "_grammarVersion": 1, - "_runtimeVersion": 1 + "_runtimeVersion": 1, + "_fileVersion": 1 }, "GraphCanvasData": [ - { - "Key": { - "id": 3744110453276 - }, - "Value": { - "ComponentData": { - "{5F84B500-8C45-40D1-8EFC-A5306B241444}": { - "$type": "SceneComponentSaveData", - "ViewParams": { - "Scale": 0.9218543514249998, - "AnchorX": 50.98419189453125, - "AnchorY": -272.27728271484375 - } - } - } - } - }, { "Key": { "id": 3748405420572 @@ -757,6 +738,18 @@ } } } + }, + { + "Key": { + "id": 337666590525276931 + }, + "Value": { + "ComponentData": { + "{5F84B500-8C45-40D1-8EFC-A5306B241444}": { + "$type": "SceneComponentSaveData" + } + } + } } ], "StatisticsHelper": { From 3e5c1cee1eca80e6678e4e097bd22cf9ca28d035 Mon Sep 17 00:00:00 2001 From: santorac <55155825+santorac@users.noreply.github.com> Date: Fri, 21 Jan 2022 11:56:32 -0800 Subject: [PATCH 077/136] Fixed a place where GetFullName was still being used. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com> --- .../MaterialEditor/Code/Source/Document/MaterialDocument.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 8f25e41827..2a0d91d0ad 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -595,7 +595,7 @@ namespace MaterialEditor MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue()); if (propertyValue.IsValid()) { - if (!AtomToolsFramework::ConvertToExportFormat(exportPath, propertyId.GetFullName(), propertyDefinition, propertyValue)) + if (!AtomToolsFramework::ConvertToExportFormat(exportPath, propertyId, propertyDefinition, propertyValue)) { AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetCStr(), m_absolutePath.c_str()); result = false; From b21878d04e78e02f430c660b4cc9c9c5bda361a8 Mon Sep 17 00:00:00 2001 From: Sergey Pereslavtsev Date: Fri, 21 Jan 2022 19:57:28 +0000 Subject: [PATCH 078/136] Removed unused variable Signed-off-by: Sergey Pereslavtsev --- .../PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Gems/PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp b/Gems/PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp index 9a216b7d80..5f830acc8a 100644 --- a/Gems/PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp +++ b/Gems/PhysX/Code/Tests/EditorHeightfieldColliderComponentTests.cpp @@ -343,7 +343,6 @@ namespace PhysXEditorTests for (int sampleColumn = 0; sampleColumn < numColumns; ++sampleColumn) { physx::PxHeightFieldSample samplePhysX = heightfield->getSample(sampleRow, sampleColumn); - Physics::HeightMaterialPoint samplePhysics = samples[sampleRow * numColumns + sampleColumn]; auto [materialIndex0, materialIndex1] = PhysX::Utils::GetPhysXMaterialIndicesFromHeightfieldSamples(samples, sampleRow, sampleColumn, numRows, numColumns); EXPECT_EQ(samplePhysX.materialIndex0, materialIndex0); From a8d97cf8aa39f515c2f801e7959fdf163edcb866 Mon Sep 17 00:00:00 2001 From: michabr <82236305+michabr@users.noreply.github.com> Date: Fri, 21 Jan 2022 12:02:20 -0800 Subject: [PATCH 079/136] Fix hi-res display issues in UI Editor (#6912) * Fix dpi scaling issues in UI Editor Signed-off-by: abrmich * Remove older method for getting dpi scaling factor Signed-off-by: abrmich * Remove direct call to devicePixelRatioF() Signed-off-by: abrmich * Use existing convenience function Signed-off-by: abrmich * Fix one more text size Signed-off-by: abrmich * Fix compile warning Signed-off-by: abrmich * Remove unnecessary typecast Signed-off-by: abrmich --- Gems/LyShine/Code/Editor/GuideHelpers.cpp | 5 +- Gems/LyShine/Code/Editor/QtHelpers.cpp | 14 ---- Gems/LyShine/Code/Editor/QtHelpers.h | 5 -- Gems/LyShine/Code/Editor/RulerWidget.cpp | 17 ++++- Gems/LyShine/Code/Editor/ViewportHelpers.cpp | 6 +- Gems/LyShine/Code/Editor/ViewportIcon.cpp | 2 +- .../Code/Editor/ViewportInteraction.cpp | 39 +++++----- .../LyShine/Code/Editor/ViewportInteraction.h | 2 +- Gems/LyShine/Code/Editor/ViewportWidget.cpp | 71 ++++++++++++------- Gems/LyShine/Code/Editor/ViewportWidget.h | 13 ++-- 10 files changed, 97 insertions(+), 77 deletions(-) diff --git a/Gems/LyShine/Code/Editor/GuideHelpers.cpp b/Gems/LyShine/Code/Editor/GuideHelpers.cpp index b6d7acc57a..0713782063 100644 --- a/Gems/LyShine/Code/Editor/GuideHelpers.cpp +++ b/Gems/LyShine/Code/Editor/GuideHelpers.cpp @@ -134,7 +134,7 @@ namespace GuideHelpers AZ::Matrix4x4 transform; EBUS_EVENT_ID_RESULT(transform, canvasEntityId, UiCanvasBus, GetCanvasToViewportMatrix); - AZ::Vector2 viewportSize(aznumeric_cast(viewport->size().width()), aznumeric_cast(viewport->size().height())); + AZ::Vector2 viewportSize = viewport->GetRenderViewportSize(); AZ::Color guideColor; EBUS_EVENT_ID_RESULT(guideColor, canvasEntityId, UiEditorCanvasBus, GetGuideColor); @@ -167,8 +167,7 @@ namespace GuideHelpers void DrawGhostGuideLine(Draw2dHelper& draw2d, AZ::EntityId canvasEntityId, bool guideIsVertical, ViewportWidget* viewport, const AZ::Vector2& canvasPoint) { AZ::Vector2 viewportPoint = CanvasHelpers::GetViewportPoint(canvasEntityId, canvasPoint); - - AZ::Vector2 viewportSize(aznumeric_cast(viewport->size().width()), aznumeric_cast(viewport->size().height())); + AZ::Vector2 viewportSize = viewport->GetRenderViewportSize(); // the line is drawn as the inverse of the background color AZ::Color guideColor(1.0f, 1.0f, 1.0f, 1.0f); diff --git a/Gems/LyShine/Code/Editor/QtHelpers.cpp b/Gems/LyShine/Code/Editor/QtHelpers.cpp index d9147463ed..3b38894016 100644 --- a/Gems/LyShine/Code/Editor/QtHelpers.cpp +++ b/Gems/LyShine/Code/Editor/QtHelpers.cpp @@ -29,18 +29,4 @@ namespace QtHelpers bool inWidget = (localPos.x() >= 0 && localPos.x() < size.width() && localPos.y() >= 0 && localPos.y() < size.height()); return inWidget; } - - float GetHighDpiScaleFactor(const QWidget& widget) - { - return static_cast(QHighDpiScaling::factor(widget.windowHandle()->screen())); - } - - QSize GetDpiScaledViewportSize(const QWidget& widget) - { - float dpiScale = GetHighDpiScaleFactor(widget); - float width = ceilf(widget.size().width() * dpiScale); - float height = ceilf(widget.size().height() * dpiScale); - return QSize(static_cast(width), static_cast(height)); - } - } // namespace QtHelpers diff --git a/Gems/LyShine/Code/Editor/QtHelpers.h b/Gems/LyShine/Code/Editor/QtHelpers.h index 4a9e7091ff..1b5f561871 100644 --- a/Gems/LyShine/Code/Editor/QtHelpers.h +++ b/Gems/LyShine/Code/Editor/QtHelpers.h @@ -16,9 +16,4 @@ namespace QtHelpers AZ::Vector2 MapGlobalPosToLocalVector2(const QWidget* widget, const QPoint& pos); bool IsGlobalPosInWidget(const QWidget* widget, const QPoint& pos); - - float GetHighDpiScaleFactor(const QWidget& widget); - - QSize GetDpiScaledViewportSize(const QWidget& widget); - } // namespace QtHelpers diff --git a/Gems/LyShine/Code/Editor/RulerWidget.cpp b/Gems/LyShine/Code/Editor/RulerWidget.cpp index 0a9209ba38..c82a64ac14 100644 --- a/Gems/LyShine/Code/Editor/RulerWidget.cpp +++ b/Gems/LyShine/Code/Editor/RulerWidget.cpp @@ -61,6 +61,14 @@ void RulerWidget::paintEvent([[maybe_unused]] QPaintEvent* event) float scale = translationAndScale.scale; float translation = (m_orientation == Orientation::Horizontal) ? translationAndScale.translation.GetX() : translationAndScale.translation.GetY(); + // Convert back to qt widget coords for painting + float dpiScaleFactor = m_editorWindow->GetViewport()->WidgetToViewportFactor(); + if (dpiScaleFactor != 0.0f) + { + scale /= dpiScaleFactor; + translation /= dpiScaleFactor; + } + // If the viewport is really small then scale can be zero (or very close) which would cause a divide by zero in later math so we just don't paint anything const float epsilon = 0.00001f; if (scale < epsilon) @@ -87,7 +95,9 @@ void RulerWidget::paintEvent([[maybe_unused]] QPaintEvent* event) void RulerWidget::mousePressEvent(QMouseEvent* ev) { // start a drag interaction to create a guide - AZ::Vector2 viewportMousePos = QtHelpers::MapGlobalPosToLocalVector2(m_editorWindow->GetViewport(), ev->globalPos()); + AZ::Vector2 localMousePos = QtHelpers::MapGlobalPosToLocalVector2(m_editorWindow->GetViewport(), ev->globalPos()); + float dpiScaleFactor = m_editorWindow->GetViewport()->WidgetToViewportFactor(); + AZ::Vector2 viewportMousePos = localMousePos * dpiScaleFactor; bool isVertical = m_orientation == Orientation::Vertical; m_dragInteraction = new ViewportAddGuideInteraction(m_editorWindow, m_editorWindow->GetCanvas(), isVertical, viewportMousePos); } @@ -98,7 +108,10 @@ void RulerWidget::mouseMoveEvent(QMouseEvent* ev) // We only get the events if the mouse is pressed down. So we only get here when adding a ruler. if (m_dragInteraction) { - AZ::Vector2 viewportMousePos = QtHelpers::MapGlobalPosToLocalVector2(m_editorWindow->GetViewport(), ev->globalPos()); + AZ::Vector2 localMousePos = QtHelpers::MapGlobalPosToLocalVector2(m_editorWindow->GetViewport(), ev->globalPos()); + float dpiScaleFactor = m_editorWindow->GetViewport()->WidgetToViewportFactor(); + AZ::Vector2 viewportMousePos = localMousePos * dpiScaleFactor; + m_dragInteraction->Update(viewportMousePos); } diff --git a/Gems/LyShine/Code/Editor/ViewportHelpers.cpp b/Gems/LyShine/Code/Editor/ViewportHelpers.cpp index 7d81a12477..ee89b213ef 100644 --- a/Gems/LyShine/Code/Editor/ViewportHelpers.cpp +++ b/Gems/LyShine/Code/Editor/ViewportHelpers.cpp @@ -336,7 +336,7 @@ namespace ViewportHelpers draw2d.SetTextAlignment(IDraw2d::HAlign::Center, IDraw2d::VAlign::Bottom); draw2d.SetTextRotation(0.0f); - draw2d.DrawText(rotationString.toUtf8().data(), rotationStringPos, GetDpiScaledSize(16.0f), 1.0f); + draw2d.DrawText(rotationString.toUtf8().data(), rotationStringPos, 8.0f, 1.0f); } } @@ -347,9 +347,11 @@ namespace ViewportHelpers const AZ::Vector2 textLabelOffset(10.0f, -10.0f); QPoint viewportCursorPos = viewport->mapFromGlobal(QCursor::pos()); AZ::Vector2 textPos = AZ::Vector2(aznumeric_cast(viewportCursorPos.x()), aznumeric_cast(viewportCursorPos.y())) + textLabelOffset; + float dpiScale = viewport->WidgetToViewportFactor(); + textPos *= dpiScale; draw2d.SetTextAlignment(IDraw2d::HAlign::Left, IDraw2d::VAlign::Bottom); draw2d.SetTextRotation(0.0f); - draw2d.DrawText(textLabel.c_str(), textPos, GetDpiScaledSize(16.0f), 1.0f); + draw2d.DrawText(textLabel.c_str(), textPos, 8.0f, 1.0f); } } // namespace ViewportHelpers diff --git a/Gems/LyShine/Code/Editor/ViewportIcon.cpp b/Gems/LyShine/Code/Editor/ViewportIcon.cpp index 33f2f40ffe..bdbad6afb2 100644 --- a/Gems/LyShine/Code/Editor/ViewportIcon.cpp +++ b/Gems/LyShine/Code/Editor/ViewportIcon.cpp @@ -296,7 +296,7 @@ void ViewportIcon::DrawDistanceLine(Draw2dHelper& draw2d, AZ::Vector2 start, AZ: draw2d.SetTextAlignment(IDraw2d::HAlign::Center, IDraw2d::VAlign::Bottom); draw2d.SetTextRotation(rotation); - draw2d.DrawText(textBuf, textPos, 16.0f * ViewportIcon::GetDpiScaleFactor(), 1.0f); + draw2d.DrawText(textBuf, textPos, 8.0f, 1.0f); } void ViewportIcon::DrawAnchorLinesSplit(Draw2dHelper& draw2d, AZ::Vector2 anchorPos1, AZ::Vector2 anchorPos2, diff --git a/Gems/LyShine/Code/Editor/ViewportInteraction.cpp b/Gems/LyShine/Code/Editor/ViewportInteraction.cpp index a39a7b9cac..7bd55be4bc 100644 --- a/Gems/LyShine/Code/Editor/ViewportInteraction.cpp +++ b/Gems/LyShine/Code/Editor/ViewportInteraction.cpp @@ -674,13 +674,13 @@ void ViewportInteraction::MouseReleaseEvent(QMouseEvent* ev, { // test to see if the mouse position is inside the viewport on each axis const QPoint& pos = ev->pos(); - const QSize& size = m_editorWindow->GetViewport()->size(); + const AZ::Vector2 size = m_editorWindow->GetViewport()->GetRenderViewportSize(); ViewportDragInteraction::EndState inWidget; - if (pos.x() >= 0 && pos.x() < size.width()) - inWidget = pos.y() >= 0 && pos.y() < size.height() ? ViewportDragInteraction::EndState::Inside : ViewportDragInteraction::EndState::OutsideY; + if (pos.x() >= 0 && pos.x() < size.GetX()) + inWidget = pos.y() >= 0 && pos.y() < size.GetY() ? ViewportDragInteraction::EndState::Inside : ViewportDragInteraction::EndState::OutsideY; else - inWidget = pos.y() >= 0 && pos.y() < size.height() ? ViewportDragInteraction::EndState::OutsideX : ViewportDragInteraction::EndState::OutsideXY; + inWidget = pos.y() >= 0 && pos.y() < size.GetY() ? ViewportDragInteraction::EndState::OutsideX : ViewportDragInteraction::EndState::OutsideXY; // Some interactions end differently depending on whether the mouse was released inside or outside the viewport m_dragInteraction->EndInteraction(inWidget); @@ -709,12 +709,12 @@ void ViewportInteraction::MouseReleaseEvent(QMouseEvent* ev, UpdateCursor(); } -void ViewportInteraction::MouseWheelEvent(QWheelEvent* ev) +bool ViewportInteraction::MouseWheelEvent(QWheelEvent* ev) { if (m_leftButtonIsActive || m_middleButtonIsActive) { // Ignore event. - return; + return false; } const QPoint numDegrees(ev->angleDelta()); @@ -735,6 +735,8 @@ void ViewportInteraction::MouseWheelEvent(QWheelEvent* ev) SetCanvasToViewportScale(QuantizeZoomScale(newScale), &pivotPoint); } + + return true; } bool ViewportInteraction::KeyPressEvent(QKeyEvent* ev) @@ -921,27 +923,27 @@ void ViewportInteraction::GetScaleToFitTransformProps(const AZ::Vector2* newCanv EBUS_EVENT_ID_RESULT(canvasSize, m_editorWindow->GetCanvas(), UiCanvasBus, GetCanvasSize); } - QSize viewportSize = QtHelpers::GetDpiScaledViewportSize(*m_editorWindow->GetViewport()); - const int viewportWidth = viewportSize.width(); - const int viewportHeight = viewportSize.height(); + AZ::Vector2 viewportSize = m_editorWindow->GetViewport()->GetRenderViewportSize(); + const float viewportWidth = viewportSize.GetX(); + const float viewportHeight = viewportSize.GetY(); // We pad the edges of the viewport to allow the user to easily see the borders of // the canvas edges, which is especially helpful if there are anchors sitting on // the edges of the canvas. static const int canvasBorderPaddingInPixels = 32; AZ::Vector2 viewportPaddedSize( - aznumeric_cast(viewportWidth - canvasBorderPaddingInPixels), - aznumeric_cast(viewportHeight - canvasBorderPaddingInPixels)); + viewportWidth - canvasBorderPaddingInPixels, + viewportHeight - canvasBorderPaddingInPixels); // Guard against very small viewports if (viewportPaddedSize.GetX() <= 0.0f) { - viewportPaddedSize.SetX(aznumeric_cast(viewportWidth)); + viewportPaddedSize.SetX(viewportWidth); } if (viewportPaddedSize.GetY() <= 0.0f) { - viewportPaddedSize.SetY(aznumeric_cast(viewportHeight)); + viewportPaddedSize.SetY(viewportHeight); } // Use a "scale to fit" approach @@ -949,8 +951,8 @@ void ViewportInteraction::GetScaleToFitTransformProps(const AZ::Vector2* newCanv viewportPaddedSize.GetX() / canvasSize.GetX(), viewportPaddedSize.GetY() / canvasSize.GetY()); - const int scaledCanvasWidth = static_cast(canvasSize.GetX() * canvasToViewportScale); - const int scaledCanvasHeight = static_cast(canvasSize.GetY() * canvasToViewportScale); + const float scaledCanvasWidth = canvasSize.GetX() * canvasToViewportScale; + const float scaledCanvasHeight = canvasSize.GetY() * canvasToViewportScale; // Centers the canvas within the viewport propsOut.translation = AZ::Vector3( @@ -1008,9 +1010,12 @@ void ViewportInteraction::SetCanvasToViewportScale(float newScale, Vec2i* option } else { + AZ::Vector2 viewportSize = m_editorWindow->GetViewport()->GetRenderViewportSize(); + const float viewportWidth = viewportSize.GetX(); + const float viewportHeight = viewportSize.GetY(); pivotPoint = Vec2i( - static_cast(m_editorWindow->GetViewport()->size().width() * 0.5f), - static_cast(m_editorWindow->GetViewport()->size().height() * 0.5f)); + static_cast(viewportWidth * 0.5f), + static_cast(viewportHeight * 0.5f)); } // Get the distance between our pivot point and the upper-left corner of the diff --git a/Gems/LyShine/Code/Editor/ViewportInteraction.h b/Gems/LyShine/Code/Editor/ViewportInteraction.h index a104d87634..b6417977ab 100644 --- a/Gems/LyShine/Code/Editor/ViewportInteraction.h +++ b/Gems/LyShine/Code/Editor/ViewportInteraction.h @@ -77,7 +77,7 @@ public: // member functions const QTreeWidgetItemRawPtrQList& selectedItems); void MouseReleaseEvent(QMouseEvent* ev, const QTreeWidgetItemRawPtrQList& selectedItems); - void MouseWheelEvent(QWheelEvent* ev); + bool MouseWheelEvent(QWheelEvent* ev); bool KeyPressEvent(QKeyEvent* ev); bool KeyReleaseEvent(QKeyEvent* ev); diff --git a/Gems/LyShine/Code/Editor/ViewportWidget.cpp b/Gems/LyShine/Code/Editor/ViewportWidget.cpp index b481e9cbf1..eb5625ac31 100644 --- a/Gems/LyShine/Code/Editor/ViewportWidget.cpp +++ b/Gems/LyShine/Code/Editor/ViewportWidget.cpp @@ -351,6 +351,17 @@ void ViewportWidget::SetRedrawEnabled(bool enabled) m_canvasRenderIsEnabled = enabled; } +AZ::Vector2 ViewportWidget::GetRenderViewportSize() const +{ + AZ::Vector2 widgetSize(aznumeric_cast(size().width()), aznumeric_cast(size().height())); + return widgetSize * WidgetToViewportFactor(); +} + +float ViewportWidget::WidgetToViewportFactor() const +{ + return GetViewportContext()->GetDpiScalingFactor(); +} + void ViewportWidget::PickItem(AZ::EntityId entityId) { AzToolsFramework::EditorPickModeRequestBus::Broadcast( @@ -496,7 +507,7 @@ void ViewportWidget::OnRenderTick() return; } - const float dpiScale = QtHelpers::GetHighDpiScaleFactor(*this); + const float dpiScale = WidgetToViewportFactor(); ViewportIcon::SetDpiScaleFactor(dpiScale); UiEditorMode editorMode = m_editorWindow->GetEditorMode(); @@ -510,6 +521,12 @@ void ViewportWidget::OnRenderTick() } } +//////////////////////////////////////////////////////////////////////////////////////////////////// +void ViewportWidget::OnViewportDpiScalingChanged(float dpiScale) +{ + ViewportIcon::SetDpiScaleFactor(dpiScale); +} + void ViewportWidget::RefreshTick() { #ifdef LYSHINE_EDITOR_TODO // still need this? @@ -640,27 +657,34 @@ void ViewportWidget::mouseReleaseEvent(QMouseEvent* ev) void ViewportWidget::wheelEvent(QWheelEvent* ev) { + bool handled = false; UiEditorMode editorMode = m_editorWindow->GetEditorMode(); - QWheelEvent scaledEvent( - WidgetToViewport(ev->position()), - ev->globalPosition(), - ev->pixelDelta(), - ev->angleDelta(), - ev->buttons(), - ev->modifiers(), - ev->phase(), - ev->inverted() - ); - if (editorMode == UiEditorMode::Edit) { + QWheelEvent scaledEvent( + WidgetToViewport(ev->position()), + ev->globalPosition(), + ev->pixelDelta(), + ev->angleDelta(), + ev->buttons(), + ev->modifiers(), + ev->phase(), + ev->inverted() + ); + // in Edit mode just send input to ViewportInteraction - m_viewportInteraction->MouseWheelEvent(&scaledEvent); + handled = m_viewportInteraction->MouseWheelEvent(&scaledEvent); } - RenderViewportWidget::wheelEvent(ev); - - Refresh(); + if (handled) + { + ev->accept(); + Refresh(); + } + else + { + RenderViewportWidget::wheelEvent(ev); + } } bool ViewportWidget::eventFilter([[maybe_unused]] QObject* watched, QEvent* event) @@ -975,8 +999,7 @@ void ViewportWidget::RenderEditMode() EBUS_EVENT_ID(canvasEntityId, UiCanvasBus, SetTargetCanvasSize, false, canvasSize); // Render this canvas - QSize scaledViewportSize = QtHelpers::GetDpiScaledViewportSize(*this); - AZ::Vector2 viewportSize(static_cast(scaledViewportSize.width()), static_cast(scaledViewportSize.height())); + AZ::Vector2 viewportSize = GetRenderViewportSize(); EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, RenderCanvasInEditorViewport, false, viewportSize); m_draw2d->SetSortKey(topLayerKey); @@ -1085,15 +1108,12 @@ void ViewportWidget::UpdatePreviewMode(float deltaTime) if (canvasEntityId.IsValid()) { - QSize scaledViewportSize = QtHelpers::GetDpiScaledViewportSize(*this); - AZ::Vector2 viewportSize(static_cast(scaledViewportSize.width()), static_cast(scaledViewportSize.height())); - // Get the canvas size AZ::Vector2 canvasSize = m_editorWindow->GetPreviewCanvasSize(); if (canvasSize.GetX() == 0.0f && canvasSize.GetY() == 0.0f) { // special value of (0,0) means use the viewport size - canvasSize = viewportSize; + canvasSize = GetRenderViewportSize();; } // Set the target size of the canvas @@ -1127,8 +1147,7 @@ void ViewportWidget::RenderPreviewMode() if (canvasEntityId.IsValid()) { - QSize scaledViewportSize = QtHelpers::GetDpiScaledViewportSize(*this); - AZ::Vector2 viewportSize(static_cast(scaledViewportSize.width()), static_cast(scaledViewportSize.height())); + AZ::Vector2 viewportSize = GetRenderViewportSize(); // Get the canvas size AZ::Vector2 canvasSize = m_editorWindow->GetPreviewCanvasSize(); @@ -1208,13 +1227,13 @@ void ViewportWidget::RenderPreviewMode() void ViewportWidget::RenderViewportBackground() { - QSize viewportSize = QtHelpers::GetDpiScaledViewportSize(*this); + AZ::Vector2 viewportSize = GetRenderViewportSize(); AZ::Color backgroundColor = ViewportHelpers::backgroundColorDark; const AZ::Data::Instance& image = AZ::RPI::ImageSystemInterface::Get()->GetSystemImage(AZ::RPI::SystemImage::White); Draw2dHelper draw2d(m_draw2d.get()); draw2d.SetImageColor(backgroundColor.GetAsVector3()); - draw2d.DrawImage(image, AZ::Vector2(0.0f, 0.0f), AZ::Vector2(static_cast(viewportSize.width()), static_cast(viewportSize.height()))); + draw2d.DrawImage(image, AZ::Vector2(0.0f, 0.0f), viewportSize); } void ViewportWidget::SetupShortcuts() diff --git a/Gems/LyShine/Code/Editor/ViewportWidget.h b/Gems/LyShine/Code/Editor/ViewportWidget.h index 722335aa93..c285e0d969 100644 --- a/Gems/LyShine/Code/Editor/ViewportWidget.h +++ b/Gems/LyShine/Code/Editor/ViewportWidget.h @@ -72,6 +72,12 @@ public: // member functions //! Used by ViewportInteraction for drawing ViewportHighlight* GetViewportHighlight() { return m_viewportHighlight.get(); } + //! Get the size of the RPI render viewport + AZ::Vector2 GetRenderViewportSize() const; + + //! Get the widget to viewport scale factor + float WidgetToViewportFactor() const; + bool IsInObjectPickMode() { return m_inObjectPickMode; } void PickItem(AZ::EntityId entityId); @@ -156,6 +162,7 @@ private: // member functions // AZ::RPI::ViewportContextNotificationBus::Handler overrides... void OnRenderTick() override; + void OnViewportDpiScalingChanged(float dpiScale) override; //! Update UI canvases when in edit mode void UpdateEditMode(float deltaTime); @@ -187,12 +194,6 @@ private: // data bool AcceptsMimeData(const QMimeData* mimeData); - double WidgetToViewportFactor() const - { - // Needed for high DPI mode on windows - return devicePixelRatioF(); - } - QPointF WidgetToViewport(const QPointF &point) const; EditorWindow* m_editorWindow; From 7fc4e4bd105ab53ec2ea990fa055b581da97d666 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Fri, 21 Jan 2022 14:29:37 -0600 Subject: [PATCH 080/136] Refactored the styling of TableView header sections Signed-off-by: Chris Galvan --- .../AzQtComponents/Components/Style.cpp | 12 ------------ .../Components/Widgets/TableView.cpp | 18 ------------------ .../Components/Widgets/TableView.h | 2 -- .../Components/Widgets/TableView.qss | 2 +- .../AzQtComponents/Gallery/TableViewPage.cpp | 3 +++ 5 files changed, 4 insertions(+), 33 deletions(-) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Style.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/Style.cpp index ef29c05e61..849785ff01 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Style.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Style.cpp @@ -411,18 +411,6 @@ namespace AzQtComponents } break; - case CE_HeaderSection: - { - if (qobject_cast(widget)) - { - if (TableView::drawHeaderSection(this, option, painter, widget, m_data->tableViewConfig)) - { - return; - } - } - } - break; - case CE_ComboBoxLabel: { if (qobject_cast(widget)) diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TableView.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TableView.cpp index f5cb90ae1a..b4b49bdcec 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TableView.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TableView.cpp @@ -38,7 +38,6 @@ namespace AzQtComponents ConfigHelpers::read(settings, QStringLiteral("FocusBorderWidth"), config.focusBorderWidth); ConfigHelpers::read(settings, QStringLiteral("FocusBorderColor"), config.focusBorderColor); ConfigHelpers::read(settings, QStringLiteral("FocusFillColor"), config.focusFillColor); - ConfigHelpers::read(settings, QStringLiteral("HeaderFillColor"), config.headerFillColor); settings.endGroup(); return config; @@ -52,7 +51,6 @@ namespace AzQtComponents config.focusBorderWidth = 1; config.focusBorderColor = QStringLiteral("#94D2FF"); config.focusFillColor = QStringLiteral("#10ffffff"); - config.headerFillColor = QStringLiteral("#2d2d2d"); return config; } @@ -177,22 +175,6 @@ namespace AzQtComponents return true; } - bool TableView::drawHeaderSection(const Style* style, const QStyleOption* option, QPainter* painter, const QWidget* widget, const Config& config) - { - Q_UNUSED(widget); - Q_UNUSED(style); - - const auto headerViewOption = qstyleoption_cast(option); - if (!headerViewOption) - { - return false; - } - - painter->fillRect(headerViewOption->rect, config.headerFillColor); - - return true; - } - bool TableView::drawFrameFocusRect(const Style* style, const QStyleOption* option, QPainter* painter, const Config& config) { Q_UNUSED(style); diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TableView.h b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TableView.h index 99fb77c3d8..6187f44dd5 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TableView.h +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TableView.h @@ -62,7 +62,6 @@ namespace AzQtComponents qreal focusBorderWidth; QColor focusBorderColor; QColor focusFillColor; - QColor headerFillColor; }; /*! @@ -93,7 +92,6 @@ namespace AzQtComponents private: static bool drawHeader(const Style* style, const QStyleOption* option, QPainter* painter, const QWidget* widget, const Config& config); - static bool drawHeaderSection(const Style* style, const QStyleOption* option, QPainter* painter, const QWidget* widget, const Config& config); static bool drawFrameFocusRect(const Style* style, const QStyleOption* option, QPainter* painter, const Config& config); static QRect itemViewItemRect(const Style* style, QStyle::SubElement element, const QStyleOptionViewItem* option, const QWidget* widget, const Config& config); static QSize sizeFromContents(const Style* style, QStyle::ContentsType type, const QStyleOption* option, const QSize& contentsSize, const QWidget* widget, const Config& config); diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TableView.qss b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TableView.qss index 47281eda7e..531a3378fa 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TableView.qss +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/TableView.qss @@ -66,7 +66,7 @@ QTreeView QHeaderView::section { height: 24px; - background: #444444; + background: #2d2d2d; border: none; font-size: 12px; diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Gallery/TableViewPage.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Gallery/TableViewPage.cpp index 788ba62366..24e65ac540 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Gallery/TableViewPage.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Gallery/TableViewPage.cpp @@ -134,6 +134,9 @@ TableViewPage::TableViewPage(QWidget* parent) auto logItemDelegate = new AzToolsFramework::Logging::LogTableItemDelegate(ui->logTableView); ui->logTableView->setItemDelegate(logItemDelegate); + // Example of changing the header section background color + ui->logTableView->setStyleSheet("QHeaderView::section { background: transparent; }"); + ui->qTableView->setModel(logModel); ui->qTableView->setAlternatingRowColors(true); ui->qTableView->setShowGrid(false); From 86a0be256135d047fe82f4041283e77a13c73dba Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Fri, 21 Jan 2022 12:35:29 -0800 Subject: [PATCH 081/136] Prevent read-only entities from being duplicated via prefab workflows (#7076) * Refactor the sanitation of the selection for prefab operations to prevent read-only entities from being deleted or duplicated. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Fix comment. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../Prefab/PrefabPublicHandler.cpp | 45 ++++++++----------- .../Prefab/PrefabPublicHandler.h | 5 ++- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index bde5de2f64..0c1fb9bed2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -1063,7 +1063,7 @@ namespace AzToolsFramework return AZ::Failure(AZStd::string("No entities to duplicate.")); } - const EntityIdList entityIdsNoFocusContainer = GenerateEntityIdListWithoutFocusedInstanceContainer(entityIds); + const EntityIdList entityIdsNoFocusContainer = SanitizeEntityIdList(entityIds); if (entityIdsNoFocusContainer.empty()) { return AZ::Failure(AZStd::string("No entities to duplicate because only instance selected is the container entity of the focused instance.")); @@ -1202,7 +1202,7 @@ namespace AzToolsFramework PrefabOperationResult PrefabPublicHandler::DeleteFromInstance(const EntityIdList& entityIds, bool deleteDescendants) { // Remove the container entity of the focused prefab from the list, if it is included. - const EntityIdList entityIdsNoFocusContainer = GenerateEntityIdListWithoutFocusedInstanceContainer(entityIds); + const EntityIdList entityIdsNoFocusContainer = SanitizeEntityIdList(entityIds); if (entityIdsNoFocusContainer.empty()) { @@ -1236,27 +1236,6 @@ namespace AzToolsFramework return AZ::Failure(AZStd::string("Cannot delete entities belonging to an instance that is not being edited.")); } - // None of the specified entities can be marked as read only, otherwise this operation is invalid. - if (auto readOnlyEntityPublicInterface = AZ::Interface::Get()) - { - AZ::EntityId readOnlyEntityId; - for (const auto& entityId : entityIdsNoFocusContainer) - { - if (readOnlyEntityPublicInterface->IsReadOnly(entityId)) - { - readOnlyEntityId = entityId; - break; - } - } - - if (readOnlyEntityId.IsValid()) - { - return AZ::Failure(AZStd::string::format( - "Cannot delete entities because entity (id '%llu') is marked as read only.", - static_cast(readOnlyEntityId))); - } - } - // Retrieve entityList from entityIds EntityList inputEntityList = EntityIdListToEntityList(entityIdsNoFocusContainer); @@ -1680,10 +1659,24 @@ namespace AzToolsFramework return AZ::Success(); } - EntityIdList PrefabPublicHandler::GenerateEntityIdListWithoutFocusedInstanceContainer( - const EntityIdList& entityIds) const + EntityIdList PrefabPublicHandler::SanitizeEntityIdList(const EntityIdList& entityIds) const { - EntityIdList outEntityIds(entityIds); + EntityIdList outEntityIds; + + if (auto readOnlyEntityPublicInterface = AZ::Interface::Get()) + { + std::copy_if( + entityIds.begin(), entityIds.end(), AZStd::back_inserter(outEntityIds), + [readOnlyEntityPublicInterface](const AZ::EntityId& entityId) + { + return !readOnlyEntityPublicInterface->IsReadOnly(entityId); + } + ); + } + else + { + outEntityIds = entityIds; + } AzFramework::EntityContextId editorEntityContextId = AzToolsFramework::GetEntityContextId(); AZ::EntityId focusedInstanceContainerEntityId = m_prefabFocusPublicInterface->GetFocusedPrefabContainerEntityId(editorEntityContextId); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h index 41c9b4a292..a1a7ac9844 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h @@ -75,7 +75,10 @@ namespace AzToolsFramework Instance& commonRootEntityOwningInstance, EntityList& outEntities, AZStd::vector& outInstances) const; - EntityIdList GenerateEntityIdListWithoutFocusedInstanceContainer(const EntityIdList& entityIds) const; + + //! Sanitizes an EntityIdList to remove entities that should not be affected by prefab operations. + //! It will identify and exclude the container entity of the root prefab instance, and all read-only entities. + EntityIdList SanitizeEntityIdList(const EntityIdList& entityIds) const; InstanceOptionalReference GetOwnerInstanceByEntityId(AZ::EntityId entityId) const; bool EntitiesBelongToSameInstance(const EntityIdList& entityIds) const; From 1909e5fa540e11d9fa010dc0b578e45f095dbd15 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Fri, 21 Jan 2022 13:09:09 -0800 Subject: [PATCH 082/136] Handle case where engine.json missing or corrupt (#7049) Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- Code/Tools/ProjectManager/Source/Application.cpp | 9 ++++----- Code/Tools/ProjectManager/Source/PythonBindings.cpp | 3 +++ scripts/o3de/o3de/manifest.py | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/Application.cpp b/Code/Tools/ProjectManager/Source/Application.cpp index 08a812999f..7ccd855b7e 100644 --- a/Code/Tools/ProjectManager/Source/Application.cpp +++ b/Code/Tools/ProjectManager/Source/Application.cpp @@ -196,9 +196,7 @@ namespace O3DE::ProjectManager return true; } - bool forceRegistration = false; - - // check if an engine with this name is already registered + // check if an engine with this name is already registered and has a valid engine.json auto existingEngineResult = m_pythonBindings->GetEngineInfo(engineInfo.m_name); if (existingEngineResult) { @@ -230,10 +228,11 @@ namespace O3DE::ProjectManager // user elected not to change the name or force registration return false; } - - forceRegistration = true; } + // always force register in case there is an engine registered in o3de_manifest.json, but + // the engine.json is missing or corrupt in which case GetEngineInfo() fails + constexpr bool forceRegistration = true; auto registerOutcome = m_pythonBindings->SetEngineInfo(engineInfo, forceRegistration); if (!registerOutcome) { diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 00ece7396d..13fa73625c 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -459,6 +459,9 @@ namespace O3DE::ProjectManager if (!pybind11::isinstance(enginePathResult)) { engineInfo = EngineInfoFromPath(enginePathResult); + + // it is possible an engine is registered in o3de_manifest.json but the engine.json is + // missing or corrupt in which case we do not consider it a registered engine } }); diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py index c06a4d12fc..51b6eaf226 100644 --- a/scripts/o3de/o3de/manifest.py +++ b/scripts/o3de/o3de/manifest.py @@ -608,7 +608,7 @@ def get_registered(engine_name: str = None, except json.JSONDecodeError as e: logger.warning(f'{engine_json} failed to load: {str(e)}') else: - this_engines_name = engine_json_data['engine_name'] + this_engines_name = engine_json_data.get('engine_name','') if this_engines_name == engine_name: return engine_path engines_path = json_data.get('engines_path', {}) From ea3cf928b03bf499bcb9543cfebc54060ac31194 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Fri, 21 Jan 2022 14:40:12 -0800 Subject: [PATCH 083/136] Small change looking for logs so py code doesnt need to wait as long Signed-off-by: Gene Walters --- .../Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py index 4548dff0b8..0d1067269c 100644 --- a/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py +++ b/AutomatedTesting/Gem/PythonTests/Multiplayer/tests/Multiplayer_SimpleNetworkLevelEntity.py @@ -58,7 +58,7 @@ def Multiplayer_SimpleNetworkLevelEntity(): Report.critical_result(TestSuccessFailTuples.find_network_player, player_id.IsValid()) # 4) Check the editor logs for network spawnable errors - ATTEMPTING_INVALID_NETSPAWN_WAIT_TIME_SECONDS = 1.0 # The editor will try to net-spawn its networked level entity before it's even a client. Make sure this doesn't happen. + ATTEMPTING_INVALID_NETSPAWN_WAIT_TIME_SECONDS = 0.0 # The editor will try to net-spawn its networked level entity before it's even a client. Make sure this didn't happen. helper.fail_if_log_line_found('NetworkEntityManager', "RequestNetSpawnableInstantiation: Requested spawnable Root.network.spawnable doesn't exist in the NetworkSpawnableLibrary. Please make sure it is a network spawnable", section_tracer.errors, ATTEMPTING_INVALID_NETSPAWN_WAIT_TIME_SECONDS) # 5) Ensure the script graph attached to the level entity is running on the server From 529c342ecac86479b08ce6b14cbb10ff46d2ba43 Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Fri, 21 Jan 2022 14:53:11 -0800 Subject: [PATCH 084/136] fixing remove_components Signed-off-by: Scott Murray --- .../editor_python_test_tools/editor_entity_utils.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py index c3398406ab..f19bf540a9 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py @@ -473,12 +473,11 @@ class EditorEntity: :param component_names: List of component names to remove :return: None """ - type_ids = EditorComponent.get_type_ids(component_names, EditorEntityType.GAME) - for type_id in type_ids: - remove_outcome = editor.EditorComponentAPIBus(bus.Broadcast, "RemoveComponents", self.id, [type_id]) - assert ( - remove_outcome.IsSuccess() - ), f"Failure: could not remove component from '{self.get_name()}'" + component_ids = [component.id for component in self.get_components_of_type(component_names)] + remove_success = editor.EditorComponentAPIBus(bus.Broadcast, "RemoveComponents", component_ids) + assert ( + remove_success + ), f"Failure: could not remove component from '{self.get_name()}'" def get_components_of_type(self, component_names: list) -> List[EditorComponent]: """ From 44cbc7659fd172d7e4f98ad9c8dda54f35ccc761 Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Fri, 21 Jan 2022 15:00:36 -0800 Subject: [PATCH 085/136] removing unused line Signed-off-by: Scott Murray --- .../tests/hydra_AtomEditorComponents_EntityReferenceAdded.py | 1 - 1 file changed, 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py index 464f2a1892..7f15702199 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py @@ -193,7 +193,6 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): 1) count_after = entity_reference_component.get_container_count( AtomComponentProperties.entity_reference('EntityIdReferences')) - remove_count = (count_before == 3) and (count_after == 2) Report.result( Tests.container_remove, ((count_before == 3) and (count_after == 2) and From 7fa6a82f550a4ca687b1a7742948859ad472af4f Mon Sep 17 00:00:00 2001 From: michabr <82236305+michabr@users.noreply.github.com> Date: Fri, 21 Jan 2022 15:03:57 -0800 Subject: [PATCH 086/136] Make ILyShine an AZ::Interface (#6923) * Move ILyShine instance out of legacy code Signed-off-by: abrmich * Remove last remaining reference of gEnv->pLyShine Signed-off-by: abrmich * Make m_lyShine a unique pointer Signed-off-by: abrmich --- Code/Legacy/CryCommon/ISystem.h | 1 - .../Editor/CommandCanvasPropertiesChange.cpp | 2 +- Gems/LyShine/Code/Editor/EditorWindow.cpp | 10 ++++---- .../Editor/LyShineEditorSystemComponent.cpp | 4 +-- .../Code/Editor/SpriteBorderEditor.cpp | 3 ++- Gems/LyShine/Code/Editor/ViewportWidget.cpp | 10 ++++---- Gems/LyShine/Code/Include/LyShine/IDraw2d.h | 8 +++--- Gems/LyShine/Code/Include/LyShine/ILyShine.h | 5 +++- Gems/LyShine/Code/Source/LyShine.cpp | 14 +++++------ Gems/LyShine/Code/Source/LyShine.h | 2 +- Gems/LyShine/Code/Source/LyShineDebug.cpp | 8 +++--- .../LyShine/Code/Source/LyShineLoadScreen.cpp | 25 ++++++++++--------- .../Code/Source/LyShineSystemComponent.cpp | 20 ++++++++------- .../Code/Source/LyShineSystemComponent.h | 2 +- .../Code/Source/Script/UiCanvasLuaBus.cpp | 4 +-- .../LyShine/Code/Source/UiCanvasComponent.cpp | 8 +++--- Gems/LyShine/Code/Source/UiImageComponent.cpp | 12 ++++----- .../Code/Source/UiImageSequenceComponent.cpp | 4 +-- .../Code/Source/UiInteractableState.cpp | 8 +++--- .../Source/UiParticleEmitterComponent.cpp | 6 ++--- .../World/UiCanvasAssetRefComponent.cpp | 9 ++++--- .../Code/Tests/UiTooltipComponentTest.cpp | 5 ---- .../Code/Source/LyShineExamplesCppExample.cpp | 4 +-- .../Code/Source/UiCustomImageComponent.cpp | 6 ++--- .../Code/Source/LyShineMessagePopup.cpp | 12 ++++----- 25 files changed, 97 insertions(+), 95 deletions(-) diff --git a/Code/Legacy/CryCommon/ISystem.h b/Code/Legacy/CryCommon/ISystem.h index 6fdc8b52fe..14b78fd155 100644 --- a/Code/Legacy/CryCommon/ISystem.h +++ b/Code/Legacy/CryCommon/ISystem.h @@ -614,7 +614,6 @@ struct SSystemGlobalEnvironment ISystem* pSystem = nullptr; ILog* pLog; IMovieSystem* pMovieSystem; - ILyShine* pLyShine; SharedEnvironmentInstance* pSharedEnvironment; #if defined(AZ_RESTRICTED_PLATFORM) diff --git a/Gems/LyShine/Code/Editor/CommandCanvasPropertiesChange.cpp b/Gems/LyShine/Code/Editor/CommandCanvasPropertiesChange.cpp index 30a716b142..e90252e54a 100644 --- a/Gems/LyShine/Code/Editor/CommandCanvasPropertiesChange.cpp +++ b/Gems/LyShine/Code/Editor/CommandCanvasPropertiesChange.cpp @@ -64,7 +64,7 @@ void CommandCanvasPropertiesChange::Recreate(bool isUndo) // Create a new canvas from the XML and release the old canvas, use the new entity context for // the new canvas const AZStd::string& xml = isUndo ? m_undoXml : m_redoXml; - gEnv->pLyShine->ReloadCanvasFromXml(xml, newEntityContext); + AZ::Interface::Get()->ReloadCanvasFromXml(xml, newEntityContext); // Tell the editor window to use the new entity context m_editorWindow->ReplaceEntityContext(newEntityContext); diff --git a/Gems/LyShine/Code/Editor/EditorWindow.cpp b/Gems/LyShine/Code/Editor/EditorWindow.cpp index 7b60474ed5..8f1d574ae5 100644 --- a/Gems/LyShine/Code/Editor/EditorWindow.cpp +++ b/Gems/LyShine/Code/Editor/EditorWindow.cpp @@ -315,7 +315,7 @@ EditorWindow::~EditorWindow() // unload the preview mode canvas if it exists (e.g. if we close the editor window while in preview mode) if (m_previewModeCanvasEntityId.IsValid()) { - gEnv->pLyShine->ReleaseCanvas(m_previewModeCanvasEntityId, false); + AZ::Interface::Get()->ReleaseCanvas(m_previewModeCanvasEntityId, false); } delete m_sliceLibraryTree; @@ -564,7 +564,7 @@ bool EditorWindow::OnPreWarning(const char* /*window*/, const char* /*fileName*/ void EditorWindow::DestroyCanvas(const UiCanvasMetadata& canvasMetadata) { - gEnv->pLyShine->ReleaseCanvas(canvasMetadata.m_canvasEntityId, true); + AZ::Interface::Get()->ReleaseCanvas(canvasMetadata.m_canvasEntityId, true); } bool EditorWindow::IsCanvasTabMetadataValidForTabIndex(int index) @@ -950,14 +950,14 @@ bool EditorWindow::LoadCanvas(const QString& canvasFilename, bool autoLoad, bool bool errorsOnLoad = false; if (canvasFilename.isEmpty()) { - canvasEntityId = gEnv->pLyShine->CreateCanvasInEditor(entityContext); + canvasEntityId = AZ::Interface::Get()->CreateCanvasInEditor(entityContext); } else { // Collect errors and warnings during the canvas load AZ::Debug::TraceMessageBus::Handler::BusConnect(); - canvasEntityId = gEnv->pLyShine->LoadCanvasInEditor(assetIdPathname.c_str(), sourceAssetPathName.c_str(), entityContext); + canvasEntityId = AZ::Interface::Get()->LoadCanvasInEditor(assetIdPathname.c_str(), sourceAssetPathName.c_str(), entityContext); // Stop receiving error and warning events AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); @@ -1603,7 +1603,7 @@ void EditorWindow::ToggleEditorMode() EBUS_EVENT_RESULT(entity, AZ::ComponentApplicationBus, FindEntity, m_previewModeCanvasEntityId); if (entity) { - gEnv->pLyShine->ReleaseCanvas(m_previewModeCanvasEntityId, false); + AZ::Interface::Get()->ReleaseCanvas(m_previewModeCanvasEntityId, false); } m_previewModeCanvasEntityId.SetInvalid(); } diff --git a/Gems/LyShine/Code/Editor/LyShineEditorSystemComponent.cpp b/Gems/LyShine/Code/Editor/LyShineEditorSystemComponent.cpp index 229101d4c0..3ec6980cfb 100644 --- a/Gems/LyShine/Code/Editor/LyShineEditorSystemComponent.cpp +++ b/Gems/LyShine/Code/Editor/LyShineEditorSystemComponent.cpp @@ -211,9 +211,9 @@ namespace LyShineEditor void LyShineEditorSystemComponent::OnStopPlayInEditor() { // reset UI system - if (gEnv->pLyShine) + if (AZ::Interface::Get()) { - gEnv->pLyShine->Reset(); + AZ::Interface::Get()->Reset(); } } } diff --git a/Gems/LyShine/Code/Editor/SpriteBorderEditor.cpp b/Gems/LyShine/Code/Editor/SpriteBorderEditor.cpp index 93d77bd174..b9ca4cd32c 100644 --- a/Gems/LyShine/Code/Editor/SpriteBorderEditor.cpp +++ b/Gems/LyShine/Code/Editor/SpriteBorderEditor.cpp @@ -7,6 +7,7 @@ */ #include "SpriteBorderEditorCommon.h" +#include #include #include #include @@ -35,7 +36,7 @@ SpriteBorderEditor::SpriteBorderEditor(const char* path, QWidget* parent) setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint); // Make sure the sprite can load and be displayed before continuing - m_sprite = gEnv->pLyShine->LoadSprite(m_spritePath.toLatin1().constData()); + m_sprite = AZ::Interface::Get()->LoadSprite(m_spritePath.toLatin1().constData()); QString fullPath = Path::GamePathToFullPath(m_sprite->GetTexturePathname().c_str()); const bool imageWontLoad = !m_sprite || QPixmap(fullPath).isNull(); if (imageWontLoad) diff --git a/Gems/LyShine/Code/Editor/ViewportWidget.cpp b/Gems/LyShine/Code/Editor/ViewportWidget.cpp index eb5625ac31..32231058bf 100644 --- a/Gems/LyShine/Code/Editor/ViewportWidget.cpp +++ b/Gems/LyShine/Code/Editor/ViewportWidget.cpp @@ -181,7 +181,7 @@ namespace EBUS_EVENT_ID_RESULT(handled, canvasEntityId, UiCanvasBus, HandleInputEvent, inputSnapshot, viewportPos, activeModifierKeys); // Execute events that have been queued during the input event handler - gEnv->pLyShine->ExecuteQueuedEvents(); + AZ::Interface::Get()->ExecuteQueuedEvents(); return handled; } @@ -192,7 +192,7 @@ namespace EBUS_EVENT_ID_RESULT(handled, canvasEntityId, UiCanvasBus, HandleTextEvent, textUTF8); // Execute events that have been queued during the input event handler - gEnv->pLyShine->ExecuteQueuedEvents(); + AZ::Interface::Get()->ExecuteQueuedEvents(); return handled; } @@ -265,7 +265,7 @@ ViewportWidget::~ViewportWidget() // Notify LyShine that this is no longer a valid UiRenderer. // Only one viewport/renderer is currently supported in the UI Editor - CLyShine* lyShine = static_cast(gEnv->pLyShine); + CLyShine* lyShine = static_cast(AZ::Interface::Get()); lyShine->SetUiRendererForEditor(nullptr); } @@ -276,7 +276,7 @@ void ViewportWidget::InitUiRenderer() // Notify LyShine that this is the UiRenderer to be used for rendering // UI canvases that are loaded in the UI Editor. // Only one viewport/renderer is currently supported in the UI Editor - CLyShine* lyShine = static_cast(gEnv->pLyShine); + CLyShine* lyShine = static_cast(AZ::Interface::Get()); lyShine->SetUiRendererForEditor(m_uiRenderer); m_draw2d = AZStd::make_shared(GetViewportContext()); @@ -1123,7 +1123,7 @@ void ViewportWidget::UpdatePreviewMode(float deltaTime) EBUS_EVENT_ID(canvasEntityId, UiEditorCanvasBus, UpdateCanvasInEditorViewport, deltaTime, true); // Execute events that have been queued during the canvas update - gEnv->pLyShine->ExecuteQueuedEvents(); + AZ::Interface::Get()->ExecuteQueuedEvents(); } } diff --git a/Gems/LyShine/Code/Include/LyShine/IDraw2d.h b/Gems/LyShine/Code/Include/LyShine/IDraw2d.h index 77dc5ac601..e880ca54a7 100644 --- a/Gems/LyShine/Code/Include/LyShine/IDraw2d.h +++ b/Gems/LyShine/Code/Include/LyShine/IDraw2d.h @@ -473,9 +473,9 @@ public: // static member functions //! Helper to get the default IDraw2d interface static IDraw2d* GetDefaultDraw2d() { - if (gEnv && gEnv->pLyShine) // [LYSHINE_ATOM_TODO][GHI #3569] Remove LyShine global interface pointer from legacy global environment + if (AZ::Interface::Get()) { - IDraw2d* draw2d = gEnv->pLyShine->GetDraw2d(); + IDraw2d* draw2d = AZ::Interface::Get()->GetDraw2d(); return reinterpret_cast(draw2d); } @@ -485,9 +485,9 @@ public: // static member functions //! Helper to load a texture static AZ::Data::Instance LoadTexture(const AZStd::string& pathName) { - if (gEnv && gEnv->pLyShine) // [LYSHINE_ATOM_TODO][GHI #3569] Remove LyShine global interface pointer from legacy global environment + if (AZ::Interface::Get()) { - return gEnv->pLyShine->LoadTexture(pathName); + return AZ::Interface::Get()->LoadTexture(pathName); } return nullptr; diff --git a/Gems/LyShine/Code/Include/LyShine/ILyShine.h b/Gems/LyShine/Code/Include/LyShine/ILyShine.h index 71ca6ec074..d05e105c87 100644 --- a/Gems/LyShine/Code/Include/LyShine/ILyShine.h +++ b/Gems/LyShine/Code/Include/LyShine/ILyShine.h @@ -38,7 +38,10 @@ namespace AZ::RPI class ILyShine { public: - virtual ~ILyShine(){} + AZ_RTTI(ILyShine, "{652ED9D7-0782-44E8-BCE7-65DD38C90907}"); + + ILyShine() = default; + virtual ~ILyShine() = default; //! Delete this object virtual void Release() = 0; diff --git a/Gems/LyShine/Code/Source/LyShine.cpp b/Gems/LyShine/Code/Source/LyShine.cpp index b362ed2106..df26a905ad 100644 --- a/Gems/LyShine/Code/Source/LyShine.cpp +++ b/Gems/LyShine/Code/Source/LyShine.cpp @@ -124,7 +124,7 @@ AllocateConstIntCVar(CLyShine, CV_ui_RunUnitTestsOnStartup); #endif //////////////////////////////////////////////////////////////////////////////////////////////////// -CLyShine::CLyShine([[maybe_unused]] ISystem* system) +CLyShine::CLyShine() : AzFramework::InputChannelEventListener(AzFramework::InputChannelEventListener::GetPriorityUI()) , AzFramework::InputTextEventListener(AzFramework::InputTextEventListener::GetPriorityUI()) , m_draw2d(new CDraw2d) @@ -386,8 +386,8 @@ void CLyShine::Update(float deltaTimeInSeconds) } // Tell the UI system the size of the viewport we are rendering to - this drives the - // canvas size for full screen UI canvases. It needs to be set before either pLyShine->Update or - // pLyShine->Render are called. It must match the viewport size that the input system is using. + // canvas size for full screen UI canvases. It needs to be set before either lyShine->Update or + // lyShine->Render are called. It must match the viewport size that the input system is using. SetViewportSize(m_uiRenderer->GetViewportSize()); // Guard against nested updates. This can occur if a canvas update below triggers the load screen component's @@ -708,10 +708,10 @@ void CLyShine::RenderUiCursor() //////////////////////////////////////////////////////////////////////////////////////////////////// void CLyShine::DebugReportDrawCalls(IConsoleCmdArgs* cmdArgs) { - if (gEnv->pLyShine) + if (AZ::Interface::Get()) { // We want to use an internal-only non-static function so downcast to CLyShine - CLyShine* pLyShine = static_cast(gEnv->pLyShine); + CLyShine* lyShine = static_cast(AZ::Interface::Get()); // There is an optional parameter which is a name to include in the output filename AZStd::string name; @@ -721,7 +721,7 @@ void CLyShine::DebugReportDrawCalls(IConsoleCmdArgs* cmdArgs) } // Use the canvas manager to access all the loaded canvases - pLyShine->m_uiCanvasManager->DebugReportDrawCalls(name); + lyShine->m_uiCanvasManager->DebugReportDrawCalls(name); } } #endif @@ -742,7 +742,7 @@ void CLyShine::RunUnitTests(IConsoleCmdArgs* cmdArgs) return; } - CLyShine* lyShine = static_cast(gEnv->pLyShine); + CLyShine* lyShine = static_cast(AZ::Interface::Get()); AZ_Assert(lyShine, "Attempting to run unit-tests prior to LyShine initialization!"); TextMarkup::UnitTest(cmdArgs); diff --git a/Gems/LyShine/Code/Source/LyShine.h b/Gems/LyShine/Code/Source/LyShine.h index eab52258c1..2fd0f80210 100644 --- a/Gems/LyShine/Code/Source/LyShine.h +++ b/Gems/LyShine/Code/Source/LyShine.h @@ -48,7 +48,7 @@ class CLyShine public: //! Create the LyShine object, the given system pointer is stored internally - CLyShine(ISystem* system); + CLyShine(); // ILyShine diff --git a/Gems/LyShine/Code/Source/LyShineDebug.cpp b/Gems/LyShine/Code/Source/LyShineDebug.cpp index 7e99652f45..3502699525 100644 --- a/Gems/LyShine/Code/Source/LyShineDebug.cpp +++ b/Gems/LyShine/Code/Source/LyShineDebug.cpp @@ -997,7 +997,7 @@ static AZ::Entity* CreateButton(const char* name, bool atRoot, AZ::EntityId pare EBUS_EVENT_ID(buttonId, UiInteractableStatesBus, SetStateAlpha, UiInteractableStatesInterface::StatePressed, buttonId, pressedColor.GetA()); AZStd::string pathname = "Textures/Basic/Button_Sliced_Normal.sprite"; - ISprite* sprite = gEnv->pLyShine->LoadSprite(pathname); + ISprite* sprite = AZ::Interface::Get()->LoadSprite(pathname); EBUS_EVENT_ID(buttonId, UiImageBus, SetSprite, sprite); EBUS_EVENT_ID(buttonId, UiImageBus, SetImageType, UiImageInterface::ImageType::Sliced); @@ -1096,7 +1096,7 @@ static AZ::Entity* CreateTextInput(const char* name, bool atRoot, AZ::EntityId p EBUS_EVENT_ID(textInputId, UiInteractableStatesBus, SetStateAlpha, UiInteractableStatesInterface::StatePressed, textInputId, pressedColor.GetA()); AZStd::string pathname = "Textures/Basic/Button_Sliced_Normal.sprite"; - ISprite* sprite = gEnv->pLyShine->LoadSprite(pathname); + ISprite* sprite = AZ::Interface::Get()->LoadSprite(pathname); EBUS_EVENT_ID(textInputId, UiImageBus, SetSprite, sprite); EBUS_EVENT_ID(textInputId, UiImageBus, SetImageType, UiImageInterface::ImageType::Sliced); @@ -1192,7 +1192,7 @@ static void DestroyTestCanvas() delete g_testActionListener2; g_testActionListener2 = nullptr; - gEnv->pLyShine->ReleaseCanvas(g_testCanvasId, false); + AZ::Interface::Get()->ReleaseCanvas(g_testCanvasId, false); g_testCanvasId.SetInvalid(); } } @@ -1216,7 +1216,7 @@ static void TestCanvasCreate ([[maybe_unused]] IConsoleCmdArgs* Cmd) DestroyTestCanvas(); // test creation of canvas and some simple elements - AZ::EntityId canvasEntityId = gEnv->pLyShine->CreateCanvas(); + AZ::EntityId canvasEntityId = AZ::Interface::Get()->CreateCanvas(); UiCanvasInterface* canvas = UiCanvasBus::FindFirstHandler(canvasEntityId); if (!canvas) { diff --git a/Gems/LyShine/Code/Source/LyShineLoadScreen.cpp b/Gems/LyShine/Code/Source/LyShineLoadScreen.cpp index c59cb5cb34..e0916d43b2 100644 --- a/Gems/LyShine/Code/Source/LyShineLoadScreen.cpp +++ b/Gems/LyShine/Code/Source/LyShineLoadScreen.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -63,7 +64,7 @@ namespace LyShine AZ_ErrorOnce(nullptr, false, "NotifyGameLoadStart needs to be removed/ported to use Atom"); return false; #if 0 - if (!gEnv || gEnv->pRenderer || !gEnv->pLyShine) + if (!gEnv || gEnv->pRenderer || !AZ::Interface::Get()) { return false; } @@ -103,7 +104,7 @@ namespace LyShine return false; //TODO: gEnv->pRenderer is always null, fix the logic below #if 0 - if (!gEnv || gEnv->pRenderer || !gEnv->pLyShine) + if (!gEnv || gEnv->pRenderer || !AZ::Interface::Get()) { return false; } @@ -140,22 +141,22 @@ namespace LyShine void LyShineLoadScreenComponent::UpdateAndRender([[maybe_unused]] float deltaTimeInSeconds) { AZ_Assert(m_isPlaying, "LyShineLoadScreenComponent should not be connected to LoadScreenUpdateNotificationBus while not playing"); - AZ_ErrorOnce(nullptr, m_isPlaying && gEnv && gEnv->pLyShine, "UpdateAndRender needs to be removed/ported to use Atom"); + AZ_ErrorOnce(nullptr, m_isPlaying && AZ::Interface::Get(), "UpdateAndRender needs to be removed/ported to use Atom"); //TODO: gEnv->pRenderer is always null, fix the logic below #if 0 - if (m_isPlaying && gEnv && gEnv->pLyShine && gEnv->pRenderer) + if (m_isPlaying && gEnv && AZ::Interface::Get() && gEnv->pRenderer) { AZ_Assert(GetCurrentThreadId() == gEnv->mMainThreadId, "UpdateAndRender should only be called from the main thread"); // update the animation system - gEnv->pLyShine->Update(deltaTimeInSeconds); + AZ::Interface::Get()->Update(deltaTimeInSeconds); // Render. gEnv->pRenderer->SetViewport(0, 0, gEnv->pRenderer->GetOverlayWidth(), gEnv->pRenderer->GetOverlayHeight()); gEnv->pRenderer->BeginFrame(); - gEnv->pLyShine->Render(); + AZ::Interface::Get()->Render(); gEnv->pRenderer->EndFrame(); } #endif @@ -177,7 +178,7 @@ namespace LyShine m_isPlaying = false; - if (gEnv && gEnv->pLyShine) + if (AZ::Interface::Get()) { AZ::Entity* canvasEntity = nullptr; @@ -187,8 +188,8 @@ namespace LyShine EBUS_EVENT_RESULT(canvasEntity, AZ::ComponentApplicationBus, FindEntity, m_gameCanvasEntityId); if (canvasEntity) { - gEnv->pLyShine->ReleaseCanvas(m_gameCanvasEntityId, false); - gEnv->pLyShine->OnLoadScreenUnloaded(); + AZ::Interface::Get()->ReleaseCanvas(m_gameCanvasEntityId, false); + AZ::Interface::Get()->OnLoadScreenUnloaded(); } } @@ -198,8 +199,8 @@ namespace LyShine EBUS_EVENT_RESULT(canvasEntity, AZ::ComponentApplicationBus, FindEntity, m_levelCanvasEntityId); if (canvasEntity) { - gEnv->pLyShine->ReleaseCanvas(m_levelCanvasEntityId, false); - gEnv->pLyShine->OnLoadScreenUnloaded(); + AZ::Interface::Get()->ReleaseCanvas(m_levelCanvasEntityId, false); + AZ::Interface::Get()->OnLoadScreenUnloaded(); } } } @@ -234,7 +235,7 @@ namespace LyShine return AZ::EntityId(); } - AZ::EntityId canvasId = gEnv->pLyShine->LoadCanvas(path); + AZ::EntityId canvasId = AZ::Interface::Get()->LoadCanvas(path); AZ_Warning("LoadScreenComponent", canvasId.IsValid(), "Can't load canvas: %s", path.c_str()); if (!canvasId.IsValid()) { diff --git a/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp b/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp index 787797e462..7253935c2d 100644 --- a/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp +++ b/Gems/LyShine/Code/Source/LyShineSystemComponent.cpp @@ -384,16 +384,16 @@ namespace LyShine // When module is linked statically, we'll share the application's gEnv pointer. gEnv = system.GetGlobalEnvironment(); #endif - m_pLyShine = new CLyShine(gEnv->pSystem); - gEnv->pLyShine = m_pLyShine; + m_lyShine = AZStd::make_unique(); + AZ::Interface::Register(m_lyShine.get()); system.GetILevelSystem()->AddListener(this); BroadcastCursorImagePathname(); - if (gEnv->pLyShine) + if (AZ::Interface::Get()) { - gEnv->pLyShine->PostInit(); + AZ::Interface::Get()->PostInit(); } } @@ -402,18 +402,20 @@ namespace LyShine { system.GetILevelSystem()->RemoveListener(this); - gEnv->pLyShine = nullptr; - delete m_pLyShine; - m_pLyShine = nullptr; + if (m_lyShine) + { + AZ::Interface::Unregister(m_lyShine.get()); + m_lyShine.reset(); + } } //////////////////////////////////////////////////////////////////////// void LyShineSystemComponent::OnUnloadComplete([[maybe_unused]] const char* levelName) { // Perform level unload procedures for the LyShine UI system - if (gEnv && gEnv->pLyShine) + if (AZ::Interface::Get()) { - gEnv->pLyShine->OnLevelUnload(); + AZ::Interface::Get()->OnLevelUnload(); } } diff --git a/Gems/LyShine/Code/Source/LyShineSystemComponent.h b/Gems/LyShine/Code/Source/LyShineSystemComponent.h index d2cdcf6761..001ddd6fab 100644 --- a/Gems/LyShine/Code/Source/LyShineSystemComponent.h +++ b/Gems/LyShine/Code/Source/LyShineSystemComponent.h @@ -107,7 +107,7 @@ namespace LyShine protected: // data - CLyShine* m_pLyShine = nullptr; + AZStd::unique_ptr m_lyShine; AzFramework::SimpleAssetReference m_cursorImagePathname; diff --git a/Gems/LyShine/Code/Source/Script/UiCanvasLuaBus.cpp b/Gems/LyShine/Code/Source/Script/UiCanvasLuaBus.cpp index 4b0ff56241..679f13b333 100644 --- a/Gems/LyShine/Code/Source/Script/UiCanvasLuaBus.cpp +++ b/Gems/LyShine/Code/Source/Script/UiCanvasLuaBus.cpp @@ -114,7 +114,7 @@ AZ::EntityId UiCanvasLuaProxy::LoadCanvas(const char* canvasFilename) CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "UiCanvasLuaProxy:LoadCanvas is deprecated. Please use UiCanvasManagerBus:LoadCanvas instead\n"); - return gEnv->pLyShine->LoadCanvas(canvasFilename); + return AZ::Interface::Get()->LoadCanvas(canvasFilename); } void UiCanvasLuaProxy::UnloadCanvas(AZ::EntityId canvasEntityId) @@ -130,7 +130,7 @@ void UiCanvasLuaProxy::UnloadCanvas(AZ::EntityId canvasEntityId) UiCanvasComponent* canvasComponent = canvasEntity->FindComponent(); if (canvasComponent) { - gEnv->pLyShine->ReleaseCanvas(canvasEntityId, false); + AZ::Interface::Get()->ReleaseCanvas(canvasEntityId, false); } else { diff --git a/Gems/LyShine/Code/Source/UiCanvasComponent.cpp b/Gems/LyShine/Code/Source/UiCanvasComponent.cpp index ea6e3681a3..0a7161ecb3 100644 --- a/Gems/LyShine/Code/Source/UiCanvasComponent.cpp +++ b/Gems/LyShine/Code/Source/UiCanvasComponent.cpp @@ -254,9 +254,9 @@ namespace UiRenderer* GetUiRendererForGame() { - if (gEnv && gEnv->pLyShine) + if (AZ::Interface::Get()) { - CLyShine* lyShine = static_cast(gEnv->pLyShine); + CLyShine* lyShine = static_cast(AZ::Interface::Get()); return lyShine->GetUiRenderer(); } return nullptr; @@ -264,9 +264,9 @@ namespace UiRenderer* GetUiRendererForEditor() { - if (gEnv && gEnv->pLyShine) + if (AZ::Interface::Get()) { - CLyShine* lyShine = static_cast(gEnv->pLyShine); + CLyShine* lyShine = static_cast(AZ::Interface::Get()); return lyShine->GetUiRendererForEditor(); } return nullptr; diff --git a/Gems/LyShine/Code/Source/UiImageComponent.cpp b/Gems/LyShine/Code/Source/UiImageComponent.cpp index a8b4210d6b..d412695ac3 100644 --- a/Gems/LyShine/Code/Source/UiImageComponent.cpp +++ b/Gems/LyShine/Code/Source/UiImageComponent.cpp @@ -588,7 +588,7 @@ void UiImageComponent::SetSpritePathname(AZStd::string spritePath) //////////////////////////////////////////////////////////////////////////////////////////////////// bool UiImageComponent::SetSpritePathnameIfExists(AZStd::string spritePath) { - if (gEnv->pLyShine->DoesSpriteTextureAssetExist(spritePath)) + if (AZ::Interface::Get()->DoesSpriteTextureAssetExist(spritePath)) { SetSpritePathname(spritePath); return true; @@ -1179,7 +1179,7 @@ void UiImageComponent::Init() // If this is called from RC.exe for example these pointers will not be set. In that case // we only need to be able to load, init and save the component. It will never be // activated. - if (!(gEnv && gEnv->pLyShine)) + if (!AZ::Interface::Get()) { return; } @@ -1192,14 +1192,14 @@ void UiImageComponent::Init() { if (!m_spritePathname.GetAssetPath().empty()) { - m_sprite = gEnv->pLyShine->LoadSprite(m_spritePathname.GetAssetPath().c_str()); + m_sprite = AZ::Interface::Get()->LoadSprite(m_spritePathname.GetAssetPath().c_str()); } } else if (m_spriteType == UiImageInterface::SpriteType::RenderTarget) { if (!m_renderTargetName.empty()) { - m_sprite = gEnv->pLyShine->CreateSprite(m_renderTargetName.c_str()); + m_sprite = AZ::Interface::Get()->CreateSprite(m_renderTargetName.c_str()); } } else @@ -2527,7 +2527,7 @@ void UiImageComponent::OnSpritePathnameChange() if (!m_spritePathname.GetAssetPath().empty()) { // Load the new texture. - newSprite = gEnv->pLyShine->LoadSprite(m_spritePathname.GetAssetPath().c_str()); + newSprite = AZ::Interface::Get()->LoadSprite(m_spritePathname.GetAssetPath().c_str()); } // if listening for notifications from a current sprite then disconnect @@ -2557,7 +2557,7 @@ void UiImageComponent::OnSpriteRenderTargetNameChange() if (!m_renderTargetName.empty()) { - newSprite = gEnv->pLyShine->CreateSprite(m_renderTargetName.c_str()); + newSprite = AZ::Interface::Get()->CreateSprite(m_renderTargetName.c_str()); } SAFE_RELEASE(m_sprite); diff --git a/Gems/LyShine/Code/Source/UiImageSequenceComponent.cpp b/Gems/LyShine/Code/Source/UiImageSequenceComponent.cpp index 3559dc6306..3981777f2d 100644 --- a/Gems/LyShine/Code/Source/UiImageSequenceComponent.cpp +++ b/Gems/LyShine/Code/Source/UiImageSequenceComponent.cpp @@ -52,7 +52,7 @@ namespace spriteList.reserve(imageList.size()); for (auto& textureAssetRef : imageList) { - ISprite* sprite = gEnv->pLyShine->LoadSprite(textureAssetRef.GetAssetPath().c_str()); + ISprite* sprite = AZ::Interface::Get()->LoadSprite(textureAssetRef.GetAssetPath().c_str()); if (sprite) { spriteList.push_back(sprite); @@ -383,7 +383,7 @@ void UiImageSequenceComponent::Init() // If this is called from RC.exe for example these pointers will not be set. In that case // we only need to be able to load, init and save the component. It will never be // activated. - if (!(gEnv && gEnv->pLyShine)) + if (!AZ::Interface::Get()) { return; } diff --git a/Gems/LyShine/Code/Source/UiInteractableState.cpp b/Gems/LyShine/Code/Source/UiInteractableState.cpp index d2c09201c6..18bacb3a9f 100644 --- a/Gems/LyShine/Code/Source/UiInteractableState.cpp +++ b/Gems/LyShine/Code/Source/UiInteractableState.cpp @@ -274,7 +274,7 @@ UiInteractableStateSprite::UiInteractableStateSprite(AZ::EntityId target, const if (!m_spritePathname.GetAssetPath().empty()) { - m_sprite = gEnv->pLyShine->LoadSprite(m_spritePathname.GetAssetPath().c_str()); + m_sprite = AZ::Interface::Get()->LoadSprite(m_spritePathname.GetAssetPath().c_str()); } } @@ -297,7 +297,7 @@ void UiInteractableStateSprite::Init(AZ::EntityId interactableEntityId) // If this is called from RC.exe for example these pointers will not be set. In that case // we only need to be able to load, init and save the component. It will never be // activated. - if (!(gEnv && gEnv->pLyShine)) + if (!AZ::Interface::Get()) { return; } @@ -306,7 +306,7 @@ void UiInteractableStateSprite::Init(AZ::EntityId interactableEntityId) // are not loaded then load them if (!m_sprite && !m_spritePathname.GetAssetPath().empty()) { - m_sprite = gEnv->pLyShine->LoadSprite(m_spritePathname.GetAssetPath().c_str()); + m_sprite = AZ::Interface::Get()->LoadSprite(m_spritePathname.GetAssetPath().c_str()); } if (!m_sprite) @@ -366,7 +366,7 @@ void UiInteractableStateSprite::OnSpritePathnameChange() if (!m_spritePathname.GetAssetPath().empty()) { // Load the new texture. - newSprite = gEnv->pLyShine->LoadSprite(m_spritePathname.GetAssetPath().c_str()); + newSprite = AZ::Interface::Get()->LoadSprite(m_spritePathname.GetAssetPath().c_str()); } SAFE_RELEASE(m_sprite); diff --git a/Gems/LyShine/Code/Source/UiParticleEmitterComponent.cpp b/Gems/LyShine/Code/Source/UiParticleEmitterComponent.cpp index b999480940..b9f986c14a 100644 --- a/Gems/LyShine/Code/Source/UiParticleEmitterComponent.cpp +++ b/Gems/LyShine/Code/Source/UiParticleEmitterComponent.cpp @@ -1429,14 +1429,14 @@ void UiParticleEmitterComponent::Init() // If this is called from RC.exe for example these pointers will not be set. In that case // we only need to be able to load, init and save the component. It will never be // activated. - if (!(gEnv && gEnv->pLyShine)) + if (!AZ::Interface::Get()) { return; } if (!m_sprite && !m_spritePathname.GetAssetPath().empty()) { - m_sprite = gEnv->pLyShine->LoadSprite(m_spritePathname.GetAssetPath().c_str()); + m_sprite = AZ::Interface::Get()->LoadSprite(m_spritePathname.GetAssetPath().c_str()); } m_currentAspectRatio = m_particleSize.GetX() / m_particleSize.GetY(); @@ -1927,7 +1927,7 @@ void UiParticleEmitterComponent::OnSpritePathnameChange() if (!m_spritePathname.GetAssetPath().empty()) { // Load the new texture. - newSprite = gEnv->pLyShine->LoadSprite(m_spritePathname.GetAssetPath().c_str()); + newSprite = AZ::Interface::Get()->LoadSprite(m_spritePathname.GetAssetPath().c_str()); } SAFE_RELEASE(m_sprite); diff --git a/Gems/LyShine/Code/Source/World/UiCanvasAssetRefComponent.cpp b/Gems/LyShine/Code/Source/World/UiCanvasAssetRefComponent.cpp index 933cca424a..e186e1158d 100644 --- a/Gems/LyShine/Code/Source/World/UiCanvasAssetRefComponent.cpp +++ b/Gems/LyShine/Code/Source/World/UiCanvasAssetRefComponent.cpp @@ -8,6 +8,7 @@ #include "UiCanvasAssetRefComponent.h" #include #include +#include #include #include #include @@ -106,11 +107,11 @@ AZ::EntityId UiCanvasAssetRefComponent::LoadCanvas() // Check if we already have a referenced UI canvas, if so release it if (m_canvasEntityId.IsValid()) { - gEnv->pLyShine->ReleaseCanvasDeferred(m_canvasEntityId); + AZ::Interface::Get()->ReleaseCanvasDeferred(m_canvasEntityId); m_canvasEntityId.SetInvalid(); } - m_canvasEntityId = gEnv->pLyShine->LoadCanvas(canvasPath.c_str()); + m_canvasEntityId = AZ::Interface::Get()->LoadCanvas(canvasPath.c_str()); EBUS_EVENT_ID(GetEntityId(), UiCanvasAssetRefNotificationBus, OnCanvasLoadedIntoEntity, m_canvasEntityId); EBUS_EVENT_ID(GetEntityId(), UiCanvasRefNotificationBus, OnCanvasRefChanged, GetEntityId(), m_canvasEntityId); @@ -124,7 +125,7 @@ void UiCanvasAssetRefComponent::UnloadCanvas() { if (m_canvasEntityId.IsValid()) { - gEnv->pLyShine->ReleaseCanvasDeferred(m_canvasEntityId); + AZ::Interface::Get()->ReleaseCanvasDeferred(m_canvasEntityId); m_canvasEntityId.SetInvalid(); EBUS_EVENT_ID(GetEntityId(), UiCanvasRefNotificationBus, OnCanvasRefChanged, GetEntityId(), m_canvasEntityId); @@ -243,7 +244,7 @@ void UiCanvasAssetRefComponent::Deactivate() { if (m_canvasEntityId.IsValid()) { - gEnv->pLyShine->ReleaseCanvasDeferred(m_canvasEntityId); + AZ::Interface::Get()->ReleaseCanvasDeferred(m_canvasEntityId); m_canvasEntityId.SetInvalid(); } diff --git a/Gems/LyShine/Code/Tests/UiTooltipComponentTest.cpp b/Gems/LyShine/Code/Tests/UiTooltipComponentTest.cpp index 8a3d9f2af6..652cec3c0f 100644 --- a/Gems/LyShine/Code/Tests/UiTooltipComponentTest.cpp +++ b/Gems/LyShine/Code/Tests/UiTooltipComponentTest.cpp @@ -144,7 +144,6 @@ namespace UnitTest SSystemGlobalEnvironment env; SSystemGlobalEnvironment* prevEnv = gEnv; gEnv = &env; - gEnv->pLyShine = nullptr; auto [uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent] = CreateUiCanvasWithTooltip(); uiTooltipDisplayComponent->SetTriggerMode(UiTooltipDisplayInterface::TriggerMode::OnHover); @@ -170,7 +169,6 @@ namespace UnitTest SSystemGlobalEnvironment env; SSystemGlobalEnvironment* prevEnv = gEnv; gEnv = &env; - gEnv->pLyShine = nullptr; auto [uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent] = CreateUiCanvasWithTooltip(); uiTooltipDisplayComponent->SetTriggerMode(UiTooltipDisplayInterface::TriggerMode::OnHover); @@ -194,7 +192,6 @@ namespace UnitTest SSystemGlobalEnvironment env; SSystemGlobalEnvironment* prevEnv = gEnv; gEnv = &env; - gEnv->pLyShine = nullptr; auto [uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent] = CreateUiCanvasWithTooltip(); uiTooltipDisplayComponent->SetTriggerMode(UiTooltipDisplayInterface::TriggerMode::OnPress); @@ -218,7 +215,6 @@ namespace UnitTest SSystemGlobalEnvironment env; SSystemGlobalEnvironment* prevEnv = gEnv; gEnv = &env; - gEnv->pLyShine = nullptr; auto [uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent] = CreateUiCanvasWithTooltip(); uiTooltipDisplayComponent->SetTriggerMode(UiTooltipDisplayInterface::TriggerMode::OnPress); @@ -242,7 +238,6 @@ namespace UnitTest SSystemGlobalEnvironment env; SSystemGlobalEnvironment* prevEnv = gEnv; gEnv = &env; - gEnv->pLyShine = nullptr; auto [uiCanvasComponent, uiTooltipDisplayComponent, uiTooltipComponent] = CreateUiCanvasWithTooltip(); uiTooltipDisplayComponent->SetTriggerMode(UiTooltipDisplayInterface::TriggerMode::OnClick); diff --git a/Gems/LyShineExamples/Code/Source/LyShineExamplesCppExample.cpp b/Gems/LyShineExamples/Code/Source/LyShineExamplesCppExample.cpp index f2da79fa99..7619764fbc 100644 --- a/Gems/LyShineExamples/Code/Source/LyShineExamplesCppExample.cpp +++ b/Gems/LyShineExamples/Code/Source/LyShineExamplesCppExample.cpp @@ -47,7 +47,7 @@ namespace LyShineExamples // Remove the existing example canvas if it exists DestroyCanvas(); - AZ::EntityId canvasEntityId = gEnv->pLyShine->CreateCanvas(); + AZ::EntityId canvasEntityId = AZ::Interface::Get()->CreateCanvas(); if (!canvasEntityId.IsValid()) { return; @@ -90,7 +90,7 @@ namespace LyShineExamples m_healthBar.SetInvalid(); - gEnv->pLyShine->ReleaseCanvas(m_canvasId, false); + AZ::Interface::Get()->ReleaseCanvas(m_canvasId, false); m_canvasId.SetInvalid(); } } diff --git a/Gems/LyShineExamples/Code/Source/UiCustomImageComponent.cpp b/Gems/LyShineExamples/Code/Source/UiCustomImageComponent.cpp index e8b0e4370a..c228176b4f 100644 --- a/Gems/LyShineExamples/Code/Source/UiCustomImageComponent.cpp +++ b/Gems/LyShineExamples/Code/Source/UiCustomImageComponent.cpp @@ -284,7 +284,7 @@ namespace LyShineExamples // If this is called from RC.exe for example these pointers will not be set. In that case // we only need to be able to load, init and save the component. It will never be // activated. - if (!(gEnv && gEnv->pLyShine)) + if (!AZ::Interface::Get()) { return; } @@ -294,7 +294,7 @@ namespace LyShineExamples { if (!m_spritePathname.GetAssetPath().empty()) { - m_sprite = gEnv->pLyShine->LoadSprite(m_spritePathname.GetAssetPath().c_str()); + m_sprite = AZ::Interface::Get()->LoadSprite(m_spritePathname.GetAssetPath().c_str()); } } @@ -399,7 +399,7 @@ namespace LyShineExamples if (!m_spritePathname.GetAssetPath().empty()) { // Load the new texture. - newSprite = gEnv->pLyShine->LoadSprite(m_spritePathname.GetAssetPath().c_str()); + newSprite = AZ::Interface::Get()->LoadSprite(m_spritePathname.GetAssetPath().c_str()); } SAFE_RELEASE(m_sprite); diff --git a/Gems/MessagePopup/Code/Source/LyShineMessagePopup.cpp b/Gems/MessagePopup/Code/Source/LyShineMessagePopup.cpp index 40fed3448b..de54bef4eb 100644 --- a/Gems/MessagePopup/Code/Source/LyShineMessagePopup.cpp +++ b/Gems/MessagePopup/Code/Source/LyShineMessagePopup.cpp @@ -127,21 +127,21 @@ namespace MessagePopup switch (_buttons) { case EPopupButtons::EPopupButtons_NoButtons: - canvasEntityId = gEnv->pLyShine->LoadCanvas("@products@/ui/canvases/defaultmessagepopup.uicanvas"); + canvasEntityId = AZ::Interface::Get()->LoadCanvas("@products@/ui/canvases/defaultmessagepopup.uicanvas"); break; case EPopupButtons::EPopupButtons_Confirm: - canvasEntityId = gEnv->pLyShine->LoadCanvas("@products@/ui/canvases/defaultmessagepopup_confirm.uicanvas"); + canvasEntityId = AZ::Interface::Get()->LoadCanvas("@products@/ui/canvases/defaultmessagepopup_confirm.uicanvas"); isNavigationSupported = true; break; case EPopupButtons::EPopupButtons_YesNo: - canvasEntityId = gEnv->pLyShine->LoadCanvas("@products@/ui/canvases/defaultmessagepopup_yesno.uicanvas"); + canvasEntityId = AZ::Interface::Get()->LoadCanvas("@products@/ui/canvases/defaultmessagepopup_yesno.uicanvas"); isNavigationSupported = true; break; } } else if (_kind == EPopupKind_Toaster) { - canvasEntityId = gEnv->pLyShine->LoadCanvas("@products@/ui/canvases/toaster.uicanvas"); + canvasEntityId = AZ::Interface::Get()->LoadCanvas("@products@/ui/canvases/toaster.uicanvas"); } if (canvasEntityId.IsValid()) @@ -183,7 +183,7 @@ namespace MessagePopup { // get the canvas ID in the clientdata LyShine::CanvasId canvasId = *((LyShine::CanvasId*)&_popupInfo.m_clientData); - AZ::EntityId canvasEntityId = gEnv->pLyShine->FindCanvasById(canvasId); + AZ::EntityId canvasEntityId = AZ::Interface::Get()->FindCanvasById(canvasId); if (canvasEntityId.IsValid()) { // Hide the cursor if it was shown in LyShineMessagePopup::OnShowPopup @@ -197,7 +197,7 @@ namespace MessagePopup // Disable the popup EBUS_EVENT_ID(canvasEntityId, UiCanvasBus, SetEnabled, false); - gEnv->pLyShine->ReleaseCanvas(canvasEntityId, false); + AZ::Interface::Get()->ReleaseCanvas(canvasEntityId, false); UiCanvasNotificationBus::MultiHandler::BusDisconnect(canvasEntityId); m_activePopupIdsByCanvasId.erase(canvasEntityId); From a145d3c82fa3c5a71dc0545708518d7bd7769d53 Mon Sep 17 00:00:00 2001 From: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> Date: Fri, 21 Jan 2022 15:07:27 -0800 Subject: [PATCH 087/136] Issues/install missing assets (#7081) * Fixes for missing assets in the install folder Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * delayed expansion to try to fix project_engineinstall_profile Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> * Improvements to build scripts to solve the project build from the install folder Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com> --- CMakeLists.txt | 4 ++++ cmake/Platform/Common/Install_common.cmake | 8 +++++--- .../build/Platform/Windows/build_windows.cmd | 11 ++++++----- .../build/Platform/Windows/env_windows.cmd | 19 ++++++++++++------- 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c81581fe0f..efcc866195 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,6 +93,10 @@ endfunction() # Add the projects first so the Launcher can find them include(cmake/Projects.cmake) +if(LY_EXTERNAL_SUBDIRS) + set_property(GLOBAL APPEND PROPERTY LY_EXTERNAL_SUBDIRS ${LY_EXTERNAL_SUBDIRS}) +endif() + if(NOT INSTALLED_ENGINE) # Add external subdirectories listed in the engine.json. LY_EXTERNAL_SUBDIRS is a cache variable so the user can add extra # external subdirectories. This should go before adding the rest of the targets so the targets are availbe to the launcher. diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 46130f1345..e42664c107 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -445,9 +445,10 @@ function(ly_setup_cmake_install) ) endforeach() - # Transform the LY_EXTERNAL_SUBDIRS list into a json array + # Transform the LY_EXTERNAL_SUBDIRS global property list into a json array set(indent " ") - foreach(external_subdir ${LY_EXTERNAL_SUBDIRS}) + get_property(external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS) + foreach(external_subdir ${external_subdirs}) cmake_path(RELATIVE_PATH external_subdir BASE_DIRECTORY ${LY_ROOT_FOLDER} OUTPUT_VARIABLE engine_rel_external_subdir) list(APPEND relative_external_subdirs "\"${engine_rel_external_subdir}\"") endforeach() @@ -639,7 +640,8 @@ function(ly_setup_assets) # the install layout from the root directory. Such as /Cache. # This is also done to avoid globbing thousands of files in subdirectories that shouldn't # be processed. - foreach(gem_candidate_dir IN LISTS LY_EXTERNAL_SUBDIRS LY_PROJECTS) + get_property(external_subdirs GLOBAL PROPERTY LY_EXTERNAL_SUBDIRS) + foreach(gem_candidate_dir IN LISTS external_subdirs LY_PROJECTS) file(REAL_PATH ${gem_candidate_dir} gem_candidate_dir BASE_DIRECTORY ${LY_ROOT_FOLDER}) # Don't recurse immediately in order to exclude transient source artifacts file(GLOB diff --git a/scripts/build/Platform/Windows/build_windows.cmd b/scripts/build/Platform/Windows/build_windows.cmd index 798550370f..c77c262692 100644 --- a/scripts/build/Platform/Windows/build_windows.cmd +++ b/scripts/build/Platform/Windows/build_windows.cmd @@ -9,6 +9,7 @@ REM SETLOCAL EnableDelayedExpansion CALL "%~dp0env_windows.cmd" +IF NOT %ERRORLEVEL%==0 EXIT /b 1 IF NOT EXIST "%OUTPUT_DIRECTORY%" ( MKDIR %OUTPUT_DIRECTORY%. @@ -21,7 +22,7 @@ ECHO [ci_build] cmake --version cmake --version IF ERRORLEVEL 1 ( ECHO [ci_build] CMAKE not found! - exit /b 1 + EXIT /b 1 ) REM Compute half the amount of processors so some jobs can run @@ -47,14 +48,14 @@ IF NOT EXIST CMakeCache.txt ( ) ) IF DEFINED RUN_CONFIGURE ( - ECHO [ci_build] %CONFIGURE_CMD% - %CONFIGURE_CMD% + call ECHO [ci_build] %CONFIGURE_CMD% + call %CONFIGURE_CMD% IF NOT !ERRORLEVEL!==0 GOTO :error ECHO !CONFIGURE_CMD!> %LAST_CONFIGURE_CMD_FILE% ) -ECHO [ci_build] cmake --build . --target %CMAKE_TARGET% --config %CONFIGURATION% %CMAKE_BUILD_ARGS% -- %CMAKE_NATIVE_BUILD_ARGS% -cmake --build . --target %CMAKE_TARGET% --config %CONFIGURATION% %CMAKE_BUILD_ARGS% -- %CMAKE_NATIVE_BUILD_ARGS% +call ECHO [ci_build] cmake --build . --target %CMAKE_TARGET% --config %CONFIGURATION% %CMAKE_BUILD_ARGS% -- %CMAKE_NATIVE_BUILD_ARGS% +call cmake --build . --target %CMAKE_TARGET% --config %CONFIGURATION% %CMAKE_BUILD_ARGS% -- %CMAKE_NATIVE_BUILD_ARGS% IF NOT %ERRORLEVEL%==0 GOTO :error POPD diff --git a/scripts/build/Platform/Windows/env_windows.cmd b/scripts/build/Platform/Windows/env_windows.cmd index 78b5ca6c1a..c6f46ef575 100644 --- a/scripts/build/Platform/Windows/env_windows.cmd +++ b/scripts/build/Platform/Windows/env_windows.cmd @@ -13,17 +13,21 @@ SETLOCAL EnableExtensions EnableDelayedExpansion where /Q cmake IF NOT %ERRORLEVEL%==0 ( ECHO [ci_build] CMake not found - GOTO :error -) - -IF NOT "%COMMAND_CWD%"=="" ( - ECHO [ci_build] Changing CWD to %COMMAND_CWD% - CD %COMMAND_CWD% + GOTO :errorlocal ) REM Ending the local environment to be able to propagate the TMP/TEMP variables to the calling script ENDLOCAL +IF NOT "%COMMAND_CWD%"=="" ( + call ECHO [ci_build] Changing CWD to %COMMAND_CWD% + call CD %COMMAND_CWD% + IF ERRORLEVEL 1 ( + ECHO [ci_build] Failed to change directory to %COMMAND_CWD% + GOTO :error + ) +) + REM Jenkins does not defined TMP IF "%TMP%"=="" ( IF "%WORKSPACE%"=="" ( @@ -41,6 +45,7 @@ IF "%TMP%"=="" ( EXIT /b 0 -:error +:errorlocal ENDLOCAL +:error EXIT /b 1 \ No newline at end of file From 6481b147fc8136a889fefc4c60838c2f6a6d42f5 Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Fri, 21 Jan 2022 16:03:39 -0800 Subject: [PATCH 088/136] style and other fixes Signed-off-by: Scott Murray --- ...omEditorComponents_EntityReferenceAdded.py | 38 +++++++++---------- .../editor_entity_utils.py | 2 +- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py index 7f15702199..66efab9e01 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py @@ -86,9 +86,9 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): 7) Add item to 'EntityIdReferences' 8) Update item in 'EntityIdReferences' 9) Remove item from 'EntityIdReferences' - 10) Rest the container property then put one entity reference back for further tests + 10) Reset the container property then put one entity reference back for further tests 11) Remove component - 12) Undo component remove + 12) UNDO component remove 13) Enter/Exit game mode. 14) Test IsHidden. 15) Test IsVisible. @@ -160,55 +160,53 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): AtomComponentProperties.entity_reference('EntityIdReferences'))) # 6. Append item to 'EntityIdReferences' - entity_reference_component.append_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), - test_1.id) + entity_reference_component.append_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), test_1.id) Report.result( Tests.container_append, entity_reference_component.get_container_item( AtomComponentProperties.entity_reference('EntityIdReferences'), 0) == test_1.id) # 7. Add item to 'EntityIdReferences' - entity_reference_component.add_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), - 1, test_1.id) + entity_reference_component.add_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), 1, test_1.id) Report.result( Tests.container_add, entity_reference_component.get_container_count( - AtomComponentProperties.entity_reference('EntityIdReferences')) == 2 - ) + AtomComponentProperties.entity_reference('EntityIdReferences')) == 2) # 8. Update item in 'EntityIdReferences' - entity_reference_component.update_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), - 1, test_2.id) + entity_reference_component.update_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), 1, test_2.id) Report.result( Tests.container_update, entity_reference_component.get_container_item( AtomComponentProperties.entity_reference('EntityIdReferences'), 1) == test_2.id) # 9. Remove item from 'EntityIdReferences' - entity_reference_component.append_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), - test_3.id) + entity_reference_component.append_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), test_3.id) count_before = entity_reference_component.get_container_count( AtomComponentProperties.entity_reference('EntityIdReferences')) - entity_reference_component.remove_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), - 1) + entity_reference_component.remove_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), 1) count_after = entity_reference_component.get_container_count( AtomComponentProperties.entity_reference('EntityIdReferences')) Report.result( Tests.container_remove, ((count_before == 3) and (count_after == 2) and (entity_reference_component.get_container_item( - AtomComponentProperties.entity_reference('EntityIdReferences'), 1) == test_3.id)) - ) + AtomComponentProperties.entity_reference('EntityIdReferences'), 1) == test_3.id))) - # 10. Rest the container property then put one entity reference back for further tests + # 10. Reset the container property then put one entity reference back for further tests entity_reference_component.reset_container(AtomComponentProperties.entity_reference('EntityIdReferences')) general.idle_wait_frames(1) Report.result( Tests.container_reset, entity_reference_component.get_container_count( AtomComponentProperties.entity_reference('EntityIdReferences')) == 0) - entity_reference_component.append_container_item(AtomComponentProperties.entity_reference('EntityIdReferences'), - test_1.id) + entity_reference_component.append_container_item( + AtomComponentProperties.entity_reference('EntityIdReferences'), test_1.id) # 11. Remove component entity_reference_entity.remove_component(AtomComponentProperties.entity_reference()) @@ -216,7 +214,7 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): Report.result(Tests.entity_reference_component_removed, not entity_reference_entity.has_component( AtomComponentProperties.entity_reference())) - # 12. Undo component remove + # 12. UNDO component remove general.undo() general.idle_wait_frames(1) Report.result(Tests.entity_reference_component, entity_reference_entity.has_component( diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py index f19bf540a9..d8d4a77a65 100644 --- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py +++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py @@ -477,7 +477,7 @@ class EditorEntity: remove_success = editor.EditorComponentAPIBus(bus.Broadcast, "RemoveComponents", component_ids) assert ( remove_success - ), f"Failure: could not remove component from '{self.get_name()}'" + ), f"Failure: could not remove component from entity '{self.get_name()}'" def get_components_of_type(self, component_names: list) -> List[EditorComponent]: """ From dbd6ddbc1c62db227344407a1e51421380adde1c Mon Sep 17 00:00:00 2001 From: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> Date: Fri, 21 Jan 2022 18:05:19 -0600 Subject: [PATCH 089/136] Optimized Gradient Previewer (#7074) * Faster method with older one commented out for profiling. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Removed commented-out code Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Addressed PR feedback, fixed subtle bug in interlace math. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Fixed unrelated bug in terrain cmake file. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> * Fix linux compile error. Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com> --- .../Editor/EditorGradientPreviewRenderer.h | 202 +++++++++++------- Gems/Terrain/Code/CMakeLists.txt | 1 - 2 files changed, 126 insertions(+), 77 deletions(-) diff --git a/Gems/GradientSignal/Code/Include/GradientSignal/Editor/EditorGradientPreviewRenderer.h b/Gems/GradientSignal/Code/Include/GradientSignal/Editor/EditorGradientPreviewRenderer.h index 2790a668a3..db39431ba1 100644 --- a/Gems/GradientSignal/Code/Include/GradientSignal/Editor/EditorGradientPreviewRenderer.h +++ b/Gems/GradientSignal/Code/Include/GradientSignal/Editor/EditorGradientPreviewRenderer.h @@ -25,7 +25,6 @@ #include #include - namespace GradientSignal { //! EditorGradientPreviewUpdateJob offloads the creation of a gradient preview image to another thread. @@ -223,7 +222,7 @@ namespace GradientSignal // If you ever want to make this use a smaller number of passes, set this value to any even number. // A value of 0 is the same as "non-interlaced", 6 would exactly use the Adam7 algorithm, etc. // It's currently clamping to 30 as a somewhat aribtrary choice. - const uint64_t maxFinalInterlacingPass = 30; + const int64_t maxFinalInterlacingPass = 30; m_finalInterlacingPass = AZ::GetMin(m_finalInterlacingPass, maxFinalInterlacingPass); // Finally, lock our mutex, modify our status variables, and start the Job. @@ -238,6 +237,8 @@ namespace GradientSignal //! Process runs exactly once for each time Start() is called on a Job, and processes on a Job worker thread. void Process() override { + AZ_PROFILE_FUNCTION(Entity); + // Guard against the case that we're trying to cancel even before we've started to run. if (!m_shouldCancel) { @@ -247,88 +248,136 @@ namespace GradientSignal // This is the "striding value". When walking directly through our preview image bits() buffer, there might be // extra pad bytes for each line due to alignment. We use this to make sure we start writing each line at the right byte offset. - const uint64_t imageBytesPerLine = m_previewImage->bytesPerLine(); + const int64_t imageBytesPerLine = m_previewImage->bytesPerLine(); - // The following are all used for calculating our interlaced pixel updates. + // Keep track of the total number of pixels that we intend to process. For easy interlacing calculations, we always use + // square power-of-two conceptual images, but we'll skip any pixels that fall outside of our actual image bounds. + const int64_t totalPixels = (m_imageBoundsPowerOfTwo * m_imageBoundsPowerOfTwo); - // The current interlace pass that we're on. - int64_t curPass = 0; - // The index of the first pixel for this pass. This is used to calculate the relative pixel index per pass. - uint64_t firstPixelPerPass = 0; - // Total number of pixels that we'll process per pass. After the first two passes, the amount doubles per pass till we reach 100%. - uint64_t totalPixelsPerPass = (m_imageBoundsPowerOfTwo * m_imageBoundsPowerOfTwo) / (1LL << (m_finalInterlacingPass - curPass)); - // The general interlace formulas need a multiplier and an offset for x and y to apply to each relative pixel index. - // The pixel multipliers start high and reduce on each pass to increase the pixel density per pass. - // The pixel offsets alternate between 0 and a reducing number because we start on aligned grids, then fill in the midpoints - // of the grids on every other pass. - uint64_t xPixelMult = 1LL << (m_finalInterlacingPass / 2); - uint64_t xPixelOffset = 0; - uint64_t yPixelMult = 1LL << (m_finalInterlacingPass / 2); - uint64_t yPixelOffset = 0; + // Preallocate buffers for our gradient lookup positions, our gradient output values, and the corresponding pixel buffer + // index to store the value into. These allow us to fetch gradient values in bulk, which is much faster than fetching them + // individually. The max size we'll need is for our last interacing pass which requests 50% of our total pixels (as + // described further below), so that's what we will preallocate. + AZStd::vector gradientLookupPositions(totalPixels / 2); + AZStd::vector gradientValues(totalPixels / 2); + AZStd::vector pixelBufferIndex(totalPixels / 2); - // The heart of the processing - loop through each pixel using interlaced indexing, get the gradient value, and write it into - // the pixel buffer. On each pixel, we also check to see if the main thread requested a cancel so that we can early-out. - // The loop itself runs through the full square power-of-two bounds that encapsulates our image so that we can perform our - // interlaced indexing easily, but we skip processing any pixel that falls outside the actual image bounds. - for (uint64_t curPixel = 0; (!m_shouldCancel) && (curPixel < (m_imageBoundsPowerOfTwo * m_imageBoundsPowerOfTwo)); curPixel++) + // The following loop uses a variant of the Adam7 interlacing algorithm that's been generalized to work for N passes, + // instead of exactly 7 passes. The first two passes fill in 1 pixel each, and then each subsequent pass doubles the + // number of pixels it fills in, until the last pass fills in 50%. + // Note that m_finalInteracingPass contains the value of the final pass to process, not the total number of passes. + // On each pass, we'll also early-out if the main thread requested a cancellation. + for (int64_t curPass = 0; (!m_shouldCancel) && (curPass <= m_finalInterlacingPass); curPass++) { - // Check to see if we've finished the pixels for this pass and need to move on to the next pass. - if (curPixel >= (firstPixelPerPass + totalPixelsPerPass)) + gradientLookupPositions.clear(); + pixelBufferIndex.clear(); + gradientValues.clear(); + + // The general interlace formulas need a multiplier and an offset for x and y to apply to each relative pixel index. + // + // The first 3 passes are a little different than the others because they establish the base pattern: + // 1 . . . 2 . . . + // . . . . . . . . + // . . . . . . . . + // . . . . . . . . + // 3 . . . 3 . . . + // . . . . . . . . + // . . . . . . . . + // . . . . . . . . + // + // Every 2 passes from then on do the same thing, with shrinking grids. One pass fills in the grid X midpoints on the + // lines that were already processed, and the second pass fills in all the equivalent points on the Y grid midpoints + // x . 4 . x . 4 . + // . . . . . . . . + // 5 . 5 . 5 . 5 . + // . . . . . . . . + // x . 4 . x . 4 . + // . . . . . . . . + // 5 . 5 . 5 . 5 . + // . . . . . . . . + // + // x 6 x 6 x 6 x 6 + // 7 7 7 7 7 7 7 7 + // x 6 x 6 x 6 x 6 + // 7 7 7 7 7 7 7 7 + // x 6 x 6 x 6 x 6 + // 7 7 7 7 7 7 7 7 + // x 6 x 6 x 6 x 6 + // 7 7 7 7 7 7 7 7 + // + // The total number of pixels processed per pass starts at 1 pixel each for the first two passes, then doubles per + // pass till we reach 50% in the last pass, since all the other passes before it will have covered the other 50%. + // Ex: 7 passes will do N/64, N/64, N/32, N/16, N/8, N/4, N/2 pixels per pass. + + + // For X, we want our starting pixel offset to alternate between 0 and a decreasing power of 2 on every pass, and + // our stride to decrease by a power of 2 every two passes, ending with an offset of 0 and a stride of 1 on the last + // pass. + const int64_t xOffsetShifter = AZ::GetMin(m_finalInterlacingPass - curPass, m_finalInterlacingPass - 1); + const int64_t xPixelOffset = (curPass % 2) * (1LL << (xOffsetShifter / 2)); + const int64_t xPixelStride = 1LL << ((xOffsetShifter + 1) / 2); + + // For Y, we want our starting pixel offset and our stride to behave the same as X, except that we hold our starting + // offset and stride for one additional pass which is what causes the first 3 passes to behave differently than the + // rest. The pass offset between X and Y is also what causes the pattern to keep filling in pixels and lines that + // haven't already been processed. + const int64_t laggingPass = AZ::GetMax(curPass - 1, 0); + const int64_t yOffsetShifter = AZ::GetMin(m_finalInterlacingPass - laggingPass, m_finalInterlacingPass - 1); + const int64_t yPixelOffset = (laggingPass % 2) * (1LL << (yOffsetShifter / 2)); + const int64_t yPixelStride = 1LL << ((yOffsetShifter + 1) / 2); + + // First, we loop and fill in all the gradientLookupPositions and pixelBufferIndex values for any pixels that don't + // get culled out. We're using a power of two for calculating our interlacing offsets and strides, but we don't need + // to actually process any of those pixels that fall outside our image bounds, so we end our loops at the bounds. + for (int64_t y = yPixelOffset; y < m_imageBoundsY; y += yPixelStride) { - curPass++; - - // Adjust our interlacing formula adjustments on each pass. These will cause us to process an increasing - // number of pixels at a higher density on each pass, interleaving in a way that ensures each pixel is only - // processed once at the end. - yPixelMult = xPixelMult; - yPixelOffset = xPixelOffset; - xPixelMult = 1LL << ((m_finalInterlacingPass - curPass + 1) / 2); - xPixelOffset = (curPass % 2) * (1LL << ((m_finalInterlacingPass - curPass) / 2)); - - firstPixelPerPass += totalPixelsPerPass; - totalPixelsPerPass = (m_imageBoundsPowerOfTwo * m_imageBoundsPowerOfTwo) / (1LL << (m_finalInterlacingPass - curPass + 1)); - } - - // Here's where interlacing happens. If this were non-interlaced, we'd simply have the following: - // x = curPixel % m_imageBoundsPowerOfTwo - // y = curPixel / m_imageBoundsPowerOfTwo - uint64_t adjustedPixel = curPixel - firstPixelPerPass; - uint64_t x = ((adjustedPixel * xPixelMult) + xPixelOffset) % m_imageBoundsPowerOfTwo; - uint64_t y = ((((adjustedPixel * xPixelMult) + xPixelOffset) / m_imageBoundsPowerOfTwo) * yPixelMult) + yPixelOffset; - - // Since we're using a power of two for calculating our interlacing, it's possible to get pixel offsets beyond the bounds - // of our actual image. We just skip those and continue on to the next pixel. - if ((x >= m_imageBoundsX) || (y >= m_imageBoundsY)) - { - continue; - } - - // Now that we've calculated the pixel position, update it with the gradient value. - { - // Invert world y to match axis. (We use "imageBoundsY- 1" to invert because our loop doesn't go all the way to imageBoundsY) - AZ::Vector3 uvw(static_cast(x), static_cast((m_imageBoundsY - 1) - y), 0.0f); - - GradientSampleParams sampleParams; - sampleParams.m_position = m_previewBoundsStart + (uvw * m_pixelToBoundsScale) + m_scaledTexelOffset; - - bool inBounds = true; - if (m_constrainToShape) + for (int64_t x = xPixelOffset; x < m_imageBoundsX; x += xPixelStride) { - LmbrCentral::ShapeComponentRequestsBus::EventResult(inBounds, m_previewEntityId, &LmbrCentral::ShapeComponentRequestsBus::Events::IsPointInside, sampleParams.m_position); - } + // Map the pixel coordinate back into world coordinates for the shape and gradient queries. Note that we + // invert world y to match the world axis. (We use "imageBoundsY- 1" to invert because our loop doesn't go all + // the way to imageBoundsY) + AZ::Vector3 uvw(static_cast(x), static_cast((m_imageBoundsY - 1) - y), 0.0f); + AZ::Vector3 position = m_previewBoundsStart + (uvw * m_pixelToBoundsScale) + m_scaledTexelOffset; - float sample = inBounds ? m_sampler.GetValue(sampleParams) : 0.0f; + // If our preview is only drawing what appears inside the given shape, check to see if the pixel should be + // drawn. + bool inBounds = true; + if (m_constrainToShape) + { + LmbrCentral::ShapeComponentRequestsBus::EventResult( + inBounds, m_previewEntityId, &LmbrCentral::ShapeComponentRequestsBus::Events::IsPointInside, position); + } + + // If we're drawing this pixel, push it into our buffer of lookup positions. + if (inBounds) + { + gradientLookupPositions.emplace_back(position); + pixelBufferIndex.emplace_back(((m_centeringOffsetY + y) * imageBytesPerLine) + (m_centeringOffsetX + x)); + } + } + } + + // Resize our output buffer to match our input buffer and query for all the gradient values at once. + gradientValues.resize(gradientLookupPositions.size()); + m_sampler.GetValues(gradientLookupPositions, gradientValues); + + // For each output value, run it through a filter if we were given one, then store it in the pixel buffer. + for (size_t index = 0; index < gradientLookupPositions.size(); index++) + { + float sample = gradientValues[index]; if (m_filterFunc) { + GradientSampleParams sampleParams; + sampleParams.m_position = gradientLookupPositions[index]; sample = m_filterFunc(sample, sampleParams); } - buffer[((m_centeringOffsetY + y) * imageBytesPerLine) + (m_centeringOffsetX + x)] = static_cast(sample * 255); - } + buffer[pixelBufferIndex[index]] = static_cast(sample * 255); - // Notify the main thread via atomic bool that the image has changed by at least one pixel. - m_refreshUI = true; + // Notify the main thread via atomic bool that the image has changed by at least one pixel. + m_refreshUI = true; + } } } @@ -356,15 +405,15 @@ namespace GradientSignal AZ::EntityId m_previewEntityId; // Values calculated during preview setup that we'll use during processing - uint64_t m_imageBoundsX = 0; - uint64_t m_imageBoundsY = 0; - uint64_t m_centeringOffsetX = 0; - uint64_t m_centeringOffsetY = 0; + int64_t m_imageBoundsX = 0; + int64_t m_imageBoundsY = 0; + int64_t m_centeringOffsetX = 0; + int64_t m_centeringOffsetY = 0; AZ::Vector3 m_previewBoundsStart; AZ::Vector3 m_pixelToBoundsScale; AZ::Vector3 m_scaledTexelOffset; - uint64_t m_imageBoundsPowerOfTwo = 1; - uint64_t m_finalInterlacingPass = 0; + int64_t m_imageBoundsPowerOfTwo = 1; + int64_t m_finalInterlacingPass = 0; // Communication / synchronization mechanisms between the different threads AZStd::mutex m_previewMutex; @@ -456,3 +505,4 @@ namespace GradientSignal EditorGradientPreviewUpdateJob* m_updateJob = nullptr; }; } //namespace GradientSignal + diff --git a/Gems/Terrain/Code/CMakeLists.txt b/Gems/Terrain/Code/CMakeLists.txt index 69a1bef3c0..44e33b7008 100644 --- a/Gems/Terrain/Code/CMakeLists.txt +++ b/Gems/Terrain/Code/CMakeLists.txt @@ -98,7 +98,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) NAME Terrain.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} NAMESPACE Gem FILES_CMAKE - terrain_files.cmake terrain_tests_files.cmake INCLUDE_DIRECTORIES PRIVATE From dd7706f9feec5370a8d6b5e9b2565c13421016e9 Mon Sep 17 00:00:00 2001 From: chiyenteng <82238204+chiyenteng@users.noreply.github.com> Date: Fri, 21 Jan 2022 16:23:31 -0800 Subject: [PATCH 090/136] Fire OnEditorEntityCreated notification in SandboxIntegrationManager::CreateNewEntityAtPosition (#7079) * Ensure to fire OnEditorEntityCreated notification in SandboxIntegrationManager::CreateNewEntityAtPosition Signed-off-by: chiyenteng <82238204+chiyenteng@users.noreply.github.com> * Ensure to fire OnEditorEntityCreated notification in SandboxIntegrationManager::CreateNewEntityAtPosition Signed-off-by: chiyenteng <82238204+chiyenteng@users.noreply.github.com> * convert test AreaNodes_DependentComponentsAdded to use prefab system Signed-off-by: chiyenteng <82238204+chiyenteng@users.noreply.github.com> * Prevent SetupEditorEntity being called twice Signed-off-by: chiyenteng <82238204+chiyenteng@users.noreply.github.com> --- .../AreaNodes_DependentComponentsAdded.py | 2 +- .../TestSuite_Main_Optimized.py | 10 +++++--- .../Entity/EditorEntityContextBus.h | 5 +++- .../Entity/EditorEntityContextComponent.cpp | 23 +++++-------------- .../Entity/EditorEntityContextComponent.h | 5 +--- .../Prefab/PrefabPublicHandler.cpp | 1 + 6 files changed, 20 insertions(+), 26 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py index c69ce77041..8151299cea 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py @@ -69,7 +69,7 @@ def AreaNodes_DependentComponentsAdded(): # Open an existing simple level helper.init_idle() - helper.open_level("Physics", "Base") + helper.open_level("", "Base") # Open Landscape Canvas tool and verify general.open_pane('Landscape Canvas') diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Main_Optimized.py index 402df133cb..e501b3ad3b 100644 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Main_Optimized.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/TestSuite_Main_Optimized.py @@ -12,6 +12,13 @@ import ly_test_tools.environment.file_system as file_system import ly_test_tools._internal.pytest_plugin as internal_plugin from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite +@pytest.mark.SUITE_periodic +@pytest.mark.parametrize("launcher_platform", ['windows_editor']) +@pytest.mark.parametrize("project", ["AutomatedTesting"]) +class TestAutomationWithPrefabSystemEnabled(EditorTestSuite): + + class test_LandscapeCanvas_AreaNodes_DependentComponentsAdded(EditorSharedTest): + from .EditorScripts import AreaNodes_DependentComponentsAdded as test_module @pytest.mark.SUITE_periodic @pytest.mark.parametrize("launcher_platform", ['windows_editor']) @@ -26,9 +33,6 @@ class TestAutomation(EditorTestSuite): class test_LandscapeCanvas_GradientMixer_NodeConstruction(EditorSharedTest): from .EditorScripts import GradientMixer_NodeConstruction as test_module - class test_LandscapeCanvas_AreaNodes_DependentComponentsAdded(EditorSharedTest): - from .EditorScripts import AreaNodes_DependentComponentsAdded as test_module - class test_LandscapeCanvas_AreaNodes_EntityCreatedOnNodeAdd(EditorSharedTest): from .EditorScripts import AreaNodes_EntityCreatedOnNodeAdd as test_module diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextBus.h index 1a5ba60bdf..29d9b742e2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextBus.h @@ -63,9 +63,12 @@ namespace AzToolsFramework /// Registers an existing set of entities with the editor context. virtual void AddEditorEntities(const EntityList& entities) = 0; - /// Registers an existing set of entities with the editor context. + /// Triggers registered callbacks for an existing set of entities with the editor context. virtual void HandleEntitiesAdded(const EntityList& entities) = 0; + /// Creates an editor ready entity, and sends out notification for the creation. + virtual void FinalizeEditorEntity(AZ::Entity* entity) = 0; + /// Destroys an entity in the editor context. /// \return whether or not the entity was destroyed. A false return value signifies the entity did not belong to the game context. virtual bool DestroyEditorEntity(AZ::EntityId entityId) = 0; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp index 470ca8b9ea..95b3f2bf93 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.cpp @@ -227,14 +227,8 @@ namespace AzToolsFramework { AZ::Entity* entity = CreateEntity(name); AZ_Assert(entity != nullptr, "Entity with name %s couldn't be created.", name); - if (m_isLegacySliceService) - { - FinalizeEditorEntity(entity); - } - else - { - EditorEntityContextNotificationBus::Broadcast(&EditorEntityContextNotification::OnEditorEntityCreated, entity->GetId()); - } + FinalizeEditorEntity(entity); + return entity->GetId(); } @@ -263,14 +257,7 @@ namespace AzToolsFramework entity = aznew AZ::Entity(entityId, name); AZ_Assert(entity != nullptr, "Entity with name %s couldn't be created.", name); AddEntity(entity); - if (m_isLegacySliceService) - { - FinalizeEditorEntity(entity); - } - else - { - EditorEntityContextNotificationBus::Broadcast(&EditorEntityContextNotification::OnEditorEntityCreated, entity->GetId()); - } + FinalizeEditorEntity(entity); return entity->GetId(); } @@ -284,10 +271,12 @@ namespace AzToolsFramework { return; } - SetupEditorEntity(entity); // Store creation undo command. + if (m_isLegacySliceService) { + SetupEditorEntity(entity); + ScopedUndoBatch undoBatch("Create Entity"); EntityCreateCommand* command = aznew EntityCreateCommand(static_cast(entity->GetId())); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.h index 28cf67c0f2..4e04b81c67 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityContextComponent.h @@ -81,6 +81,7 @@ namespace AzToolsFramework void AddEditorEntity(AZ::Entity* entity) override; void AddEditorEntities(const EntityList& entities) override; void HandleEntitiesAdded(const EntityList& entities) override; + void FinalizeEditorEntity(AZ::Entity* entity) override; bool CloneEditorEntities(const EntityIdList& sourceEntities, EntityList& resultEntities, AZ::SliceComponent::EntityIdToEntityIdMap& sourceToCloneEntityIdMap) override; @@ -142,13 +143,9 @@ namespace AzToolsFramework } protected: - void OnContextEntitiesAdded(const EntityList& entities) override; void OnContextEntityRemoved(const AZ::EntityId& id) override; - // Helper function for creating editor ready entities. - void FinalizeEditorEntity(AZ::Entity* entity); - void SetupEditorEntity(AZ::Entity* entity); void SetupEditorEntities(const EntityList& entities); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 0c1fb9bed2..62003cd846 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -661,6 +661,7 @@ namespace AzToolsFramework entityOwningInstance.AddEntity(*entity, entityAlias); EditorEntityContextRequestBus::Broadcast(&EditorEntityContextRequestBus::Events::HandleEntitiesAdded, EntityList{entity}); + EditorEntityContextRequestBus::Broadcast(&EditorEntityContextRequestBus::Events::FinalizeEditorEntity, entity); AZ::Transform transform = AZ::Transform::CreateIdentity(); transform.SetTranslation(position); From 1f7040c6b825361e54e6d502d8452e82543d56b7 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 21 Jan 2022 18:28:13 -0600 Subject: [PATCH 091/136] Updating mock calls in unit_test_manifest.py to fix test (#7090) The manifest.py `get_all_templates` method was modified to add a call to `get_all_gems` and `get_gem_templates`. Those calls were not mocked, so they tried to load an o3de_manifest.json file that was on user's machine, which failed on the CI node. Also added a mock call for `load_o3de_manifest`, that validates that it is not called to catch this issue during Automated Review. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- scripts/o3de/tests/unit_test_manifest.py | 39 +++++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/scripts/o3de/tests/unit_test_manifest.py b/scripts/o3de/tests/unit_test_manifest.py index c7d7a7573b..c8eb916bf3 100644 --- a/scripts/o3de/tests/unit_test_manifest.py +++ b/scripts/o3de/tests/unit_test_manifest.py @@ -29,10 +29,17 @@ class TestGetTemplatesForCreation: def get_project_templates() -> list: return [] + @staticmethod + def get_gem_templates() -> list: + return [] + @staticmethod def get_engine_templates() -> list: return [pathlib.Path('D:/o3de/Templates/DefaultProject'), pathlib.Path('D:/o3de/Templates/DefaultGem')] + @staticmethod + def get_all_gems(project_path: pathlib.Path = None) -> list: + return [] @pytest.mark.parametrize("expected_template_paths", [ pytest.param([]) @@ -50,17 +57,25 @@ class TestGetTemplatesForCreation: as get_manifest_templates_patch, \ patch('o3de.manifest.get_project_templates', side_effect=self.get_project_templates)\ as get_project_templates_patch, \ + patch('o3de.manifest.get_gem_templates', side_effect=self.get_gem_templates) \ + as get_gem_templates_patch, \ patch('o3de.manifest.get_engine_templates', side_effect=self.get_engine_templates)\ as get_engine_templates_patch, \ + patch('o3de.manifest.get_all_gems', side_effect=self.get_all_gems) \ + as get_all_gems_patch, \ patch('o3de.validation.valid_o3de_template_json', return_value=True) \ as validate_template_json,\ patch('o3de.validation.valid_o3de_project_json', side_effect=validate_project_json) \ as validate_project_json,\ patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) \ - as validate_gem_json: + as validate_gem_json,\ + patch('o3de.manifest.load_o3de_manifest') as load_o3de_manifest_patch: templates = manifest.get_templates_for_generic_creation() assert templates == expected_template_paths + # make sure the o3de manifest isn't attempted to be loaded + load_o3de_manifest_patch.assert_not_called() + @pytest.mark.parametrize("expected_template_paths", [ pytest.param([pathlib.Path('D:/o3de/Templates/DefaultProject')]) @@ -78,17 +93,25 @@ class TestGetTemplatesForCreation: as get_manifest_templates_patch, \ patch('o3de.manifest.get_project_templates', side_effect=self.get_project_templates) \ as get_project_templates_patch, \ + patch('o3de.manifest.get_gem_templates', side_effect=self.get_gem_templates) \ + as get_gem_templates_patch, \ patch('o3de.manifest.get_engine_templates', side_effect=self.get_engine_templates) \ as get_engine_templates_patch, \ + patch('o3de.manifest.get_all_gems', side_effect=self.get_all_gems) \ + as get_all_gems_patch, \ patch('o3de.validation.valid_o3de_template_json', return_value=True) \ as validate_template_json, \ patch('o3de.validation.valid_o3de_project_json', side_effect=validate_project_json) \ as validate_project_json, \ patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) \ - as validate_gem_json: + as validate_gem_json,\ + patch('o3de.manifest.load_o3de_manifest') as load_o3de_manifest_patch: templates = manifest.get_templates_for_project_creation() assert templates == expected_template_paths + # make sure the o3de manifest isn't attempted to be loaded + load_o3de_manifest_patch.assert_not_called() + @pytest.mark.parametrize("expected_template_paths", [ pytest.param([pathlib.Path('D:/o3de/Templates/DefaultGem')]) @@ -106,13 +129,21 @@ class TestGetTemplatesForCreation: as get_manifest_templates_patch, \ patch('o3de.manifest.get_project_templates', side_effect=self.get_project_templates) \ as get_project_templates_patch, \ + patch('o3de.manifest.get_gem_templates', side_effect=self.get_gem_templates) \ + as get_gem_templates_patch, \ patch('o3de.manifest.get_engine_templates', side_effect=self.get_engine_templates) \ as get_engine_templates_patch, \ + patch('o3de.manifest.get_all_gems', side_effect=self.get_all_gems) \ + as get_all_gems_patch, \ patch('o3de.validation.valid_o3de_template_json', return_value=True) \ as validate_template_json, \ patch('o3de.validation.valid_o3de_project_json', side_effect=validate_project_json) \ as validate_project_json, \ patch('o3de.validation.valid_o3de_gem_json', side_effect=validate_gem_json) \ - as validate_gem_json: + as validate_gem_json, \ + patch('o3de.manifest.load_o3de_manifest') as load_o3de_manifest_patch: templates = manifest.get_templates_for_gem_creation() - assert templates == expected_template_paths \ No newline at end of file + assert templates == expected_template_paths + + # make sure the o3de manifest isn't attempted to be loaded + load_o3de_manifest_patch.assert_not_called() From 878ba24a3f617c1bed46dad8e0f7ee105f21af26 Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Fri, 21 Jan 2022 18:28:26 -0600 Subject: [PATCH 092/136] Removed unused AWSNativeSDK dependency from Editor (#7091) * Removed unused AWSNativeSDK dependency from Editor Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Remove build dependencies on the aws-cpp-sdk library from the Editor Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Code/Editor/CMakeLists.txt | 3 --- Code/Editor/CryEdit.cpp | 10 ---------- Code/Editor/IEditorImpl.cpp | 10 ---------- Code/Editor/IEditorImpl.h | 1 - Code/Editor/MainWindow.cpp | 5 ----- 5 files changed, 29 deletions(-) diff --git a/Code/Editor/CMakeLists.txt b/Code/Editor/CMakeLists.txt index 9d74f8e3a2..3f340e37d8 100644 --- a/Code/Editor/CMakeLists.txt +++ b/Code/Editor/CMakeLists.txt @@ -104,13 +104,11 @@ ly_add_target( 3rdParty::Qt::Concurrent 3rdParty::TIFF 3rdParty::squish-ccr - 3rdParty::AWSNativeSDK::STS Legacy::CryCommon Legacy::EditorCommon AZ::AzCore AZ::AzToolsFramework Gem::LmbrCentral.Static - AZ::AWSNativeSDKInit AZ::AtomCore Gem::Atom_RPI.Edit Gem::Atom_RPI.Public @@ -119,7 +117,6 @@ ly_add_target( Gem::AtomViewportDisplayInfo ${additional_dependencies} PUBLIC - 3rdParty::AWSNativeSDK::Core 3rdParty::Qt::Network Legacy::EditorCore RUNTIME_DEPENDENCIES diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 8789b31fdc..cb64d47a57 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -36,14 +36,6 @@ AZ_POP_DISABLE_WARNING #include #include -// Aws Native SDK -#include -#include -#include -#include -#include -#include - // AzCore #include #include @@ -144,9 +136,7 @@ AZ_POP_DISABLE_WARNING #include "Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.h" -// AWSNativeSDK #include -#include #if defined(AZ_PLATFORM_WINDOWS) diff --git a/Code/Editor/IEditorImpl.cpp b/Code/Editor/IEditorImpl.cpp index 38006c6fca..a2712b653d 100644 --- a/Code/Editor/IEditorImpl.cpp +++ b/Code/Editor/IEditorImpl.cpp @@ -16,12 +16,6 @@ // Qt #include -// AWS Native SDK -AZ_PUSH_DISABLE_WARNING(4251 4355 4996, "-Wunknown-warning-option") -#include -#include -AZ_POP_DISABLE_WARNING - // AzCore #include #include @@ -78,9 +72,6 @@ AZ_POP_DISABLE_WARNING // EditorCommon #include -// AWSNativeSDK -#include - #include "Core/QtEditorApplication.h" // for Editor::EditorQtApplication static CCryEditDoc * theDocument; @@ -132,7 +123,6 @@ CEditorImpl::CEditorImpl() , m_pSettingsManager(nullptr) , m_pLevelIndependentFileMan(nullptr) , m_pExportManager(nullptr) - , m_awsResourceManager(nullptr) , m_bMatEditMode(false) , m_bShowStatusText(true) , m_bInitialized(false) diff --git a/Code/Editor/IEditorImpl.h b/Code/Editor/IEditorImpl.h index 7867912941..354f631507 100644 --- a/Code/Editor/IEditorImpl.h +++ b/Code/Editor/IEditorImpl.h @@ -369,7 +369,6 @@ protected: QString m_selectFileBuffer; QString m_levelNameBuffer; - IAWSResourceManager* m_awsResourceManager; std::unique_ptr m_winWidgetManager; //! True if the editor is in material edit mode. Fast preview of materials. diff --git a/Code/Editor/MainWindow.cpp b/Code/Editor/MainWindow.cpp index bbebac96a3..63841299be 100644 --- a/Code/Editor/MainWindow.cpp +++ b/Code/Editor/MainWindow.cpp @@ -11,11 +11,6 @@ #include -// AWs Native SDK -AZ_PUSH_DISABLE_WARNING(4251 4355 4996, "-Wunknown-warning-option") -#include -AZ_POP_DISABLE_WARNING - // Qt #include #include From c4addbc0e0e693f63a8891625ea0d0b9719685fc Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Fri, 21 Jan 2022 22:08:31 -0800 Subject: [PATCH 093/136] Moved AutomatedTesting specific script translation assets from gems/canvas into AutomatedTesting Signed-off-by: Gene Walters --- ...orityToAutonomousNoParamsNotifyEvent.names | 0 .../AuthorityToAutonomousNotifyEvent.names | 0 ...ToAutonomous_PlayerNumberNotifyEvent.names | 56 ++++ ...AuthorityToClientNoParamsNotifyEvent.names | 0 ...tyToClientNoParams_PlayFxNotifyEvent.names | 50 ++++ .../AuthorityToClientNotifyEvent.names | 0 ...nomousToAuthorityNoParamsNotifyEvent.names | 0 .../AutonomousToAuthorityNotifyEvent.names | 0 .../ServerToAuthorityNoParamNotifyEvent.names | 0 .../ServerToAuthorityNotifyEvent.names | 0 ...verToAuthority_DealDamageNotifyEvent.names | 56 ++++ .../Classes/NetworkTestPlayerComponent.names | 242 +++++++++--------- ...tworkTestPlayerComponentNetworkInput.names | 0 13 files changed, 283 insertions(+), 121 deletions(-) rename {Gems/ScriptCanvas/Assets => AutomatedTesting/ScriptCanvas}/TranslationAssets/AZEvents/AuthorityToAutonomousNoParamsNotifyEvent.names (100%) rename {Gems/ScriptCanvas/Assets => AutomatedTesting/ScriptCanvas}/TranslationAssets/AZEvents/AuthorityToAutonomousNotifyEvent.names (100%) create mode 100644 AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AuthorityToAutonomous_PlayerNumberNotifyEvent.names rename {Gems/ScriptCanvas/Assets => AutomatedTesting/ScriptCanvas}/TranslationAssets/AZEvents/AuthorityToClientNoParamsNotifyEvent.names (100%) create mode 100644 AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AuthorityToClientNoParams_PlayFxNotifyEvent.names rename {Gems/ScriptCanvas/Assets => AutomatedTesting/ScriptCanvas}/TranslationAssets/AZEvents/AuthorityToClientNotifyEvent.names (100%) rename {Gems/ScriptCanvas/Assets => AutomatedTesting/ScriptCanvas}/TranslationAssets/AZEvents/AutonomousToAuthorityNoParamsNotifyEvent.names (100%) rename {Gems/ScriptCanvas/Assets => AutomatedTesting/ScriptCanvas}/TranslationAssets/AZEvents/AutonomousToAuthorityNotifyEvent.names (100%) rename {Gems/ScriptCanvas/Assets => AutomatedTesting/ScriptCanvas}/TranslationAssets/AZEvents/ServerToAuthorityNoParamNotifyEvent.names (100%) rename {Gems/ScriptCanvas/Assets => AutomatedTesting/ScriptCanvas}/TranslationAssets/AZEvents/ServerToAuthorityNotifyEvent.names (100%) create mode 100644 AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/ServerToAuthority_DealDamageNotifyEvent.names rename {Gems/ScriptCanvas/Assets => AutomatedTesting/ScriptCanvas}/TranslationAssets/Classes/NetworkTestPlayerComponent.names (90%) rename {Gems/ScriptCanvas/Assets => AutomatedTesting/ScriptCanvas}/TranslationAssets/Classes/NetworkTestPlayerComponentNetworkInput.names (100%) diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNoParamsNotifyEvent.names b/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AuthorityToAutonomousNoParamsNotifyEvent.names similarity index 100% rename from Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNoParamsNotifyEvent.names rename to AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AuthorityToAutonomousNoParamsNotifyEvent.names diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNotifyEvent.names b/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AuthorityToAutonomousNotifyEvent.names similarity index 100% rename from Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToAutonomousNotifyEvent.names rename to AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AuthorityToAutonomousNotifyEvent.names diff --git a/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AuthorityToAutonomous_PlayerNumberNotifyEvent.names b/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AuthorityToAutonomous_PlayerNumberNotifyEvent.names new file mode 100644 index 0000000000..7255c61d23 --- /dev/null +++ b/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AuthorityToAutonomous_PlayerNumberNotifyEvent.names @@ -0,0 +1,56 @@ +{ + "entries": [ + { + "base": "AuthorityToAutonomous_PlayerNumber Notify Event", + "context": "AZEventHandler", + "variant": "", + "details": { + "name": "Authority To Autonomous_ Player Number Notify Event" + }, + "slots": [ + { + "base": "player_number", + "details": { + "name": "player_number" + } + }, + { + "base": "AuthorityToAutonomous_PlayerNumber Notify Event", + "details": { + "name": "AuthorityToAutonomous_PlayerNumber Notify Event" + } + }, + { + "base": "Connect", + "details": { + "name": "Connect" + } + }, + { + "base": "Disconnect", + "details": { + "name": "Disconnect" + } + }, + { + "base": "On Connected", + "details": { + "name": "On Connected" + } + }, + { + "base": "On Disconnected", + "details": { + "name": "On Disconnected" + } + }, + { + "base": "OnEvent", + "details": { + "name": "OnEvent" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNoParamsNotifyEvent.names b/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AuthorityToClientNoParamsNotifyEvent.names similarity index 100% rename from Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNoParamsNotifyEvent.names rename to AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AuthorityToClientNoParamsNotifyEvent.names diff --git a/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AuthorityToClientNoParams_PlayFxNotifyEvent.names b/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AuthorityToClientNoParams_PlayFxNotifyEvent.names new file mode 100644 index 0000000000..3e0207a705 --- /dev/null +++ b/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AuthorityToClientNoParams_PlayFxNotifyEvent.names @@ -0,0 +1,50 @@ +{ + "entries": [ + { + "base": "AuthorityToClientNoParams_PlayFx Notify Event", + "context": "AZEventHandler", + "variant": "", + "details": { + "name": "Authority To Client No Params_ Play Fx Notify Event" + }, + "slots": [ + { + "base": "AuthorityToClientNoParams_PlayFx Notify Event", + "details": { + "name": "AuthorityToClientNoParams_PlayFx Notify Event" + } + }, + { + "base": "Connect", + "details": { + "name": "Connect" + } + }, + { + "base": "Disconnect", + "details": { + "name": "Disconnect" + } + }, + { + "base": "On Connected", + "details": { + "name": "On Connected" + } + }, + { + "base": "On Disconnected", + "details": { + "name": "On Disconnected" + } + }, + { + "base": "OnEvent", + "details": { + "name": "OnEvent" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNotifyEvent.names b/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AuthorityToClientNotifyEvent.names similarity index 100% rename from Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AuthorityToClientNotifyEvent.names rename to AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AuthorityToClientNotifyEvent.names diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNoParamsNotifyEvent.names b/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AutonomousToAuthorityNoParamsNotifyEvent.names similarity index 100% rename from Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNoParamsNotifyEvent.names rename to AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AutonomousToAuthorityNoParamsNotifyEvent.names diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNotifyEvent.names b/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AutonomousToAuthorityNotifyEvent.names similarity index 100% rename from Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/AutonomousToAuthorityNotifyEvent.names rename to AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/AutonomousToAuthorityNotifyEvent.names diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNoParamNotifyEvent.names b/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/ServerToAuthorityNoParamNotifyEvent.names similarity index 100% rename from Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNoParamNotifyEvent.names rename to AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/ServerToAuthorityNoParamNotifyEvent.names diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNotifyEvent.names b/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/ServerToAuthorityNotifyEvent.names similarity index 100% rename from Gems/ScriptCanvas/Assets/TranslationAssets/AZEvents/ServerToAuthorityNotifyEvent.names rename to AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/ServerToAuthorityNotifyEvent.names diff --git a/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/ServerToAuthority_DealDamageNotifyEvent.names b/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/ServerToAuthority_DealDamageNotifyEvent.names new file mode 100644 index 0000000000..2505d9593a --- /dev/null +++ b/AutomatedTesting/ScriptCanvas/TranslationAssets/AZEvents/ServerToAuthority_DealDamageNotifyEvent.names @@ -0,0 +1,56 @@ +{ + "entries": [ + { + "base": "ServerToAuthority_DealDamage Notify Event", + "context": "AZEventHandler", + "variant": "", + "details": { + "name": "Server To Authority_ Deal Damage Notify Event" + }, + "slots": [ + { + "base": "damage", + "details": { + "name": "damage" + } + }, + { + "base": "ServerToAuthority_DealDamage Notify Event", + "details": { + "name": "ServerToAuthority_DealDamage Notify Event" + } + }, + { + "base": "Connect", + "details": { + "name": "Connect" + } + }, + { + "base": "Disconnect", + "details": { + "name": "Disconnect" + } + }, + { + "base": "On Connected", + "details": { + "name": "On Connected" + } + }, + { + "base": "On Disconnected", + "details": { + "name": "On Disconnected" + } + }, + { + "base": "OnEvent", + "details": { + "name": "OnEvent" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponent.names b/AutomatedTesting/ScriptCanvas/TranslationAssets/Classes/NetworkTestPlayerComponent.names similarity index 90% rename from Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponent.names rename to AutomatedTesting/ScriptCanvas/TranslationAssets/Classes/NetworkTestPlayerComponent.names index 22636e0453..03e949f784 100644 --- a/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponent.names +++ b/AutomatedTesting/ScriptCanvas/TranslationAssets/Classes/NetworkTestPlayerComponent.names @@ -8,64 +8,6 @@ "name": "Network Test Player Component" }, "methods": [ - { - "base": "AutonomousToAuthority", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Autonomous To Authority" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Autonomous To Authority is invoked" - }, - "details": { - "name": "Autonomous To Authority" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "float" - } - } - ] - }, - { - "base": "ServerToAuthority", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Server To Authority" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Server To Authority is invoked" - }, - "details": { - "name": "Server To Authority" - }, - "params": [ - { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", - "details": { - "name": "Network Test Player Component" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "float" - } - } - ] - }, { "base": "AutonomousToAuthorityByEntityId", "context": "NetworkTestPlayerComponent", @@ -97,18 +39,72 @@ ] }, { - "base": "ServerToAuthorityByEntityId", + "base": "AuthorityToClientNoParams_PlayFxByEntityId", "context": "NetworkTestPlayerComponent", "entry": { "name": "In", - "tooltip": "When signaled, this will invoke Server To Authority By Entity Id" + "tooltip": "When signaled, this will invoke Authority To Client No Params_ Play Fx By Entity Id" }, "exit": { "name": "Out", - "tooltip": "Signaled after Server To Authority By Entity Id is invoked" + "tooltip": "Signaled after Authority To Client No Params_ Play Fx By Entity Id is invoked" }, "details": { - "name": "Server To Authority By Entity Id" + "name": "Authority To Client No Params_ Play Fx By Entity Id" + }, + "params": [ + { + "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", + "details": { + "name": "Source", + "tooltip": "The Source containing the NetworkTestPlayerComponentController" + } + } + ] + }, + { + "base": "AuthorityToAutonomous_PlayerNumberByEntityId", + "context": "NetworkTestPlayerComponent", + "entry": { + "name": "In", + "tooltip": "When signaled, this will invoke Authority To Autonomous_ Player Number By Entity Id" + }, + "exit": { + "name": "Out", + "tooltip": "Signaled after Authority To Autonomous_ Player Number By Entity Id is invoked" + }, + "details": { + "name": "Authority To Autonomous_ Player Number By Entity Id" + }, + "params": [ + { + "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", + "details": { + "name": "Source", + "tooltip": "The Source containing the NetworkTestPlayerComponentController" + } + }, + { + "typeid": "{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}", + "details": { + "name": "player_number" + } + } + ] + }, + { + "base": "ServerToAuthority_DealDamageByEntityId", + "context": "NetworkTestPlayerComponent", + "entry": { + "name": "In", + "tooltip": "When signaled, this will invoke Server To Authority_ Deal Damage By Entity Id" + }, + "exit": { + "name": "Out", + "tooltip": "Signaled after Server To Authority_ Deal Damage By Entity Id is invoked" + }, + "details": { + "name": "Server To Authority_ Deal Damage By Entity Id" }, "params": [ { @@ -121,47 +117,48 @@ { "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", "details": { - "name": "some Float" + "name": "damage" } } ] }, { - "base": "AutonomousToAuthorityNoParams", + "base": "AutonomousToAuthorityNoParamsByEntityId", "context": "NetworkTestPlayerComponent", "entry": { "name": "In", - "tooltip": "When signaled, this will invoke Autonomous To Authority No Params" + "tooltip": "When signaled, this will invoke Autonomous To Authority No Params By Entity Id" }, "exit": { "name": "Out", - "tooltip": "Signaled after Autonomous To Authority No Params is invoked" + "tooltip": "Signaled after Autonomous To Authority No Params By Entity Id is invoked" }, "details": { - "name": "Autonomous To Authority No Params" + "name": "Autonomous To Authority No Params By Entity Id" }, "params": [ { - "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", + "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", "details": { - "name": "Network Test Player Component" + "name": "Source", + "tooltip": "The Source containing the NetworkTestPlayerComponentController" } } ] }, { - "base": "AuthorityToAutonomous", + "base": "ServerToAuthority_DealDamage", "context": "NetworkTestPlayerComponent", "entry": { "name": "In", - "tooltip": "When signaled, this will invoke Authority To Autonomous" + "tooltip": "When signaled, this will invoke Server To Authority_ Deal Damage" }, "exit": { "name": "Out", - "tooltip": "Signaled after Authority To Autonomous is invoked" + "tooltip": "Signaled after Server To Authority_ Deal Damage is invoked" }, "details": { - "name": "Authority To Autonomous" + "name": "Server To Authority_ Deal Damage" }, "params": [ { @@ -179,18 +176,18 @@ ] }, { - "base": "AuthorityToClientNoParams", + "base": "AutonomousToAuthority", "context": "NetworkTestPlayerComponent", "entry": { "name": "In", - "tooltip": "When signaled, this will invoke Authority To Client No Params" + "tooltip": "When signaled, this will invoke Autonomous To Authority" }, "exit": { "name": "Out", - "tooltip": "Signaled after Authority To Client No Params is invoked" + "tooltip": "Signaled after Autonomous To Authority is invoked" }, "details": { - "name": "Authority To Client No Params" + "name": "Autonomous To Authority" }, "params": [ { @@ -198,6 +195,41 @@ "details": { "name": "Network Test Player Component" } + }, + { + "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", + "details": { + "name": "float" + } + } + ] + }, + { + "base": "AuthorityToAutonomous_PlayerNumber", + "context": "NetworkTestPlayerComponent", + "entry": { + "name": "In", + "tooltip": "When signaled, this will invoke Authority To Autonomous_ Player Number" + }, + "exit": { + "name": "Out", + "tooltip": "Signaled after Authority To Autonomous_ Player Number is invoked" + }, + "details": { + "name": "Authority To Autonomous_ Player Number" + }, + "params": [ + { + "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", + "details": { + "name": "Network Test Player Component" + } + }, + { + "typeid": "{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}", + "details": { + "name": "int" + } } ] }, @@ -308,79 +340,47 @@ ] }, { - "base": "AuthorityToClientNoParamsByEntityId", + "base": "AutonomousToAuthorityNoParams", "context": "NetworkTestPlayerComponent", "entry": { "name": "In", - "tooltip": "When signaled, this will invoke Authority To Client No Params By Entity Id" + "tooltip": "When signaled, this will invoke Autonomous To Authority No Params" }, "exit": { "name": "Out", - "tooltip": "Signaled after Authority To Client No Params By Entity Id is invoked" + "tooltip": "Signaled after Autonomous To Authority No Params is invoked" }, "details": { - "name": "Authority To Client No Params By Entity Id" + "name": "Autonomous To Authority No Params" }, "params": [ { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", + "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" + "name": "Network Test Player Component" } } ] }, { - "base": "AuthorityToAutonomousByEntityId", + "base": "AuthorityToClientNoParams_PlayFx", "context": "NetworkTestPlayerComponent", "entry": { "name": "In", - "tooltip": "When signaled, this will invoke Authority To Autonomous By Entity Id" + "tooltip": "When signaled, this will invoke Authority To Client No Params_ Play Fx" }, "exit": { "name": "Out", - "tooltip": "Signaled after Authority To Autonomous By Entity Id is invoked" + "tooltip": "Signaled after Authority To Client No Params_ Play Fx is invoked" }, "details": { - "name": "Authority To Autonomous By Entity Id" + "name": "Authority To Client No Params_ Play Fx" }, "params": [ { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", + "typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}", "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" - } - }, - { - "typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}", - "details": { - "name": "some Float" - } - } - ] - }, - { - "base": "AutonomousToAuthorityNoParamsByEntityId", - "context": "NetworkTestPlayerComponent", - "entry": { - "name": "In", - "tooltip": "When signaled, this will invoke Autonomous To Authority No Params By Entity Id" - }, - "exit": { - "name": "Out", - "tooltip": "Signaled after Autonomous To Authority No Params By Entity Id is invoked" - }, - "details": { - "name": "Autonomous To Authority No Params By Entity Id" - }, - "params": [ - { - "typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}", - "details": { - "name": "Source", - "tooltip": "The Source containing the NetworkTestPlayerComponentController" + "name": "Network Test Player Component" } } ] diff --git a/Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponentNetworkInput.names b/AutomatedTesting/ScriptCanvas/TranslationAssets/Classes/NetworkTestPlayerComponentNetworkInput.names similarity index 100% rename from Gems/ScriptCanvas/Assets/TranslationAssets/Classes/NetworkTestPlayerComponentNetworkInput.names rename to AutomatedTesting/ScriptCanvas/TranslationAssets/Classes/NetworkTestPlayerComponentNetworkInput.names From f20bf38f8886f9128e44c23f55f06ed70c501b04 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 23 Jan 2022 11:16:56 -0600 Subject: [PATCH 094/136] Atom Tools: Changed ME preset browser dialog into generic asset grid dialog in ATF Moving more potentially shared code out of the material editor into atom tools framework. This change consolidates the lighting preset browser, model preset browser, and the base dialogue that they shared into a single, grid based, asset selection dialog. AssetGridDialog should appear as a move and rename of PresetBrowserDialog but there are probably too many differences with new variable renames and SelectableAsset struct. Along the way I found examples showing that event bus broadcast accepted generic functions and lambdas. Used this to do a minor cleanup of the viewport settings inspector where the preset dialogs were initialized and other places that did several back to back bus calls. Signed-off-by: Guthrie Adams --- .../AssetGridDialog/AssetGridDialog.h | 69 +++++++ .../AssetGridDialog/AssetGridDialog.cpp | 179 ++++++++++++++++++ .../AssetGridDialog/AssetGridDialog.ui} | 6 +- .../Code/atomtoolsframework_files.cmake | 3 + .../LightingPresetBrowserDialog.cpp | 73 ------- .../LightingPresetBrowserDialog.h | 36 ---- .../ModelPresetBrowserDialog.cpp | 69 ------- .../ModelPresetBrowserDialog.h | 36 ---- .../PresetBrowserDialog.cpp | 133 ------------- .../PresetBrowserDialog.h | 46 ----- .../ViewportSettingsInspector.cpp | 146 ++++++++++---- .../Code/materialeditor_files.cmake | 7 - 12 files changed, 365 insertions(+), 438 deletions(-) create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/AssetGridDialog/AssetGridDialog.h create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/Source/AssetGridDialog/AssetGridDialog.cpp rename Gems/Atom/Tools/{MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.ui => AtomToolsFramework/Code/Source/AssetGridDialog/AssetGridDialog.ui} (86%) delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.cpp delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.h delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.cpp delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.h delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.cpp delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.h diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/AssetGridDialog/AssetGridDialog.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/AssetGridDialog/AssetGridDialog.h new file mode 100644 index 0000000000..afbe99a843 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/AssetGridDialog/AssetGridDialog.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#include +#endif + +#include +#include + +class QListWidgetItem; + +namespace Ui +{ + class AssetGridDialog; +} + +namespace AtomToolsFramework +{ + //! Widget for managing and selecting from a library of assets + class AssetGridDialog : public QDialog + { + Q_OBJECT + public: + struct SelectableAsset + { + AZ::Data::AssetId m_assetId; + QString m_title; + }; + + using SelectableAssetVector = AZStd::vector; + + AssetGridDialog( + const QString& title, + const SelectableAssetVector& selectableAssets, + const AZ::Data::AssetId& selectedAsset, + const QSize& tileSize, + QWidget* parent = nullptr); + + ~AssetGridDialog(); + + Q_SIGNALS: + void AssetSelected(const AZ::Data::AssetId& assetId); + + private: + AZ_DISABLE_COPY_MOVE(AssetGridDialog); + + QListWidgetItem* CreateListItem(const SelectableAsset& selectableAsset); + void SetupAssetList(); + void SetupSearchWidget(); + void SetupDialogButtons(); + void ApplySearchFilter(); + void ShowSearchMenu(const QPoint& pos); + void SelectCurrentAsset(); + void SelectInitialAsset(); + + QSize m_tileSize; + AZ::Data::AssetId m_initialSelectedAsset; + QScopedPointer m_ui; + }; +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AssetGridDialog/AssetGridDialog.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AssetGridDialog/AssetGridDialog.cpp new file mode 100644 index 0000000000..ed19c4890d --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AssetGridDialog/AssetGridDialog.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace AtomToolsFramework +{ + AssetGridDialog::AssetGridDialog( + const QString& title, + const SelectableAssetVector& selectableAssets, + const AZ::Data::AssetId& selectedAsset, + const QSize& tileSize, + QWidget* parent) + : QDialog(parent) + , m_tileSize(tileSize) + , m_initialSelectedAsset(selectedAsset) + , m_ui(new Ui::AssetGridDialog) + { + m_ui->setupUi(this); + + QSignalBlocker signalBlocker(this); + + setWindowTitle(title); + + SetupAssetList(); + SetupSearchWidget(); + SetupDialogButtons(); + setModal(true); + + QListWidgetItem* selectedItem = nullptr; + for (const auto& selectableAsset : selectableAssets) + { + QListWidgetItem* item = CreateListItem(selectableAsset); + if (!selectedItem || m_initialSelectedAsset == selectableAsset.m_assetId) + { + selectedItem = item; + } + } + + m_ui->m_assetList->sortItems(); + + if (selectedItem) + { + m_ui->m_assetList->setCurrentItem(selectedItem); + m_ui->m_assetList->scrollToItem(selectedItem); + } + } + + AssetGridDialog::~AssetGridDialog() + { + } + + QListWidgetItem* AssetGridDialog::CreateListItem(const SelectableAsset& selectableAsset) + { + const int itemBorder = aznumeric_cast( + AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/AtomToolsFramework/AssetGridDialog/ItemBorder", 4)); + const int itemSpacing = aznumeric_cast( + AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/AtomToolsFramework/AssetGridDialog/ItemSpacing", 10)); + const int headerHeight = aznumeric_cast( + AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/AtomToolsFramework/AssetGridDialog/HeaderHeight", 15)); + + const QSize gridSize = m_ui->m_assetList->gridSize(); + m_ui->m_assetList->setGridSize(QSize( + AZStd::max(gridSize.width(), m_tileSize.width() + itemSpacing), + AZStd::max(gridSize.height(), m_tileSize.height() + itemSpacing + headerHeight))); + + QListWidgetItem* item = new QListWidgetItem(m_ui->m_assetList); + item->setData(Qt::DisplayRole, selectableAsset.m_title); + item->setData(Qt::UserRole, QString(selectableAsset.m_assetId.ToString().c_str())); + item->setSizeHint(m_tileSize + QSize(itemBorder, itemBorder + headerHeight)); + m_ui->m_assetList->addItem(item); + + QWidget* itemWidget = new QWidget(m_ui->m_assetList); + itemWidget->setLayout(new QVBoxLayout(itemWidget)); + itemWidget->layout()->setSpacing(0); + itemWidget->layout()->setMargin(0); + + AzQtComponents::ElidingLabel* header = new AzQtComponents::ElidingLabel(itemWidget); + header->setText(selectableAsset.m_title); + header->setFixedSize(QSize(m_tileSize.width(), headerHeight)); + header->setMargin(0); + header->setStyleSheet("background-color: rgb(35, 35, 35)"); + AzQtComponents::Text::addPrimaryStyle(header); + AzQtComponents::Text::addLabelStyle(header); + itemWidget->layout()->addWidget(header); + + AzToolsFramework::Thumbnailer::ThumbnailWidget* thumbnail = new AzToolsFramework::Thumbnailer::ThumbnailWidget(itemWidget); + thumbnail->setFixedSize(m_tileSize); + thumbnail->SetThumbnailKey( + MAKE_TKEY(AzToolsFramework::AssetBrowser::ProductThumbnailKey, selectableAsset.m_assetId), + AzToolsFramework::Thumbnailer::ThumbnailContext::DefaultContext); + thumbnail->updateGeometry(); + itemWidget->layout()->addWidget(thumbnail); + + m_ui->m_assetList->setItemWidget(item, itemWidget); + + return item; + } + + void AssetGridDialog::SetupAssetList() + { + m_ui->m_assetList->setFlow(QListView::LeftToRight); + m_ui->m_assetList->setResizeMode(QListView::Adjust); + m_ui->m_assetList->setGridSize(QSize(0, 0)); + m_ui->m_assetList->setWrapping(true); + + QObject::connect(m_ui->m_assetList, &QListWidget::currentItemChanged, [this](){ SelectCurrentAsset(); }); + } + + void AssetGridDialog::SetupSearchWidget() + { + m_ui->m_searchWidget->setReadOnly(false); + m_ui->m_searchWidget->setContextMenuPolicy(Qt::CustomContextMenu); + AzQtComponents::LineEdit::applySearchStyle(m_ui->m_searchWidget); + connect(m_ui->m_searchWidget, &QLineEdit::textChanged, this, [this](){ ApplySearchFilter(); }); + connect(m_ui->m_searchWidget, &QWidget::customContextMenuRequested, this, [this](const QPoint& pos){ ShowSearchMenu(pos); }); + } + + void AssetGridDialog::SetupDialogButtons() + { + connect(m_ui->m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(m_ui->m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(this, &QDialog::rejected, this, [this](){ SelectInitialAsset(); }); + } + + void AssetGridDialog::ApplySearchFilter() + { + for (int index = 0; index < m_ui->m_assetList->count(); ++index) + { + QListWidgetItem* item = m_ui->m_assetList->item(index); + const QString& title = item->data(Qt::DisplayRole).toString(); + const QString filter = m_ui->m_searchWidget->text(); + item->setHidden(!filter.isEmpty() && !title.contains(filter, Qt::CaseInsensitive)); + } + } + + void AssetGridDialog::ShowSearchMenu(const QPoint& pos) + { + QScopedPointer menu(m_ui->m_searchWidget->createStandardContextMenu()); + menu->setStyleSheet("background-color: #333333"); + menu->exec(m_ui->m_searchWidget->mapToGlobal(pos)); + } + + void AssetGridDialog::SelectCurrentAsset() + { + auto item = m_ui->m_assetList->currentItem(); + if (item) + { + AZ::Data::AssetId assetId = AZ::Data::AssetId::CreateString(item->data(Qt::UserRole).toString().toUtf8().constData()); + emit AssetSelected(assetId); + } + } + + void AssetGridDialog::SelectInitialAsset() + { + emit AssetSelected(m_initialSelectedAsset); + } +} // namespace AtomToolsFramework + +#include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.ui b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AssetGridDialog/AssetGridDialog.ui similarity index 86% rename from Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.ui rename to Gems/Atom/Tools/AtomToolsFramework/Code/Source/AssetGridDialog/AssetGridDialog.ui index 172feb214c..e821a7443f 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.ui +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AssetGridDialog/AssetGridDialog.ui @@ -1,7 +1,7 @@ - PresetBrowserDialog - + AssetGridDialog + 0 @@ -26,7 +26,7 @@ - + diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake index 122e070096..db20452036 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake @@ -9,6 +9,7 @@ set(FILES Include/AtomToolsFramework/Application/AtomToolsApplication.h Include/AtomToolsFramework/AssetBrowser/AtomToolsAssetBrowser.h + Include/AtomToolsFramework/AssetGridDialog/AssetGridDialog.h Include/AtomToolsFramework/Communication/LocalServer.h Include/AtomToolsFramework/Communication/LocalSocket.h Include/AtomToolsFramework/Debug/TraceRecorder.h @@ -41,6 +42,8 @@ set(FILES Source/AssetBrowser/AtomToolsAssetBrowser.cpp Source/AssetBrowser/AtomToolsAssetBrowser.qrc Source/AssetBrowser/AtomToolsAssetBrowser.ui + Source/AssetGridDialog/AssetGridDialog.cpp + Source/AssetGridDialog/AssetGridDialog.ui Source/Communication/LocalServer.cpp Source/Communication/LocalSocket.cpp Source/Debug/TraceRecorder.cpp diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.cpp deleted file mode 100644 index cc7a851429..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include - -namespace MaterialEditor -{ - LightingPresetBrowserDialog::LightingPresetBrowserDialog(QWidget* parent) - : PresetBrowserDialog(parent) - { - QSignalBlocker signalBlocker(this); - - setWindowTitle("Lighting Preset Browser"); - - MaterialViewportRequestBus::BroadcastResult(m_initialPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); - - AZ::Render::LightingPresetPtrVector presets; - MaterialViewportRequestBus::BroadcastResult(presets, &MaterialViewportRequestBus::Events::GetLightingPresets); - AZStd::sort(presets.begin(), presets.end(), [](const auto& a, const auto& b) { return a->m_displayName < b->m_displayName; }); - - const int itemSize = aznumeric_cast( - AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/MaterialEditor/PresetBrowserDialog/LightingItemSize", 180)); - - QListWidgetItem* selectedItem = nullptr; - for (const auto& preset : presets) - { - AZStd::string path; - MaterialViewportRequestBus::BroadcastResult(path, &MaterialViewportRequestBus::Events::GetLightingPresetLastSavePath, preset); - QListWidgetItem* item = CreateListItem( - preset->m_displayName.c_str(), AZ::RPI::AssetUtils::MakeAssetId(path, 0).GetValue(), QSize(itemSize, itemSize)); - - m_listItemToPresetMap[item] = preset; - - if (m_initialPreset == preset) - { - selectedItem = item; - } - } - - if (selectedItem) - { - m_ui->m_presetList->setCurrentItem(selectedItem); - m_ui->m_presetList->scrollToItem(selectedItem); - } - } - - void LightingPresetBrowserDialog::SelectCurrentPreset() - { - auto presetItr = m_listItemToPresetMap.find(m_ui->m_presetList->currentItem()); - if (presetItr != m_listItemToPresetMap.end()) - { - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectLightingPreset, presetItr->second); - } - } - - void LightingPresetBrowserDialog::SelectInitialPreset() - { - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectLightingPreset, m_initialPreset); - } - -} // namespace MaterialEditor - -#include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.h deleted file mode 100644 index 68b52b3a98..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#endif - -#include - -namespace MaterialEditor -{ - //! Widget for managing and selecting from a library of preset assets - class LightingPresetBrowserDialog : public PresetBrowserDialog - { - Q_OBJECT - public: - LightingPresetBrowserDialog(QWidget* parent = nullptr); - ~LightingPresetBrowserDialog() = default; - - private: - void SelectCurrentPreset() override; - void SelectInitialPreset() override; - - AZ::Render::LightingPresetPtr m_initialPreset; - AZStd::unordered_map m_listItemToPresetMap; - }; -} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.cpp deleted file mode 100644 index e16b61d214..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include - -namespace MaterialEditor -{ - ModelPresetBrowserDialog::ModelPresetBrowserDialog(QWidget* parent) - : PresetBrowserDialog(parent) - { - QSignalBlocker signalBlocker(this); - - setWindowTitle("Model Preset Browser"); - - MaterialViewportRequestBus::BroadcastResult(m_initialPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection); - - AZ::Render::ModelPresetPtrVector presets; - MaterialViewportRequestBus::BroadcastResult(presets, &MaterialViewportRequestBus::Events::GetModelPresets); - AZStd::sort(presets.begin(), presets.end(), [](const auto& a, const auto& b) { return a->m_displayName < b->m_displayName; }); - - const int itemSize = aznumeric_cast( - AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/MaterialEditor/PresetBrowserDialog/ModelItemSize", 90)); - - QListWidgetItem* selectedItem = nullptr; - for (const auto& preset : presets) - { - QListWidgetItem* item = CreateListItem(preset->m_displayName.c_str(), preset->m_modelAsset.GetId(), QSize(itemSize, itemSize)); - - m_listItemToPresetMap[item] = preset; - - if (m_initialPreset == preset) - { - selectedItem = item; - } - } - - if (selectedItem) - { - m_ui->m_presetList->setCurrentItem(selectedItem); - m_ui->m_presetList->scrollToItem(selectedItem); - } - } - - void ModelPresetBrowserDialog::SelectCurrentPreset() - { - auto presetItr = m_listItemToPresetMap.find(m_ui->m_presetList->currentItem()); - if (presetItr != m_listItemToPresetMap.end()) - { - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectModelPreset, presetItr->second); - } - } - - void ModelPresetBrowserDialog::SelectInitialPreset() - { - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectModelPreset, m_initialPreset); - } - -} // namespace MaterialEditor - -#include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.h deleted file mode 100644 index a169d3053b..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#endif - -#include - -namespace MaterialEditor -{ - //! Widget for managing and selecting from a library of preset assets - class ModelPresetBrowserDialog : public PresetBrowserDialog - { - Q_OBJECT - public: - ModelPresetBrowserDialog(QWidget* parent = nullptr); - ~ModelPresetBrowserDialog() = default; - - private: - void SelectCurrentPreset() override; - void SelectInitialPreset() override; - - AZ::Render::ModelPresetPtr m_initialPreset; - AZStd::unordered_map m_listItemToPresetMap; - }; -} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.cpp deleted file mode 100644 index f2bb84dff6..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace MaterialEditor -{ - PresetBrowserDialog::PresetBrowserDialog(QWidget* parent) - : QDialog(parent) - , m_ui(new Ui::PresetBrowserDialog) - { - m_ui->setupUi(this); - - QSignalBlocker signalBlocker(this); - - SetupPresetList(); - SetupSearchWidget(); - SetupDialogButtons(); - setModal(true); - } - - void PresetBrowserDialog::SetupPresetList() - { - m_ui->m_presetList->setFlow(QListView::LeftToRight); - m_ui->m_presetList->setResizeMode(QListView::Adjust); - m_ui->m_presetList->setGridSize(QSize(0, 0)); - m_ui->m_presetList->setWrapping(true); - - QObject::connect(m_ui->m_presetList, &QListWidget::currentItemChanged, [this](){ SelectCurrentPreset(); }); - } - - QListWidgetItem* PresetBrowserDialog::CreateListItem(const QString& title, const AZ::Data::AssetId& assetId, const QSize& size) - { - const int itemBorder = aznumeric_cast( - AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/MaterialEditor/PresetBrowserDialog/ItemBorder", 4)); - const int itemSpacing = aznumeric_cast( - AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/MaterialEditor/PresetBrowserDialog/ItemSpacing", 10)); - const int headerHeight = aznumeric_cast( - AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/MaterialEditor/PresetBrowserDialog/HeaderHeight", 15)); - - const QSize gridSize = m_ui->m_presetList->gridSize(); - m_ui->m_presetList->setGridSize(QSize( - AZStd::max(gridSize.width(), size.width() + itemSpacing), - AZStd::max(gridSize.height(), size.height() + itemSpacing + headerHeight))); - - QListWidgetItem* item = new QListWidgetItem(m_ui->m_presetList); - item->setData(Qt::UserRole, title); - item->setSizeHint(size + QSize(itemBorder, itemBorder + headerHeight)); - m_ui->m_presetList->addItem(item); - - QWidget* itemWidget = new QWidget(m_ui->m_presetList); - itemWidget->setLayout(new QVBoxLayout(itemWidget)); - itemWidget->layout()->setSpacing(0); - itemWidget->layout()->setMargin(0); - - AzQtComponents::ElidingLabel* header = new AzQtComponents::ElidingLabel(itemWidget); - header->setText(title); - header->setFixedSize(QSize(size.width(), headerHeight)); - header->setMargin(0); - header->setStyleSheet("background-color: rgb(35, 35, 35)"); - AzQtComponents::Text::addPrimaryStyle(header); - AzQtComponents::Text::addLabelStyle(header); - itemWidget->layout()->addWidget(header); - - AzToolsFramework::Thumbnailer::ThumbnailWidget* thumbnail = new AzToolsFramework::Thumbnailer::ThumbnailWidget(itemWidget); - thumbnail->setFixedSize(size); - thumbnail->SetThumbnailKey( - MAKE_TKEY(AzToolsFramework::AssetBrowser::ProductThumbnailKey, assetId), - AzToolsFramework::Thumbnailer::ThumbnailContext::DefaultContext); - thumbnail->updateGeometry(); - itemWidget->layout()->addWidget(thumbnail); - - m_ui->m_presetList->setItemWidget(item, itemWidget); - - return item; - } - - void PresetBrowserDialog::SetupSearchWidget() - { - m_ui->m_searchWidget->setReadOnly(false); - m_ui->m_searchWidget->setContextMenuPolicy(Qt::CustomContextMenu); - AzQtComponents::LineEdit::applySearchStyle(m_ui->m_searchWidget); - connect(m_ui->m_searchWidget, &QLineEdit::textChanged, this, [this](){ ApplySearchFilter(); }); - connect(m_ui->m_searchWidget, &QWidget::customContextMenuRequested, this, [this](const QPoint& pos){ ShowSearchMenu(pos); }); - } - - void PresetBrowserDialog::SetupDialogButtons() - { - connect(m_ui->m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); - connect(m_ui->m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - connect(this, &QDialog::rejected, this, [this](){ SelectInitialPreset(); }); - } - - void PresetBrowserDialog::ApplySearchFilter() - { - for (int index = 0; index < m_ui->m_presetList->count(); ++index) - { - QListWidgetItem* item = m_ui->m_presetList->item(index); - const QString& title = item->data(Qt::UserRole).toString(); - const QString filter = m_ui->m_searchWidget->text(); - item->setHidden(!filter.isEmpty() && !title.contains(filter, Qt::CaseInsensitive)); - } - } - - void PresetBrowserDialog::ShowSearchMenu(const QPoint& pos) - { - QScopedPointer menu(m_ui->m_searchWidget->createStandardContextMenu()); - menu->setStyleSheet("background-color: #333333"); - menu->exec(m_ui->m_searchWidget->mapToGlobal(pos)); - } -} // namespace MaterialEditor - -#include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.h deleted file mode 100644 index 20e049f6f8..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/PresetBrowserDialogs/PresetBrowserDialog.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#endif - -#include - -class QImage; -class QListWidgetItem; -class QString; - -namespace MaterialEditor -{ - //! Widget for managing and selecting from a library of preset assets - class PresetBrowserDialog : public QDialog - { - Q_OBJECT - public: - PresetBrowserDialog(QWidget* parent = nullptr); - ~PresetBrowserDialog() = default; - -protected: - void SetupPresetList(); - QListWidgetItem* CreateListItem(const QString& title, const AZ::Data::AssetId& assetId, const QSize& size); - - void SetupSearchWidget(); - void SetupDialogButtons(); - void ApplySearchFilter(); - void ShowSearchMenu(const QPoint& pos); - virtual void SelectCurrentPreset() = 0; - virtual void SelectInitialPreset() = 0; - - QScopedPointer m_ui; - }; -} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp index 512059f1f6..dd01492031 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp @@ -6,13 +6,15 @@ * */ -#include +#include +#include +#include +#include #include #include #include +#include #include -#include -#include #include #include @@ -110,17 +112,53 @@ namespace MaterialEditor if (!savePath.empty()) { - AZ::Render::ModelPresetPtr preset; - MaterialViewportRequestBus::BroadcastResult( - preset, &MaterialViewportRequestBus::Events::AddModelPreset, AZ::Render::ModelPreset()); - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SaveModelPreset, preset, savePath); - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectModelPreset, preset); + MaterialViewportRequestBus::Broadcast( + [&savePath](MaterialViewportRequestBus::Events* viewportRequests) + { + AZ::Render::ModelPresetPtr preset = viewportRequests->AddModelPreset(AZ::Render::ModelPreset()); + viewportRequests->SaveModelPreset(preset, savePath); + viewportRequests->SelectModelPreset(preset); + }); } } void ViewportSettingsInspector::SelectModelPreset() { - ModelPresetBrowserDialog dialog(QApplication::activeWindow()); + AZ::Data::AssetId selectedAsset; + AtomToolsFramework::AssetGridDialog::SelectableAssetVector selectableAssets; + AZStd::unordered_map assetIdToPresetMap; + MaterialViewportRequestBus::Broadcast( + [&](MaterialViewportRequestBus::Events* viewportRequests) + { + const auto& selectedPreset = viewportRequests->GetModelPresetSelection(); + selectedAsset = selectedPreset->m_modelAsset.GetId(); + + const auto& presets = viewportRequests->GetModelPresets(); + selectableAssets.reserve(presets.size()); + for (const auto& preset : presets) + { + const auto& presetAssetId = preset->m_modelAsset.GetId(); + selectableAssets.push_back({ presetAssetId, preset->m_displayName.c_str() }); + assetIdToPresetMap[presetAssetId] = preset; + } + }); + + const int itemSize = aznumeric_cast( + AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/MaterialEditor/AssetGridDialog/ModelItemSize", 180)); + + AtomToolsFramework::AssetGridDialog dialog( + "Model Preset Browser", selectableAssets, selectedAsset, QSize(itemSize, itemSize), QApplication::activeWindow()); + + connect( + &dialog, &AtomToolsFramework::AssetGridDialog::AssetSelected, this, + [assetIdToPresetMap](const AZ::Data::AssetId& assetId) + { + const auto presetItr = assetIdToPresetMap.find(assetId); + if (presetItr != assetIdToPresetMap.end()) + { + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectModelPreset, presetItr->second); + } + }); dialog.setFixedSize(800, 400); dialog.show(); @@ -198,17 +236,55 @@ namespace MaterialEditor if (!savePath.empty()) { - AZ::Render::LightingPresetPtr preset; - MaterialViewportRequestBus::BroadcastResult( - preset, &MaterialViewportRequestBus::Events::AddLightingPreset, AZ::Render::LightingPreset()); - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SaveLightingPreset, preset, savePath); - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectLightingPreset, preset); + MaterialViewportRequestBus::Broadcast( + [&savePath](MaterialViewportRequestBus::Events* viewportRequests) + { + AZ::Render::LightingPresetPtr preset = viewportRequests->AddLightingPreset(AZ::Render::LightingPreset()); + viewportRequests->SaveLightingPreset(preset, savePath); + viewportRequests->SelectLightingPreset(preset); + }); } } void ViewportSettingsInspector::SelectLightingPreset() { - LightingPresetBrowserDialog dialog(QApplication::activeWindow()); + AZ::Data::AssetId selectedAsset; + AtomToolsFramework::AssetGridDialog::SelectableAssetVector selectableAssets; + AZStd::unordered_map assetIdToPresetMap; + MaterialViewportRequestBus::Broadcast( + [&](MaterialViewportRequestBus::Events* viewportRequests) + { + const auto& selectedPreset = viewportRequests->GetLightingPresetSelection(); + const auto& selectedPresetPath = viewportRequests->GetLightingPresetLastSavePath(selectedPreset); + selectedAsset = AZ::RPI::AssetUtils::MakeAssetId(selectedPresetPath, 0).GetValue(); + + const auto& presets = viewportRequests->GetLightingPresets(); + selectableAssets.reserve(presets.size()); + for (const auto& preset : presets) + { + const auto& path = viewportRequests->GetLightingPresetLastSavePath(preset); + const auto& presetAssetId = AZ::RPI::AssetUtils::MakeAssetId(path, 0).GetValue(); + selectableAssets.push_back({ presetAssetId, preset->m_displayName.c_str() }); + assetIdToPresetMap[presetAssetId] = preset; + } + }); + + const int itemSize = aznumeric_cast( + AtomToolsFramework::GetSettingOrDefault("/O3DE/Atom/MaterialEditor/AssetGridDialog/LightingItemSize", 180)); + + AtomToolsFramework::AssetGridDialog dialog( + "Lighting Preset Browser", selectableAssets, selectedAsset, QSize(itemSize, itemSize), QApplication::activeWindow()); + + connect( + &dialog, &AtomToolsFramework::AssetGridDialog::AssetSelected, this, + [assetIdToPresetMap](const AZ::Data::AssetId& assetId) + { + const auto presetItr = assetIdToPresetMap.find(assetId); + if (presetItr != assetIdToPresetMap.end()) + { + MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SelectLightingPreset, presetItr->second); + } + }); dialog.setFixedSize(800, 400); dialog.show(); @@ -249,20 +325,18 @@ namespace MaterialEditor void ViewportSettingsInspector::Reset() { m_modelPreset.reset(); - MaterialViewportRequestBus::BroadcastResult(m_modelPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection); - m_lightingPreset.reset(); - MaterialViewportRequestBus::BroadcastResult(m_lightingPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); - - MaterialViewportRequestBus::BroadcastResult(m_viewportSettings->m_enableGrid, &MaterialViewportRequestBus::Events::GetGridEnabled); - MaterialViewportRequestBus::BroadcastResult( - m_viewportSettings->m_enableShadowCatcher, &MaterialViewportRequestBus::Events::GetShadowCatcherEnabled); - MaterialViewportRequestBus::BroadcastResult( - m_viewportSettings->m_enableAlternateSkybox, &MaterialViewportRequestBus::Events::GetAlternateSkyboxEnabled); - MaterialViewportRequestBus::BroadcastResult( - m_viewportSettings->m_fieldOfView, &MaterialViewportRequestBus::Handler::GetFieldOfView); - MaterialViewportRequestBus::BroadcastResult( - m_viewportSettings->m_displayMapperOperationType, &MaterialViewportRequestBus::Handler::GetDisplayMapperOperationType); + MaterialViewportRequestBus::Broadcast( + [this](MaterialViewportRequestBus::Events* viewportRequests) + { + m_modelPreset = viewportRequests->GetModelPresetSelection(); + m_lightingPreset = viewportRequests->GetLightingPresetSelection(); + m_viewportSettings->m_enableGrid = viewportRequests->GetGridEnabled(); + m_viewportSettings->m_enableShadowCatcher = viewportRequests->GetShadowCatcherEnabled(); + m_viewportSettings->m_enableAlternateSkybox = viewportRequests->GetAlternateSkyboxEnabled(); + m_viewportSettings->m_fieldOfView = viewportRequests->GetFieldOfView(); + m_viewportSettings->m_displayMapperOperationType = viewportRequests->GetDisplayMapperOperationType(); + }); AtomToolsFramework::InspectorRequestBus::Handler::BusDisconnect(); AtomToolsFramework::InspectorWidget::Reset(); @@ -335,14 +409,16 @@ namespace MaterialEditor { MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnLightingPresetChanged, m_lightingPreset); MaterialViewportNotificationBus::Broadcast(&MaterialViewportNotificationBus::Events::OnModelPresetChanged, m_modelPreset); - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Events::SetGridEnabled, m_viewportSettings->m_enableGrid); + MaterialViewportRequestBus::Broadcast( - &MaterialViewportRequestBus::Events::SetShadowCatcherEnabled, m_viewportSettings->m_enableShadowCatcher); - MaterialViewportRequestBus::Broadcast( - &MaterialViewportRequestBus::Events::SetAlternateSkyboxEnabled, m_viewportSettings->m_enableAlternateSkybox); - MaterialViewportRequestBus::Broadcast(&MaterialViewportRequestBus::Handler::SetFieldOfView, m_viewportSettings->m_fieldOfView); - MaterialViewportRequestBus::Broadcast( - &MaterialViewportRequestBus::Handler::SetDisplayMapperOperationType, m_viewportSettings->m_displayMapperOperationType); + [this](MaterialViewportRequestBus::Events* viewportRequests) + { + viewportRequests->SetGridEnabled(m_viewportSettings->m_enableGrid); + viewportRequests->SetShadowCatcherEnabled(m_viewportSettings->m_enableShadowCatcher); + viewportRequests->SetAlternateSkyboxEnabled(m_viewportSettings->m_enableAlternateSkybox); + viewportRequests->SetFieldOfView(m_viewportSettings->m_fieldOfView); + viewportRequests->SetDisplayMapperOperationType(m_viewportSettings->m_displayMapperOperationType); + }); } AZStd::string ViewportSettingsInspector::GetDefaultUniqueSaveFilePath(const AZStd::string& baseName) const diff --git a/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake b/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake index 9d1e2b22f8..a655fd8286 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake +++ b/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake @@ -69,13 +69,6 @@ set(FILES Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp Source/Window/CreateMaterialDialog/CreateMaterialDialog.h Source/Window/CreateMaterialDialog/CreateMaterialDialog.ui - Source/Window/PresetBrowserDialogs/PresetBrowserDialog.cpp - Source/Window/PresetBrowserDialogs/PresetBrowserDialog.h - Source/Window/PresetBrowserDialogs/PresetBrowserDialog.ui - Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.cpp - Source/Window/PresetBrowserDialogs/LightingPresetBrowserDialog.h - Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.cpp - Source/Window/PresetBrowserDialogs/ModelPresetBrowserDialog.h Source/Window/PerformanceMonitor/PerformanceMonitorWidget.cpp Source/Window/PerformanceMonitor/PerformanceMonitorWidget.h Source/Window/PerformanceMonitor/PerformanceMonitorWidget.ui From d6cf8e24f31d98c23712ded6603427d867089f13 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 23 Jan 2022 12:29:33 -0600 Subject: [PATCH 095/136] =?UTF-8?q?Atom=20Tools:=20Replaced=20custom=20hel?= =?UTF-8?q?p=20dialog=20with=20generic=20message=20box=20The=20help=20dial?= =?UTF-8?q?og=20just=20displayed=20some=20HTML=20text.=20The=20message=20b?= =?UTF-8?q?ox=20class=20provided=20by=20Qt=20can=20display=20the=20same=20?= =?UTF-8?q?information=20and=20styling=20without=20additional=20code.=20We?= =?UTF-8?q?=20don=E2=80=99t=20want=20to=20carry=20around=20the=20extra=20c?= =?UTF-8?q?lass=20to=20new=20applications=20based=20off=20of=20this=20one?= =?UTF-8?q?=20or=20port=20to=20ATF.=20A=20simple=20about=20box=20was=20als?= =?UTF-8?q?o=20added=20and=20can=20be=20fleshed=20out=20in=20the=20future.?= =?UTF-8?q?=20Both=20dialogs=20will=20eventually=20need=20to=20be=20update?= =?UTF-8?q?d=20with=20additional=20information.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guthrie Adams --- .../Source/Window/HelpDialog/HelpDialog.cpp | 23 ------ .../Source/Window/HelpDialog/HelpDialog.h | 38 ---------- .../Source/Window/HelpDialog/HelpDialog.ui | 71 ------------------- .../Source/Window/MaterialEditorWindow.cpp | 20 +++++- .../Code/Source/Window/MaterialEditorWindow.h | 1 + .../Code/materialeditor_files.cmake | 3 - 6 files changed, 18 insertions(+), 138 deletions(-) delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.cpp delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.h delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.ui diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.cpp deleted file mode 100644 index 3e8cf19539..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include - -namespace MaterialEditor -{ - HelpDialog::HelpDialog(QWidget* parent) - : QDialog(parent) - , m_ui(new Ui::HelpDialogWidget) - { - m_ui->setupUi(this); - } - - HelpDialog::~HelpDialog() = default; -} // namespace MaterialEditor - -#include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.h deleted file mode 100644 index ec5b756df4..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include - -AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT -#include -#include -AZ_POP_DISABLE_WARNING -#endif - -namespace Ui -{ - class HelpDialogWidget; -} - -namespace MaterialEditor -{ - //! Displays help for Material Editor - class HelpDialog - : public QDialog - { - Q_OBJECT - public: - HelpDialog(QWidget* parent = nullptr); - ~HelpDialog(); - - QScopedPointer m_ui; - }; -} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.ui b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.ui deleted file mode 100644 index 2a2cb06bb2..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/HelpDialog/HelpDialog.ui +++ /dev/null @@ -1,71 +0,0 @@ - - - HelpDialogWidget - - - - 0 - 0 - 270 - 210 - - - - Material Editor Help - - - - - - <html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Material Editor Controls</span></p><p><span style=" font-weight:600;">LMB</span> - pan camera</p><p><span style=" font-weight:600;">RMB</span> or <span style=" font-weight:600;">Alt+LMB</span> - orbit camera around target</p><p><span style=" font-weight:600;">MMB</span> or <span style=" font-weight:600;">Alt+MMB</span> - move camera on its xy plane</p><p><span style=" font-weight:600;">Alt+RMB</span> or <span style=" font-weight:600;">LMB+RMB</span> - dolly camera on its z axis</p><p><span style=" font-weight:600;">Ctrl+LMB</span> - rotate model</p><p><span style=" font-weight:600;">Shift+LMB</span> - rotate environment</p></body></html> - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Close - - - - - - - - - buttonBox - accepted() - HelpDialogWidget - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - HelpDialogWidget - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp index e1f8e713d4..d538f62e15 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -30,6 +29,7 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnin #include #include #include +#include #include #include AZ_POP_DISABLE_WARNING @@ -178,8 +178,22 @@ namespace MaterialEditor void MaterialEditorWindow::OpenHelp() { - HelpDialog dialog(this); - dialog.exec(); + QMessageBox::information( + this, windowTitle(), + R"( +

Material Editor Controls

+

LMB - pan camera

+

RMB or Alt+LMB - orbit camera around target

+

MMB or Alt+MMB - move camera on its xy plane

+

Alt+RMB or LMB+RMB - dolly camera on its z axis

+

Ctrl+LMB - rotate model

+

Shift+LMB - rotate environment

+ )"); + } + + void MaterialEditorWindow::OpenAbout() + { + QMessageBox::about(this, windowTitle(), QApplication::applicationName()); } void MaterialEditorWindow::closeEvent(QCloseEvent* closeEvent) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h index 8ad294c529..8317382d6d 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/MaterialEditorWindow.h @@ -44,6 +44,7 @@ namespace MaterialEditor bool GetOpenDocumentParams(AZStd::string& openPath) override; void OpenSettings() override; void OpenHelp() override; + void OpenAbout() override; void closeEvent(QCloseEvent* closeEvent) override; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake b/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake index 9d1e2b22f8..262f27d854 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake +++ b/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake @@ -89,7 +89,4 @@ set(FILES Source/Window/MaterialInspector/MaterialInspector.cpp Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.h Source/Window/ViewportSettingsInspector/ViewportSettingsInspector.cpp - Source/Window/HelpDialog/HelpDialog.h - Source/Window/HelpDialog/HelpDialog.cpp - Source/Window/HelpDialog/HelpDialog.ui ) From 0a5f472f4331d5a310e55ac8b9d5dabdc491d079 Mon Sep 17 00:00:00 2001 From: Daniel Edwards Date: Sat, 22 Jan 2022 14:36:20 +0100 Subject: [PATCH 096/136] Clang 13: Fix build errors ... ... due to local variables only being written to (but never read). Signed-off-by: Daniel Edwards --- Code/Editor/EditorPreferencesPageAWS.cpp | 2 +- Code/Editor/Settings.cpp | 2 +- Code/Editor/ViewPane.cpp | 2 +- Code/Framework/AzCore/AzCore/Math/Matrix3x4.cpp | 6 +++--- Code/Framework/AzCore/AzCore/Math/Uuid.cpp | 2 +- Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp | 2 +- Code/Framework/AzCore/Tests/Name/NameTests.cpp | 2 +- .../AzFramework/Asset/Benchmark/BenchmarkCommands.cpp | 2 +- Code/Framework/AzFramework/Tests/CameraState.cpp | 2 +- .../AzQtComponents/Components/StylesheetPreprocessor.cpp | 2 +- .../AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp | 2 +- .../AzToolsFramework/Prefab/PrefabSystemComponent.cpp | 4 ++-- .../AzToolsFramework/Slice/SliceTransaction.cpp | 2 +- .../UI/PropertyEditor/PropertyEnumComboBoxCtrl.cpp | 2 +- Code/Framework/AzToolsFramework/Tests/Slices.cpp | 2 +- Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp | 4 ++-- .../native/utilities/ApplicationManagerBase.cpp | 2 +- .../AssetProcessor/native/utilities/BuilderManager.inl | 2 +- Code/Tools/ProjectManager/Source/Settings.cpp | 2 +- Code/Tools/SceneAPI/SceneBuilder/Tests/TestsMain.cpp | 2 +- .../Source/Editor/Attribution/AWSCoreAttributionManager.cpp | 2 +- .../AssetValidation/Code/Source/AssetSystemTestCommands.cpp | 6 +++--- .../DiffuseProbeGridFeatureProcessor.cpp | 2 +- .../Code/Source/RayTracing/RayTracingFeatureProcessor.cpp | 2 +- .../ReflectionProbe/ReflectionProbeFeatureProcessor.cpp | 2 +- Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp | 2 +- Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingBlas.cpp | 2 +- .../RHI/Vulkan/Code/Source/RHI/RayTracingPipelineState.cpp | 2 +- .../RHI/Vulkan/Code/Source/RHI/RayTracingShaderTable.cpp | 2 +- Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.cpp | 4 ++-- Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp | 2 +- Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp | 2 +- Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp | 2 +- Gems/EMotionFX/Code/EMotionFX/Source/Recorder.cpp | 2 +- Gems/GraphModel/Code/Source/Model/Node.cpp | 2 +- Gems/GraphModel/Code/Source/Model/Slot.cpp | 2 +- .../LyShine/Code/Editor/PropertyHandlerEntityIdComboBox.cpp | 2 +- .../EntityReplication/EntityReplicationManager.cpp | 2 +- .../Components/ClothComponentMesh/ActorClothColliders.cpp | 4 ++-- .../Source/PhysXCharacters/Components/RagdollComponent.cpp | 2 +- .../NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp | 2 +- .../Code/Source/TerrainRenderer/TerrainMeshManager.cpp | 2 +- 42 files changed, 50 insertions(+), 50 deletions(-) diff --git a/Code/Editor/EditorPreferencesPageAWS.cpp b/Code/Editor/EditorPreferencesPageAWS.cpp index 9279dce7bc..968969245d 100644 --- a/Code/Editor/EditorPreferencesPageAWS.cpp +++ b/Code/Editor/EditorPreferencesPageAWS.cpp @@ -101,7 +101,7 @@ void CEditorPreferencesPage_AWS::SaveSettingsRegistryFile() return; } - bool saved{}; + [[maybe_unused]] bool saved{}; constexpr auto configurationMode = AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY; if (AZ::IO::SystemFile outputFile; outputFile.Open(resolvedPath.data(), configurationMode)) diff --git a/Code/Editor/Settings.cpp b/Code/Editor/Settings.cpp index 8561e6dba3..9514957795 100644 --- a/Code/Editor/Settings.cpp +++ b/Code/Editor/Settings.cpp @@ -1128,7 +1128,7 @@ void SEditorSettings::SaveSettingsRegistryFile() return; } - bool saved{}; + [[maybe_unused]] bool saved{}; constexpr auto configurationMode = AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY; diff --git a/Code/Editor/ViewPane.cpp b/Code/Editor/ViewPane.cpp index e3494a4049..90b44d9c9d 100644 --- a/Code/Editor/ViewPane.cpp +++ b/Code/Editor/ViewPane.cpp @@ -745,7 +745,7 @@ namespace void PySetActiveViewport(unsigned int viewportIndex) { - bool success = false; + [[maybe_unused]] bool success = false; CLayoutWnd* layout = GetIEditor()->GetViewManager()->GetLayout(); if (layout) { diff --git a/Code/Framework/AzCore/AzCore/Math/Matrix3x4.cpp b/Code/Framework/AzCore/AzCore/Math/Matrix3x4.cpp index 78da9e76d2..23d0eea618 100644 --- a/Code/Framework/AzCore/AzCore/Math/Matrix3x4.cpp +++ b/Code/Framework/AzCore/AzCore/Math/Matrix3x4.cpp @@ -25,7 +25,7 @@ namespace AZ void Matrix3x4SetRowGeneric(Matrix3x4* thisPtr, ScriptDataContext& dc) { - bool rowIsSet = false; + [[maybe_unused]] bool rowIsSet = false; if (dc.GetNumArguments() >= 5) { if (dc.IsNumber(0)) @@ -88,7 +88,7 @@ namespace AZ void Matrix3x4SetColumnGeneric(Matrix3x4* thisPtr, ScriptDataContext& dc) { - bool columnIsSet = false; + [[maybe_unused]] bool columnIsSet = false; if (dc.GetNumArguments() >= 4) { if (dc.IsNumber(0)) @@ -133,7 +133,7 @@ namespace AZ void Matrix3x4SetTranslationGeneric(Matrix3x4* thisPtr, ScriptDataContext& dc) { - bool translationIsSet = false; + [[maybe_unused]] bool translationIsSet = false; if (dc.GetNumArguments() == 3 && dc.IsNumber(0) && diff --git a/Code/Framework/AzCore/AzCore/Math/Uuid.cpp b/Code/Framework/AzCore/AzCore/Math/Uuid.cpp index 410d235a37..b27f1a0943 100644 --- a/Code/Framework/AzCore/AzCore/Math/Uuid.cpp +++ b/Code/Framework/AzCore/AzCore/Math/Uuid.cpp @@ -77,7 +77,7 @@ namespace AZ // check open brace char c = *current++; - bool has_open_brace = false; + [[maybe_unused]] bool has_open_brace = false; if (c == '{') { c = *current++; diff --git a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp index 1b39eb81bd..2bb4faf1d5 100644 --- a/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp +++ b/Code/Framework/AzCore/AzCore/Name/NameDictionary.cpp @@ -85,7 +85,7 @@ namespace AZ NameDictionary::~NameDictionary() { - bool leaksDetected = false; + [[maybe_unused]] bool leaksDetected = false; for (const auto& keyValue : m_dictionary) { diff --git a/Code/Framework/AzCore/Tests/Name/NameTests.cpp b/Code/Framework/AzCore/Tests/Name/NameTests.cpp index eb0a048e2f..9e94c4bfdf 100644 --- a/Code/Framework/AzCore/Tests/Name/NameTests.cpp +++ b/Code/Framework/AzCore/Tests/Name/NameTests.cpp @@ -642,7 +642,7 @@ namespace UnitTest char buffer[RandomStringBufferSize]; AZStd::sys_time_t newNameTime; - AZStd::sys_time_t existingNameTime; + [[maybe_unused]] AZStd::sys_time_t existingNameTime; AZStd::sys_time_t stringTime; { diff --git a/Code/Framework/AzFramework/AzFramework/Asset/Benchmark/BenchmarkCommands.cpp b/Code/Framework/AzFramework/AzFramework/Asset/Benchmark/BenchmarkCommands.cpp index 30c1aa39c0..2c2571ec76 100644 --- a/Code/Framework/AzFramework/AzFramework/Asset/Benchmark/BenchmarkCommands.cpp +++ b/Code/Framework/AzFramework/AzFramework/Asset/Benchmark/BenchmarkCommands.cpp @@ -195,7 +195,7 @@ namespace AzFramework::AssetBenchmark // Console command: Add the given list of assets to the list of assets to load with BenchmarkLoadAssetList void BenchmarkAddAssetsToList(const AZ::ConsoleCommandContainer& parameters) { - bool allAssetsAdded = true; + [[maybe_unused]] bool allAssetsAdded = true; for (auto& assetName : parameters) { diff --git a/Code/Framework/AzFramework/Tests/CameraState.cpp b/Code/Framework/AzFramework/Tests/CameraState.cpp index 1f35d5a06c..974b5dd742 100644 --- a/Code/Framework/AzFramework/Tests/CameraState.cpp +++ b/Code/Framework/AzFramework/Tests/CameraState.cpp @@ -81,7 +81,7 @@ namespace UnitTest TEST_P(Rotation, Permutation) { - int expectedErrors = -1; + [[maybe_unused]] int expectedErrors = -1; AZ_TEST_START_TRACE_SUPPRESSION; // Given an orientation derived from the look at points diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/StylesheetPreprocessor.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/StylesheetPreprocessor.cpp index c334bbb59a..2602ecf535 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/StylesheetPreprocessor.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/StylesheetPreprocessor.cpp @@ -134,7 +134,7 @@ namespace AzQtComponents QColor color; QString colorName(m_namedVariables.value(name)); - bool colorSet = false; + [[maybe_unused]] bool colorSet = false; if (QColor::isValidColor(colorName)) { color.setNamedColor(colorName); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp index 5711ca2608..4aab7288fa 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp @@ -177,7 +177,7 @@ namespace AzToolsFramework auto data = index.data(AssetBrowserModel::Roles::EntryRole); if (data.canConvert()) { - bool isEnabled = (option.state & QStyle::State_Enabled) != 0; + [[maybe_unused]] bool isEnabled = (option.state & QStyle::State_Enabled) != 0; QStyle* style = option.widget ? option.widget->style() : QApplication::style(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp index 98e0144f22..9648a9af09 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp @@ -506,7 +506,7 @@ namespace AzToolsFramework //Remove all Links owned by the Template from TemplateToLinkIdsMap. Template& templateToDelete = findTemplateResult->get(); const Template::Links& linkIdsToDelete = templateToDelete.GetLinks(); - bool result; + [[maybe_unused]] bool result; for (auto linkId : linkIdsToDelete) { result = RemoveLinkIdFromTemplateToLinkIdsMap(linkId); @@ -774,7 +774,7 @@ namespace AzToolsFramework } Link& link = findLinkResult->get(); - bool result; + [[maybe_unused]] bool result; result = RemoveLinkIdFromTemplateToLinkIdsMap(linkId, link); AZ_Assert(result, "Prefab - PrefabSystemComponent::RemoveLink - " diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceTransaction.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceTransaction.cpp index 9d2c58a717..91517bd784 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceTransaction.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Slice/SliceTransaction.cpp @@ -926,7 +926,7 @@ namespace AzToolsFramework const bool entityIsFromIgnoredSliceInstance = ignoreSliceInstance && ignoreSliceInstance->IsValid() && ignoreSliceInstance->GetReference()->GetSliceAsset().GetId() == instanceAddr.GetReference()->GetSliceAsset().GetId(); if (!entityIsFromIgnoredSliceInstance) { - bool foundTargetAncestor = false; + [[maybe_unused]] bool foundTargetAncestor = false; const AZ::SliceComponent::EntityList& entitiesInInstance = instanceAddr.GetInstance()->GetInstantiated()->m_entities; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEnumComboBoxCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEnumComboBoxCtrl.cpp index f49b555dfe..f37fd860ea 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEnumComboBoxCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyEnumComboBoxCtrl.cpp @@ -45,7 +45,7 @@ namespace AzToolsFramework void PropertyEnumComboBoxCtrl::setValue(AZ::s64 value) { m_pComboBox->blockSignals(true); - bool indexWasFound = false; + [[maybe_unused]] bool indexWasFound = false; for (size_t enumValIndex = 0; enumValIndex < m_enumValues.size(); enumValIndex++) { if (m_enumValues[enumValIndex].first == value) diff --git a/Code/Framework/AzToolsFramework/Tests/Slices.cpp b/Code/Framework/AzToolsFramework/Tests/Slices.cpp index 9b546357cd..bf59e1f8bd 100644 --- a/Code/Framework/AzToolsFramework/Tests/Slices.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Slices.cpp @@ -430,7 +430,7 @@ namespace UnitTest size_t nextIndex = 1; size_t slices = 0; size_t liveAllocs = 0; - size_t totalAllocs = 0; + [[maybe_unused]] size_t totalAllocs = 0; auto cb = [&liveAllocs](void*, const AZ::Debug::AllocationInfo&, unsigned char) { diff --git a/Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp b/Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp index 2724bee1a7..9d88f26278 100644 --- a/Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp +++ b/Code/Framework/GridMate/GridMate/Carrier/Carrier.cpp @@ -1952,8 +1952,8 @@ CarrierThread::ProcessConnections() bool isHandshakeTimeOut = false; bool isConnectionTimeout = false; - bool isBadTrafficConditions = false; - bool isBadPackets = false; + [[maybe_unused]] bool isBadTrafficConditions = false; + [[maybe_unused]] bool isBadPackets = false; if (connection->m_isBadPackets) { isBadPackets = true; diff --git a/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp b/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp index 36450c4e65..634fdbd3bb 100644 --- a/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/ApplicationManagerBase.cpp @@ -544,7 +544,7 @@ void ApplicationManagerBase::InitConnectionManager() EBUS_EVENT(AssetProcessor::ConnectionBus, SendPerPlatform, 0, message, QString::fromUtf8(message.m_platform.c_str())); }; - bool result = QObject::connect(GetAssetCatalog(), &AssetProcessor::AssetCatalog::SendAssetMessage, connectionAndChangeMessagesThreadContext, forwardMessageFunction, Qt::QueuedConnection); + [[maybe_unused]] bool result = QObject::connect(GetAssetCatalog(), &AssetProcessor::AssetCatalog::SendAssetMessage, connectionAndChangeMessagesThreadContext, forwardMessageFunction, Qt::QueuedConnection); AZ_Assert(result, "Failed to connect to AssetCatalog signal"); //Application manager related stuff diff --git a/Code/Tools/AssetProcessor/native/utilities/BuilderManager.inl b/Code/Tools/AssetProcessor/native/utilities/BuilderManager.inl index 039680dfae..4d1983691a 100644 --- a/Code/Tools/AssetProcessor/native/utilities/BuilderManager.inl +++ b/Code/Tools/AssetProcessor/native/utilities/BuilderManager.inl @@ -19,7 +19,7 @@ namespace AssetProcessor TNetResponse netResponse; netRequest.m_request = request; - AZ::u32 type; + [[maybe_unused]] AZ::u32 type; QByteArray data; AZStd::binary_semaphore wait; diff --git a/Code/Tools/ProjectManager/Source/Settings.cpp b/Code/Tools/ProjectManager/Source/Settings.cpp index 0a8b600dd9..78100848b5 100644 --- a/Code/Tools/ProjectManager/Source/Settings.cpp +++ b/Code/Tools/ProjectManager/Source/Settings.cpp @@ -41,7 +41,7 @@ namespace O3DE::ProjectManager o3deUserPath /= AZ::SettingsRegistryInterface::RegistryFolder; o3deUserPath /= "ProjectManager.setreg"; - bool saved = false; + [[maybe_unused]] bool saved = false; constexpr auto configurationMode = AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY; diff --git a/Code/Tools/SceneAPI/SceneBuilder/Tests/TestsMain.cpp b/Code/Tools/SceneAPI/SceneBuilder/Tests/TestsMain.cpp index 5c0d2503c0..2b7497951f 100644 --- a/Code/Tools/SceneAPI/SceneBuilder/Tests/TestsMain.cpp +++ b/Code/Tools/SceneAPI/SceneBuilder/Tests/TestsMain.cpp @@ -25,7 +25,7 @@ protected: sceneCoreModule = AZ::DynamicModuleHandle::Create("SceneCore"); AZ_Assert(sceneCoreModule, "SceneBuilder unit tests failed to create SceneCore module."); - bool loaded = sceneCoreModule->Load(false); + [[maybe_unused]] bool loaded = sceneCoreModule->Load(false); AZ_Assert(loaded, "SceneBuilder unit tests failed to load SceneCore module."); auto init = sceneCoreModule->GetFunction(AZ::InitializeDynamicModuleFunctionName); AZ_Assert(init, "SceneBuilder unit tests failed to find the initialization function the SceneCore module."); diff --git a/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp index 3b9352d250..c52d3be088 100644 --- a/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp +++ b/Gems/AWSCore/Code/Source/Editor/Attribution/AWSCoreAttributionManager.cpp @@ -223,7 +223,7 @@ namespace AWSCore return; } - bool saved {}; + [[maybe_unused]] bool saved {}; constexpr auto configurationMode = AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY; if (AZ::IO::SystemFile outputFile; outputFile.Open(resolvedPathAWSPreference.c_str(), configurationMode)) diff --git a/Gems/AssetValidation/Code/Source/AssetSystemTestCommands.cpp b/Gems/AssetValidation/Code/Source/AssetSystemTestCommands.cpp index 18888c7166..2007ac01a9 100644 --- a/Gems/AssetValidation/Code/Source/AssetSystemTestCommands.cpp +++ b/Gems/AssetValidation/Code/Source/AssetSystemTestCommands.cpp @@ -120,9 +120,9 @@ namespace AssetValidation AZ::SimpleLcgRandom randomizer(seedValue); int lastTick = 0; AZStd::vector> heldAssets; - AZStd::size_t heldCount{ 0 }; - AZ::u64 changeCount{ 0 }; - AZ::u64 blockCount{ 0 }; + [[maybe_unused]] AZStd::size_t heldCount{ 0 }; + [[maybe_unused]] AZ::u64 changeCount{ 0 }; + [[maybe_unused]] AZ::u64 blockCount{ 0 }; AZ_TracePrintf("TestChangeAssets", "Beginning run with %zu assets\n", assetList.size()); while (!forceStop && runMs < runTime) { diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp index ea02a8e0a2..d690c57dea 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp @@ -537,7 +537,7 @@ namespace AZ request.m_buffer = m_boxIndexBuffer.get(); request.m_descriptor = AZ::RHI::BufferDescriptor{ AZ::RHI::BufferBindFlags::InputAssembly, m_boxIndices.size() * sizeof(uint16_t) }; request.m_initialData = m_boxIndices.data(); - AZ::RHI::ResultCode result = m_bufferPool->InitBuffer(request); + [[maybe_unused]] AZ::RHI::ResultCode result = m_bufferPool->InitBuffer(request); AZ_Error("DiffuseProbeGridFeatureProcessor", result == RHI::ResultCode::Success, "Failed to initialize box index buffer - error [%d]", result); // create index buffer view diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp index 0a9782980f..f5c1be284e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp @@ -123,7 +123,7 @@ namespace AZ // create the BLAS buffers for each sub-mesh, or re-use existing BLAS objects if they were already created. // Note: all sub-meshes must either create new BLAS objects or re-use existing ones, otherwise it's an error (it's the same model in both cases) // Note: the buffer is just reserved here, the BLAS is built in the RayTracingAccelerationStructurePass - bool blasInstanceFound = false; + [[maybe_unused]] bool blasInstanceFound = false; for (uint32_t subMeshIndex = 0; subMeshIndex < mesh.m_subMeshes.size(); ++subMeshIndex) { SubMesh& subMesh = mesh.m_subMeshes[subMeshIndex]; diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp index 0f9356428a..3ff574d977 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp @@ -397,7 +397,7 @@ namespace AZ request.m_buffer = m_boxIndexBuffer.get(); request.m_descriptor = AZ::RHI::BufferDescriptor{ AZ::RHI::BufferBindFlags::InputAssembly, m_boxIndices.size() * sizeof(uint16_t) }; request.m_initialData = m_boxIndices.data(); - AZ::RHI::ResultCode result = m_bufferPool->InitBuffer(request); + [[maybe_unused]] AZ::RHI::ResultCode result = m_bufferPool->InitBuffer(request); AZ_Error("ReflectionProbeFeatureProcessor", result == RHI::ResultCode::Success, "Failed to initialize box index buffer - error [%d]", result); // create index buffer view diff --git a/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp b/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp index 79c05c37da..3279372052 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/PipelineStateCache.cpp @@ -364,7 +364,7 @@ namespace AZ AZ_Assert(success, "PipelineStateEntry already exists in the pending cache."); } - ResultCode resultCode = ResultCode::InvalidArgument; + [[maybe_unused]] ResultCode resultCode = ResultCode::InvalidArgument; // Increment the pending compile count on the global entry, which tracks how many pipeline states // are currently being compiled across all threads. diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingBlas.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingBlas.cpp index a322380fb1..e4a90d0739 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingBlas.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingBlas.cpp @@ -120,7 +120,7 @@ namespace AZ AZ::RHI::BufferInitRequest scratchBufferRequest; scratchBufferRequest.m_buffer = buffers.m_scratchBuffer.get(); scratchBufferRequest.m_descriptor = scratchBufferDescriptor; - RHI::ResultCode resultCode = bufferPools.GetScratchBufferPool()->InitBuffer(scratchBufferRequest); + [[maybe_unused]] RHI::ResultCode resultCode = bufferPools.GetScratchBufferPool()->InitBuffer(scratchBufferRequest); AZ_Assert(resultCode == RHI::ResultCode::Success, "failed to create BLAS scratch buffer"); BufferMemoryView* scratchMemoryView = static_cast(buffers.m_scratchBuffer.get())->GetBufferMemoryView(); diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingPipelineState.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingPipelineState.cpp index 65281d923f..bddfb0df5e 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingPipelineState.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingPipelineState.cpp @@ -170,7 +170,7 @@ namespace AZ createInfo.basePipelineHandle = nullptr; createInfo.basePipelineIndex = 0; - VkResult result = vkCreateRayTracingPipelinesKHR(device.GetNativeDevice(), nullptr, nullptr, 1, &createInfo, nullptr, &m_pipeline); + [[maybe_unused]] VkResult result = vkCreateRayTracingPipelinesKHR(device.GetNativeDevice(), nullptr, nullptr, 1, &createInfo, nullptr, &m_pipeline); AZ_Assert(result == VK_SUCCESS, "vkCreateRayTracingPipelinesKHR failed"); // retrieve the shader handles diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingShaderTable.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingShaderTable.cpp index d5ef121875..5e820a18ba 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingShaderTable.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingShaderTable.cpp @@ -43,7 +43,7 @@ namespace AZ AZ::RHI::BufferInitRequest shaderTableBufferRequest; shaderTableBufferRequest.m_buffer = shaderTableBuffer.get(); shaderTableBufferRequest.m_descriptor = shaderTableBufferDescriptor; - RHI::ResultCode resultCode = bufferPools.GetShaderTableBufferPool()->InitBuffer(shaderTableBufferRequest); + [[maybe_unused]] RHI::ResultCode resultCode = bufferPools.GetShaderTableBufferPool()->InitBuffer(shaderTableBufferRequest); AZ_Assert(resultCode == RHI::ResultCode::Success, "failed to create shader table buffer"); BufferMemoryView* shaderTableMemoryView = static_cast(shaderTableBuffer.get())->GetBufferMemoryView(); diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.cpp index 9ea9ceccce..08b933c96b 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/RayTracingTlas.cpp @@ -66,7 +66,7 @@ namespace AZ AZ::RHI::BufferInitRequest tlasInstancesBufferRequest; tlasInstancesBufferRequest.m_buffer = buffers.m_tlasInstancesBuffer.get(); tlasInstancesBufferRequest.m_descriptor = tlasInstancesBufferDescriptor; - RHI::ResultCode resultCode = bufferPools.GetTlasInstancesBufferPool()->InitBuffer(tlasInstancesBufferRequest); + [[maybe_unused]] RHI::ResultCode resultCode = bufferPools.GetTlasInstancesBufferPool()->InitBuffer(tlasInstancesBufferRequest); AZ_Assert(resultCode == RHI::ResultCode::Success, "failed to create TLAS instances buffer"); BufferMemoryView* tlasInstancesMemoryView = static_cast(buffers.m_tlasInstancesBuffer.get())->GetBufferMemoryView(); @@ -160,7 +160,7 @@ namespace AZ AZ::RHI::BufferInitRequest scratchBufferRequest; scratchBufferRequest.m_buffer = buffers.m_scratchBuffer.get(); scratchBufferRequest.m_descriptor = scratchBufferDescriptor; - RHI::ResultCode resultCode = bufferPools.GetScratchBufferPool()->InitBuffer(scratchBufferRequest); + [[maybe_unused]] RHI::ResultCode resultCode = bufferPools.GetScratchBufferPool()->InitBuffer(scratchBufferRequest); AZ_Assert(resultCode == RHI::ResultCode::Success, "failed to create TLAS scratch buffer"); BufferMemoryView* scratchMemoryView = static_cast(buffers.m_scratchBuffer.get())->GetBufferMemoryView(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index bd196a2e2b..41cfb5ff12 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -312,7 +312,7 @@ namespace AZ const View::UsageFlags viewFlags = worklistData->m_view->GetUsageFlags(); const RHI::DrawListMask drawListMask = worklistData->m_view->GetDrawListMask(); - uint32_t numDrawPackets = 0; + [[maybe_unused]] uint32_t numDrawPackets = 0; uint32_t numVisibleCullables = 0; AZ_Assert(worklist.size() > 0, "Received empty worklist in ProcessWorklist"); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp index 1b5110e327..83ac77a390 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Scene.cpp @@ -322,7 +322,7 @@ namespace AZ void Scene::RemoveRenderPipeline(const RenderPipelineId& pipelineId) { - bool removed = false; + [[maybe_unused]] bool removed = false; for (auto it = m_pipelines.begin(); it != m_pipelines.end(); ++it) { if (pipelineId == (*it)->GetId()) diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp index 9130636e2a..72d574508f 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp @@ -123,7 +123,7 @@ namespace EMotionFX TargetType* targetBuffer = static_cast(targetVertexAttributeLayer->GetData()); // Fill the vertex attribute layer by iterating through the Atom meshes and copying over the vertex data for each. - size_t addedElements = 0; + [[maybe_unused]] size_t addedElements = 0; for (const AZ::RPI::ModelLodAsset::Mesh& atomMesh : sourceModelLod->GetMeshes()) { const uint32_t atomMeshVertexCount = atomMesh.GetVertexCount(); diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/Recorder.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/Recorder.cpp index 54fb130ad3..116026e8c1 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/Recorder.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/Recorder.cpp @@ -863,7 +863,7 @@ namespace EMotionFX } // process all objects for this frame - size_t totalBytesRead = 0; + [[maybe_unused]] size_t totalBytesRead = 0; const size_t numObjects = frameObjects.size(); for (size_t a = 0; a < numObjects; ++a) { diff --git a/Gems/GraphModel/Code/Source/Model/Node.cpp b/Gems/GraphModel/Code/Source/Model/Node.cpp index f51bd1f617..e55b7c05a4 100644 --- a/Gems/GraphModel/Code/Source/Model/Node.cpp +++ b/Gems/GraphModel/Code/Source/Model/Node.cpp @@ -68,7 +68,7 @@ namespace GraphModel CreateSlotData(m_inputEventSlots, m_inputEventSlotDefinitions); CreateSlotData(m_outputEventSlots, m_outputEventSlotDefinitions); - int numExtendableSlots = 0; + [[maybe_unused]] int numExtendableSlots = 0; for (auto it = m_extendableSlots.begin(); it != m_extendableSlots.end(); it++) { numExtendableSlots += aznumeric_cast(it->second.size()); diff --git a/Gems/GraphModel/Code/Source/Model/Slot.cpp b/Gems/GraphModel/Code/Source/Model/Slot.cpp index 08b52760cb..108067cc93 100644 --- a/Gems/GraphModel/Code/Source/Model/Slot.cpp +++ b/Gems/GraphModel/Code/Source/Model/Slot.cpp @@ -491,7 +491,7 @@ namespace GraphModel // multiple supported types, Slot::GetDataType() will call GetParentNode() // to try and resolve its type, which will be a nullptr at this point // because the parent won't be valid yet - bool valueTypeSupported = false; + [[maybe_unused]] bool valueTypeSupported = false; DataTypePtr valueDataType = GetGraphContext()->GetDataTypeForValue(m_value); for (DataTypePtr dataType : GetSupportedDataTypes()) { diff --git a/Gems/LyShine/Code/Editor/PropertyHandlerEntityIdComboBox.cpp b/Gems/LyShine/Code/Editor/PropertyHandlerEntityIdComboBox.cpp index 9bb98dd575..809803c3a7 100644 --- a/Gems/LyShine/Code/Editor/PropertyHandlerEntityIdComboBox.cpp +++ b/Gems/LyShine/Code/Editor/PropertyHandlerEntityIdComboBox.cpp @@ -156,7 +156,7 @@ PropertyEntityIdComboBoxCtrl::PropertyEntityIdComboBoxCtrl(QWidget* pParent) void PropertyEntityIdComboBoxCtrl::setValue(AZ::EntityId value) { m_pComboBox->blockSignals(true); - bool indexWasFound = false; + [[maybe_unused]] bool indexWasFound = false; for (size_t enumValIndex = 0; enumValIndex < m_enumValues.size(); enumValIndex++) { if (m_enumValues[enumValIndex].first == value) diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp index e095af4ae7..893799a296 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp @@ -1126,7 +1126,7 @@ namespace Multiplayer netBindComponent->NotifyServerMigration(GetRemoteHostId()); } - bool didSucceed = true; + [[maybe_unused]] bool didSucceed = true; EntityMigrationMessage message; message.m_netEntityId = replicator->GetEntityHandle().GetNetEntityId(); message.m_prefabEntityId = netBindComponent->GetPrefabEntityId(); diff --git a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothColliders.cpp b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothColliders.cpp index 1e57999b6e..cde8740694 100644 --- a/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothColliders.cpp +++ b/Gems/NvCloth/Code/Source/Components/ClothComponentMesh/ActorClothColliders.cpp @@ -72,8 +72,8 @@ namespace NvCloth // Maximum number of spheres and capsules is imposed by NvCloth library size_t sphereCount = 0; size_t capsuleCount = 0; - bool maxSphereCountReachedWarned = false; - bool maxCapsuleCountReachedWarned = false; + [[maybe_unused]] bool maxSphereCountReachedWarned = false; + [[maybe_unused]] bool maxCapsuleCountReachedWarned = false; AZStd::vector sphereColliders; AZStd::vector capsuleColliders; diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp index 7615a175d1..2c00fd188d 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/Components/RagdollComponent.cpp @@ -422,7 +422,7 @@ namespace PhysX return d1.m_depth < d2.m_depth; }); - bool massesClamped = false; + [[maybe_unused]] bool massesClamped = false; for (const auto& nodeDepth : nodeDepths) { const size_t nodeIndex = nodeDepth.m_index; diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp index da0e9c6045..86fdc0342b 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/NodePalette/ScriptEventsNodePaletteTreeItemTypes.cpp @@ -145,7 +145,7 @@ namespace ScriptCanvasEditor ScriptEvents::ScriptEventsAsset* data = asset.GetAs(); if (data) { - const ScriptEvents::ScriptEvent* previousDefinition = nullptr; + [[maybe_unused]] const ScriptEvents::ScriptEvent* previousDefinition = nullptr; ScriptEvents::ScriptEventsAsset* previousData = m_asset.GetAs(); if (previousData) { diff --git a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMeshManager.cpp b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMeshManager.cpp index d689d2635c..4a0d260a74 100644 --- a/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMeshManager.cpp +++ b/Gems/Terrain/Code/Source/TerrainRenderer/TerrainMeshManager.cpp @@ -291,7 +291,7 @@ namespace Terrain modelAssetCreator.Begin(AZ::Uuid::CreateRandom()); uint16_t gridSize = GridSize; - float gridSpacing = GridSpacing; + [[maybe_unused]] float gridSpacing = GridSpacing; for (uint32_t i = 0; i < AZ::RPI::ModelLodAsset::LodCountMax && gridSize > 0; ++i) { From aabde7916fde25177c737c199c9cb8ee94ae2753 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 23 Jan 2022 16:25:57 -0600 Subject: [PATCH 097/136] Atom Tools: Combined ME viewport widget and renderer classes Was looking into options for making any part of this more generic or reusable but 60% of the code is just setup and teardown of processors, handles, entities, and components for the material editor viewport content. The rest is about handling material editors specific setting changes. Most of the general-purpose code has already been moved into atom tools framework render viewport widget. The best reduction or generalization from this point would be using prefabs or some other mechanism to data drive setting up camera, viewport model, IBL, lighting, sky box. Also discussing options for replacing the material editor viewport camera controller and states with a generic one used in the main editor and animation editor. Signed-off-by: Guthrie Adams --- .../Viewport/MaterialViewportRenderer.cpp | 462 ------------------ .../Viewport/MaterialViewportRenderer.h | 114 ----- .../Viewport/MaterialViewportWidget.cpp | 458 ++++++++++++++++- .../Source/Viewport/MaterialViewportWidget.h | 97 +++- .../Code/materialeditor_files.cmake | 2 - 5 files changed, 536 insertions(+), 597 deletions(-) delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp delete mode 100644 Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.h diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp deleted file mode 100644 index 478fb92c55..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.cpp +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#undef RC_INVOKED - -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace MaterialEditor -{ - static constexpr float DepthNear = 0.01f; - - MaterialViewportRenderer::MaterialViewportRenderer(AZStd::shared_ptr windowContext) - : m_windowContext(windowContext) - , m_viewportController(AZStd::make_shared()) - { - using namespace AZ; - using namespace Data; - - // Create and register a scene with all available feature processors - AZ::RPI::SceneDescriptor sceneDesc; - sceneDesc.m_nameId = AZ::Name("MaterialViewport"); - m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); - m_scene->EnableAllFeatureProcessors(); - - // Bind m_defaultScene to the GameEntityContext's AzFramework::Scene - auto sceneSystem = AzFramework::SceneSystemInterface::Get(); - AZ_Assert(sceneSystem, "MaterialViewportRenderer was unable to get the scene system during construction."); - AZStd::shared_ptr mainScene = sceneSystem->GetScene(AzFramework::Scene::MainSceneName); - - // This should never happen unless scene creation has changed. - AZ_Assert(mainScene, "Main scenes missing during system component initialization"); - mainScene->SetSubsystem(m_scene); - - // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene - AZ::Data::Asset pipelineAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath(m_defaultPipelineAssetPath.c_str(), AZ::RPI::AssetUtils::TraceLevel::Error); - m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipelineForWindow(pipelineAsset, *m_windowContext.get()); - pipelineAsset.Release(); - m_scene->AddRenderPipeline(m_renderPipeline); - - // As part of our initialization we need to create the BRDF texture generation pipeline - AZ::RPI::RenderPipelineDescriptor pipelineDesc; - pipelineDesc.m_mainViewTagName = "MainCamera"; - pipelineDesc.m_name = "BRDFTexturePipeline"; - pipelineDesc.m_rootPassTemplate = "BRDFTexturePipeline"; - pipelineDesc.m_executeOnce = true; - - AZ::RPI::RenderPipelinePtr brdfTexturePipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); - m_scene->AddRenderPipeline(brdfTexturePipeline); - - // Currently the scene has to be activated after render pipeline was added so some feature processors (i.e. imgui) can be initialized properly - // with pipeline's pass information. - m_scene->Activate(); - - AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene); - - AzFramework::EntityContextId entityContextId; - AzFramework::GameEntityContextRequestBus::BroadcastResult(entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId); - - // Configure camera - AzFramework::EntityContextRequestBus::EventResult(m_cameraEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "Cameraentity"); - AZ_Assert(m_cameraEntity != nullptr, "Failed to create camera entity."); - - //Add debug camera and controller components - AZ::Debug::CameraComponentConfig cameraConfig(m_windowContext); - cameraConfig.m_fovY = AZ::Constants::HalfPi; - cameraConfig.m_depthNear = DepthNear; - m_cameraComponent = m_cameraEntity->CreateComponent(azrtti_typeid()); - m_cameraComponent->SetConfiguration(cameraConfig); - m_cameraEntity->CreateComponent(azrtti_typeid()); - m_cameraEntity->Activate(); - - // Connect camera to pipeline's default view after camera entity activated - m_renderPipeline->SetDefaultViewFromEntity(m_cameraEntity->GetId()); - - // Configure tone mapper - AzFramework::EntityContextRequestBus::EventResult(m_postProcessEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "postProcessEntity"); - AZ_Assert(m_postProcessEntity != nullptr, "Failed to create post process entity."); - - m_postProcessEntity->CreateComponent(AZ::Render::PostFxLayerComponentTypeId); - m_postProcessEntity->CreateComponent(AZ::Render::ExposureControlComponentTypeId); - m_postProcessEntity->CreateComponent(azrtti_typeid()); - m_postProcessEntity->Activate(); - - // Init directional light processor - m_directionalLightFeatureProcessor = m_scene->GetFeatureProcessor(); - - // Init display mapper processor - m_displayMapperFeatureProcessor = m_scene->GetFeatureProcessor(); - - // Init Skybox - m_skyboxFeatureProcessor = m_scene->GetFeatureProcessor(); - m_skyboxFeatureProcessor->Enable(true); - m_skyboxFeatureProcessor->SetSkyboxMode(AZ::Render::SkyBoxMode::Cubemap); - - // Create IBL - AzFramework::EntityContextRequestBus::EventResult(m_iblEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "IblEntity"); - AZ_Assert(m_iblEntity != nullptr, "Failed to create ibl entity."); - - m_iblEntity->CreateComponent(Render::ImageBasedLightComponentTypeId); - m_iblEntity->CreateComponent(azrtti_typeid()); - m_iblEntity->Activate(); - - // Create model - AzFramework::EntityContextRequestBus::EventResult(m_modelEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportModel"); - AZ_Assert(m_modelEntity != nullptr, "Failed to create model entity."); - - m_modelEntity->CreateComponent(AZ::Render::MeshComponentTypeId); - m_modelEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); - m_modelEntity->CreateComponent(azrtti_typeid()); - m_modelEntity->Activate(); - - // Create shadow catcher - AzFramework::EntityContextRequestBus::EventResult(m_shadowCatcherEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportShadowCatcher"); - AZ_Assert(m_shadowCatcherEntity != nullptr, "Failed to create shadow catcher entity."); - m_shadowCatcherEntity->CreateComponent(AZ::Render::MeshComponentTypeId); - m_shadowCatcherEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); - m_shadowCatcherEntity->CreateComponent(azrtti_typeid()); - m_shadowCatcherEntity->CreateComponent(azrtti_typeid()); - m_shadowCatcherEntity->Activate(); - - AZ::NonUniformScaleRequestBus::Event(m_shadowCatcherEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, AZ::Vector3{ 100, 100, 1.0 }); - - AZ::Data::AssetId shadowCatcherModelAssetId = RPI::AssetUtils::GetAssetIdForProductPath("materialeditor/viewportmodels/plane_1x1.azmodel", RPI::AssetUtils::TraceLevel::Error); - AZ::Render::MeshComponentRequestBus::Event(m_shadowCatcherEntity->GetId(), - &AZ::Render::MeshComponentRequestBus::Events::SetModelAssetId, shadowCatcherModelAssetId); - - auto shadowCatcherMaterialAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath("materials/special/shadowcatcher.azmaterial", RPI::AssetUtils::TraceLevel::Error); - if (shadowCatcherMaterialAsset) - { - m_shadowCatcherOpacityPropertyIndex = shadowCatcherMaterialAsset->GetMaterialTypeAsset()->GetMaterialPropertiesLayout()->FindPropertyIndex(AZ::Name{ "settings.opacity" }); - AZ_Error("MaterialViewportRenderer", m_shadowCatcherOpacityPropertyIndex.IsValid(), "Could not find opacity property"); - - m_shadowCatcherMaterial = AZ::RPI::Material::Create(shadowCatcherMaterialAsset); - AZ_Error("MaterialViewportRenderer", m_shadowCatcherMaterial != nullptr, "Could not create shadow catcher material."); - - AZ::Render::MaterialAssignmentMap shadowCatcherMaterials; - auto& shadowCatcherMaterialAssignment = shadowCatcherMaterials[AZ::Render::DefaultMaterialAssignmentId]; - shadowCatcherMaterialAssignment.m_materialInstance = m_shadowCatcherMaterial; - shadowCatcherMaterialAssignment.m_materialInstancePreCreated = true; - - AZ::Render::MaterialComponentRequestBus::Event(m_shadowCatcherEntity->GetId(), - &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialOverrides, shadowCatcherMaterials); - } - - // Create grid - AzFramework::EntityContextRequestBus::EventResult(m_gridEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportGrid"); - AZ_Assert(m_gridEntity != nullptr, "Failed to create grid entity."); - - AZ::Render::GridComponentConfig gridConfig; - gridConfig.m_gridSize = 4.0f; - gridConfig.m_axisColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f); - gridConfig.m_primaryColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f); - gridConfig.m_secondaryColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f); - auto gridComponent = m_gridEntity->CreateComponent(AZ::Render::GridComponentTypeId); - gridComponent->SetConfiguration(gridConfig); - - m_gridEntity->CreateComponent(azrtti_typeid()); - m_gridEntity->Activate(); - - OnDocumentOpened(AZ::Uuid::CreateNull()); - - // Attempt to apply the default lighting preset - AZ::Render::LightingPresetPtr lightingPreset; - MaterialViewportRequestBus::BroadcastResult(lightingPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); - OnLightingPresetSelected(lightingPreset); - - // Attempt to apply the default model preset - AZ::Render::ModelPresetPtr modelPreset; - MaterialViewportRequestBus::BroadcastResult(modelPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection); - OnModelPresetSelected(modelPreset); - - m_viewportController->Init(m_cameraEntity->GetId(), m_modelEntity->GetId(), m_iblEntity->GetId()); - - // Apply user settinngs restored since last run - AZStd::intrusive_ptr viewportSettings = - AZ::UserSettings::CreateFind(AZ::Crc32("MaterialViewportSettings"), AZ::UserSettings::CT_GLOBAL); - - OnGridEnabledChanged(viewportSettings->m_enableGrid); - OnShadowCatcherEnabledChanged(viewportSettings->m_enableShadowCatcher); - OnAlternateSkyboxEnabledChanged(viewportSettings->m_enableAlternateSkybox); - OnFieldOfViewChanged(viewportSettings->m_fieldOfView); - OnDisplayMapperOperationTypeChanged(viewportSettings->m_displayMapperOperationType); - - AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect(); - MaterialViewportNotificationBus::Handler::BusConnect(); - AZ::TickBus::Handler::BusConnect(); - AZ::TransformNotificationBus::MultiHandler::BusConnect(m_cameraEntity->GetId()); - } - - MaterialViewportRenderer::~MaterialViewportRenderer() - { - AZ::TransformNotificationBus::MultiHandler::BusDisconnect(); - AZ::TickBus::Handler::BusDisconnect(); - AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect(); - MaterialViewportNotificationBus::Handler::BusDisconnect(); - AZ::Data::AssetBus::Handler::BusDisconnect(); - - AzFramework::EntityContextId entityContextId; - AzFramework::GameEntityContextRequestBus::BroadcastResult(entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId); - - AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_iblEntity); - m_iblEntity = nullptr; - - AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity); - m_modelEntity = nullptr; - - AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_shadowCatcherEntity); - m_shadowCatcherEntity = nullptr; - - AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_gridEntity); - m_gridEntity = nullptr; - - AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_cameraEntity); - m_cameraEntity = nullptr; - - AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_postProcessEntity); - m_postProcessEntity = nullptr; - - for (DirectionalLightHandle& handle : m_lightHandles) - { - m_directionalLightFeatureProcessor->ReleaseLight(handle); - } - m_lightHandles.clear(); - - auto sceneSystem = AzFramework::SceneSystemInterface::Get(); - AZ_Assert(sceneSystem, "MaterialViewportRenderer was unable to get the scene system during destruction."); - AZStd::shared_ptr mainScene = sceneSystem->GetScene(AzFramework::Scene::MainSceneName); - // This should never happen unless scene creation has changed. - AZ_Assert(mainScene, "Main scenes missing during system component destruction"); - mainScene->UnsetSubsystem(m_scene); - - m_swapChainPass = nullptr; - AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene); - m_scene = nullptr; - } - - AZStd::shared_ptr MaterialViewportRenderer::GetController() - { - return m_viewportController; - } - - void MaterialViewportRenderer::OnDocumentOpened(const AZ::Uuid& documentId) - { - AZ::Data::Instance materialInstance; - MaterialDocumentRequestBus::EventResult(materialInstance, documentId, &MaterialDocumentRequestBus::Events::GetInstance); - - AZ::Render::MaterialAssignmentMap materials; - auto& materialAssignment = materials[AZ::Render::DefaultMaterialAssignmentId]; - materialAssignment.m_materialInstance = materialInstance; - materialAssignment.m_materialInstancePreCreated = true; - - AZ::Render::MaterialComponentRequestBus::Event(m_modelEntity->GetId(), - &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialOverrides, materials); - } - - void MaterialViewportRenderer::OnLightingPresetSelected(AZ::Render::LightingPresetPtr preset) - { - if (!preset) - { - return; - } - - AZ::Render::ImageBasedLightFeatureProcessorInterface* iblFeatureProcessor = m_scene->GetFeatureProcessor(); - AZ::Render::PostProcessFeatureProcessorInterface* postProcessFeatureProcessor = m_scene->GetFeatureProcessor(); - - AZ::Render::ExposureControlSettingsInterface* exposureControlSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(m_postProcessEntity->GetId())->GetOrCreateExposureControlSettingsInterface(); - - Camera::Configuration cameraConfig; - Camera::CameraRequestBus::EventResult(cameraConfig, m_cameraEntity->GetId(), &Camera::CameraRequestBus::Events::GetCameraConfiguration); - - bool enableAlternateSkybox = false; - MaterialViewportRequestBus::BroadcastResult(enableAlternateSkybox, &MaterialViewportRequestBus::Events::GetAlternateSkyboxEnabled); - - preset->ApplyLightingPreset( - iblFeatureProcessor, - m_skyboxFeatureProcessor, - exposureControlSettingInterface, - m_directionalLightFeatureProcessor, - cameraConfig, - m_lightHandles, - m_shadowCatcherMaterial, - m_shadowCatcherOpacityPropertyIndex, - enableAlternateSkybox); - } - - void MaterialViewportRenderer::OnLightingPresetChanged(AZ::Render::LightingPresetPtr preset) - { - AZ::Render::LightingPresetPtr selectedPreset; - MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); - if (selectedPreset == preset) - { - OnLightingPresetSelected(preset); - } - } - - void MaterialViewportRenderer::OnModelPresetSelected(AZ::Render::ModelPresetPtr preset) - { - if (!preset) - { - return; - } - - if (!preset->m_modelAsset.GetId().IsValid()) - { - AZ_Warning("MaterialViewportRenderer", false, "Attempting to set invalid model for preset: '%s'\n.", preset->m_displayName.c_str()); - return; - } - - if (preset->m_modelAsset.GetId() == m_modelAssetId) - { - return; - } - - AZ::Render::MeshComponentRequestBus::Event(m_modelEntity->GetId(), - &AZ::Render::MeshComponentRequestBus::Events::SetModelAsset, preset->m_modelAsset); - - m_modelAssetId = preset->m_modelAsset.GetId(); - - AZ::Data::AssetBus::Handler::BusDisconnect(); - AZ::Data::AssetBus::Handler::BusConnect(m_modelAssetId); - } - - void MaterialViewportRenderer::OnModelPresetChanged(AZ::Render::ModelPresetPtr preset) - { - AZ::Render::ModelPresetPtr selectedPreset; - MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection); - if (selectedPreset == preset) - { - OnModelPresetSelected(preset); - } - } - - void MaterialViewportRenderer::OnShadowCatcherEnabledChanged(bool enable) - { - AZ::Render::MeshComponentRequestBus::Event(m_shadowCatcherEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetVisibility, enable); - } - - void MaterialViewportRenderer::OnGridEnabledChanged(bool enable) - { - if (m_gridEntity) - { - if (enable && m_gridEntity->GetState() == AZ::Entity::State::Init) - { - m_gridEntity->Activate(); - } - else if (!enable && m_gridEntity->GetState() == AZ::Entity::State::Active) - { - m_gridEntity->Deactivate(); - } - } - } - - void MaterialViewportRenderer::OnAlternateSkyboxEnabledChanged(bool enable) - { - AZ_UNUSED(enable); - AZ::Render::LightingPresetPtr selectedPreset; - MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); - OnLightingPresetSelected(selectedPreset); - } - - void MaterialViewportRenderer::OnFieldOfViewChanged(float fieldOfView) - { - MaterialEditorViewportInputControllerRequestBus::Broadcast(&MaterialEditorViewportInputControllerRequestBus::Handler::SetFieldOfView, fieldOfView); - } - - void MaterialViewportRenderer::OnDisplayMapperOperationTypeChanged(AZ::Render::DisplayMapperOperationType operationType) - { - AZ::Render::DisplayMapperConfigurationDescriptor desc; - desc.m_operationType = operationType; - m_displayMapperFeatureProcessor->RegisterDisplayMapperConfiguration(desc); - } - - void MaterialViewportRenderer::OnAssetReady(AZ::Data::Asset asset) - { - if (m_modelAssetId == asset.GetId()) - { - MaterialEditorViewportInputControllerRequestBus::Broadcast(&MaterialEditorViewportInputControllerRequestBus::Handler::Reset); - AZ::Data::AssetBus::Handler::BusDisconnect(asset.GetId()); - } - } - - void MaterialViewportRenderer::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time) - { - m_renderPipeline->AddToRenderTickOnce(); - - PerformanceMonitorRequestBus::Broadcast(&PerformanceMonitorRequestBus::Handler::GatherMetrics); - - if (m_shadowCatcherMaterial) - { - // Compile the m_shadowCatcherMaterial in OnTick because changes can only be compiled once per frame. - // This is ignored when a compile isn't needed. - m_shadowCatcherMaterial->Compile(); - } - } - - void MaterialViewportRenderer::OnTransformChanged(const AZ::Transform&, const AZ::Transform&) - { - const AZ::EntityId* currentBusId = AZ::TransformNotificationBus::GetCurrentBusId(); - if (m_cameraEntity && currentBusId && *currentBusId == m_cameraEntity->GetId() && m_directionalLightFeatureProcessor) - { - auto transform = AZ::Transform::CreateIdentity(); - AZ::TransformBus::EventResult( - transform, - m_cameraEntity->GetId(), - &AZ::TransformBus::Events::GetWorldTM); - for (const DirectionalLightHandle& id : m_lightHandles) - { - m_directionalLightFeatureProcessor->SetCameraTransform( - id, transform); - } - } - } -} diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.h deleted file mode 100644 index 35b7965a2e..0000000000 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportRenderer.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace AZ -{ - namespace Render - { - class DisplayMapperFeatureProcessorInterface; - } - - class Entity; - class Component; - - namespace RPI - { - class SwapChainPass; - class WindowContext; - } -} - -namespace MaterialEditor -{ - //! Provides backend logic for MaterialViewport - //! Sets up a scene, camera, loads the model, and applies texture - class MaterialViewportRenderer - : public AZ::Data::AssetBus::Handler - , public AZ::TickBus::Handler - , public AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler - , public MaterialViewportNotificationBus::Handler - , public AZ::TransformNotificationBus::MultiHandler - { - public: - AZ_CLASS_ALLOCATOR(MaterialViewportRenderer, AZ::SystemAllocator, 0); - - MaterialViewportRenderer(AZStd::shared_ptr windowContext); - ~MaterialViewportRenderer(); - - AZStd::shared_ptr GetController(); - - private: - - // AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler interface overrides... - void OnDocumentOpened(const AZ::Uuid& documentId) override; - - // MaterialViewportNotificationBus::Handler interface overrides... - void OnLightingPresetSelected(AZ::Render::LightingPresetPtr preset) override; - void OnLightingPresetChanged(AZ::Render::LightingPresetPtr preset) override; - void OnModelPresetSelected(AZ::Render::ModelPresetPtr preset) override; - void OnModelPresetChanged(AZ::Render::ModelPresetPtr preset) override; - void OnShadowCatcherEnabledChanged(bool enable) override; - void OnGridEnabledChanged(bool enable) override; - void OnAlternateSkyboxEnabledChanged(bool enable) override; - void OnFieldOfViewChanged(float fieldOfView) override; - void OnDisplayMapperOperationTypeChanged(AZ::Render::DisplayMapperOperationType operationType) override; - - // AZ::Data::AssetBus::Handler interface overrides... - void OnAssetReady(AZ::Data::Asset asset) override; - - // AZ::TickBus::Handler interface overrides... - void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; - - // AZ::TransformNotificationBus::MultiHandler overrides... - void OnTransformChanged(const AZ::Transform&, const AZ::Transform&) override; - - using DirectionalLightHandle = AZ::Render::DirectionalLightFeatureProcessorInterface::LightHandle; - - AZ::Data::Instance m_swapChainPass; - AZStd::string m_defaultPipelineAssetPath = "passes/MainRenderPipeline.azasset"; - AZStd::shared_ptr m_windowContext; - AZ::RPI::RenderPipelinePtr m_renderPipeline; - AZ::RPI::ScenePtr m_scene; - AZ::Render::DirectionalLightFeatureProcessorInterface* m_directionalLightFeatureProcessor = nullptr; - AZ::Render::DisplayMapperFeatureProcessorInterface* m_displayMapperFeatureProcessor = nullptr; - - AZ::Entity* m_cameraEntity = nullptr; - AZ::Component* m_cameraComponent = nullptr; - bool m_cameraNeedsFullReset = true; - - AZ::Entity* m_postProcessEntity = nullptr; - - AZ::Entity* m_modelEntity = nullptr; - AZ::Data::AssetId m_modelAssetId; - - AZ::Entity* m_gridEntity = nullptr; - - AZ::Entity* m_shadowCatcherEntity = nullptr; - AZ::Data::Instance m_shadowCatcherMaterial; - AZ::RPI::MaterialPropertyIndex m_shadowCatcherOpacityPropertyIndex; - - AZStd::vector m_lightHandles; - - AZ::Entity* m_iblEntity = nullptr; - AZ::Render::SkyBoxFeatureProcessorInterface* m_skyboxFeatureProcessor = nullptr; - - AZStd::shared_ptr m_viewportController; - }; -} // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.cpp index 0322fa194e..dd157c59ac 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.cpp @@ -6,29 +6,65 @@ * */ +#undef RC_INVOKED + +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include +#include #include +#include +#include #include #include #include - -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include -#include "Viewport/ui_MaterialViewportWidget.h" AZ_POP_DISABLE_WARNING -#include - namespace MaterialEditor { + static constexpr float DepthNear = 0.01f; MaterialViewportWidget::MaterialViewportWidget(QWidget* parent) : AtomToolsFramework::RenderViewportWidget(parent) , m_ui(new Ui::MaterialViewportWidget) + , m_viewportController(AZStd::make_shared()) { m_ui->setupUi(this); @@ -38,7 +74,415 @@ namespace MaterialEditor const AZ::Name defaultContextName = viewportContextManager->GetDefaultViewportContextName(); viewportContextManager->RenameViewportContext(GetViewportContext(), defaultContextName); - m_renderer = AZStd::make_unique(GetViewportContext()->GetWindowContext()); - GetControllerList()->Add(m_renderer->GetController()); + // Create and register a scene with all available feature processors + AZ::RPI::SceneDescriptor sceneDesc; + sceneDesc.m_nameId = AZ::Name("MaterialViewport"); + m_scene = AZ::RPI::Scene::CreateScene(sceneDesc); + m_scene->EnableAllFeatureProcessors(); + + // Bind m_defaultScene to the GameEntityContext's AzFramework::Scene + auto sceneSystem = AzFramework::SceneSystemInterface::Get(); + AZ_Assert(sceneSystem, "MaterialViewportWidget was unable to get the scene system during construction."); + AZStd::shared_ptr mainScene = sceneSystem->GetScene(AzFramework::Scene::MainSceneName); + + // This should never happen unless scene creation has changed. + AZ_Assert(mainScene, "Main scenes missing during system component initialization"); + mainScene->SetSubsystem(m_scene); + + // Create a render pipeline from the specified asset for the window context and add the pipeline to the scene + AZ::Data::Asset pipelineAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath( + m_defaultPipelineAssetPath.c_str(), AZ::RPI::AssetUtils::TraceLevel::Error); + m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipelineForWindow(pipelineAsset, *GetViewportContext()->GetWindowContext().get()); + pipelineAsset.Release(); + m_scene->AddRenderPipeline(m_renderPipeline); + + // As part of our initialization we need to create the BRDF texture generation pipeline + AZ::RPI::RenderPipelineDescriptor pipelineDesc; + pipelineDesc.m_mainViewTagName = "MainCamera"; + pipelineDesc.m_name = "BRDFTexturePipeline"; + pipelineDesc.m_rootPassTemplate = "BRDFTexturePipeline"; + pipelineDesc.m_executeOnce = true; + + AZ::RPI::RenderPipelinePtr brdfTexturePipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc); + m_scene->AddRenderPipeline(brdfTexturePipeline); + + // Currently the scene has to be activated after render pipeline was added so some feature processors (i.e. imgui) can be + // initialized properly with pipeline's pass information. + m_scene->Activate(); + + AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene); + + AzFramework::EntityContextId entityContextId; + AzFramework::GameEntityContextRequestBus::BroadcastResult( + entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId); + + // Configure camera + AzFramework::EntityContextRequestBus::EventResult( + m_cameraEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "Cameraentity"); + AZ_Assert(m_cameraEntity != nullptr, "Failed to create camera entity."); + + // Add debug camera and controller components + AZ::Debug::CameraComponentConfig cameraConfig(GetViewportContext()->GetWindowContext()); + cameraConfig.m_fovY = AZ::Constants::HalfPi; + cameraConfig.m_depthNear = DepthNear; + m_cameraComponent = m_cameraEntity->CreateComponent(azrtti_typeid()); + m_cameraComponent->SetConfiguration(cameraConfig); + m_cameraEntity->CreateComponent(azrtti_typeid()); + m_cameraEntity->Activate(); + + // Connect camera to pipeline's default view after camera entity activated + m_renderPipeline->SetDefaultViewFromEntity(m_cameraEntity->GetId()); + + // Configure tone mapper + AzFramework::EntityContextRequestBus::EventResult( + m_postProcessEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "postProcessEntity"); + AZ_Assert(m_postProcessEntity != nullptr, "Failed to create post process entity."); + + m_postProcessEntity->CreateComponent(AZ::Render::PostFxLayerComponentTypeId); + m_postProcessEntity->CreateComponent(AZ::Render::ExposureControlComponentTypeId); + m_postProcessEntity->CreateComponent(azrtti_typeid()); + m_postProcessEntity->Activate(); + + // Init directional light processor + m_directionalLightFeatureProcessor = m_scene->GetFeatureProcessor(); + + // Init display mapper processor + m_displayMapperFeatureProcessor = m_scene->GetFeatureProcessor(); + + // Init Skybox + m_skyboxFeatureProcessor = m_scene->GetFeatureProcessor(); + m_skyboxFeatureProcessor->Enable(true); + m_skyboxFeatureProcessor->SetSkyboxMode(AZ::Render::SkyBoxMode::Cubemap); + + // Create IBL + AzFramework::EntityContextRequestBus::EventResult( + m_iblEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "IblEntity"); + AZ_Assert(m_iblEntity != nullptr, "Failed to create ibl entity."); + + m_iblEntity->CreateComponent(AZ::Render::ImageBasedLightComponentTypeId); + m_iblEntity->CreateComponent(azrtti_typeid()); + m_iblEntity->Activate(); + + // Create model + AzFramework::EntityContextRequestBus::EventResult( + m_modelEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportModel"); + AZ_Assert(m_modelEntity != nullptr, "Failed to create model entity."); + + m_modelEntity->CreateComponent(AZ::Render::MeshComponentTypeId); + m_modelEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); + m_modelEntity->CreateComponent(azrtti_typeid()); + m_modelEntity->Activate(); + + // Create shadow catcher + AzFramework::EntityContextRequestBus::EventResult( + m_shadowCatcherEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportShadowCatcher"); + AZ_Assert(m_shadowCatcherEntity != nullptr, "Failed to create shadow catcher entity."); + m_shadowCatcherEntity->CreateComponent(AZ::Render::MeshComponentTypeId); + m_shadowCatcherEntity->CreateComponent(AZ::Render::MaterialComponentTypeId); + m_shadowCatcherEntity->CreateComponent(azrtti_typeid()); + m_shadowCatcherEntity->CreateComponent(azrtti_typeid()); + m_shadowCatcherEntity->Activate(); + + AZ::NonUniformScaleRequestBus::Event( + m_shadowCatcherEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, AZ::Vector3{ 100, 100, 1.0 }); + + AZ::Data::AssetId shadowCatcherModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath( + "materialeditor/viewportmodels/plane_1x1.azmodel", AZ::RPI::AssetUtils::TraceLevel::Error); + AZ::Render::MeshComponentRequestBus::Event( + m_shadowCatcherEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetModelAssetId, shadowCatcherModelAssetId); + + auto shadowCatcherMaterialAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath( + "materials/special/shadowcatcher.azmaterial", AZ::RPI::AssetUtils::TraceLevel::Error); + if (shadowCatcherMaterialAsset) + { + m_shadowCatcherOpacityPropertyIndex = + shadowCatcherMaterialAsset->GetMaterialTypeAsset()->GetMaterialPropertiesLayout()->FindPropertyIndex( + AZ::Name{ "settings.opacity" }); + AZ_Error("MaterialViewportWidget", m_shadowCatcherOpacityPropertyIndex.IsValid(), "Could not find opacity property"); + + m_shadowCatcherMaterial = AZ::RPI::Material::Create(shadowCatcherMaterialAsset); + AZ_Error("MaterialViewportWidget", m_shadowCatcherMaterial != nullptr, "Could not create shadow catcher material."); + + AZ::Render::MaterialAssignmentMap shadowCatcherMaterials; + auto& shadowCatcherMaterialAssignment = shadowCatcherMaterials[AZ::Render::DefaultMaterialAssignmentId]; + shadowCatcherMaterialAssignment.m_materialInstance = m_shadowCatcherMaterial; + shadowCatcherMaterialAssignment.m_materialInstancePreCreated = true; + + AZ::Render::MaterialComponentRequestBus::Event( + m_shadowCatcherEntity->GetId(), &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialOverrides, + shadowCatcherMaterials); + } + + // Create grid + AzFramework::EntityContextRequestBus::EventResult( + m_gridEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportGrid"); + AZ_Assert(m_gridEntity != nullptr, "Failed to create grid entity."); + + AZ::Render::GridComponentConfig gridConfig; + gridConfig.m_gridSize = 4.0f; + gridConfig.m_axisColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f); + gridConfig.m_primaryColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f); + gridConfig.m_secondaryColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f); + auto gridComponent = m_gridEntity->CreateComponent(AZ::Render::GridComponentTypeId); + gridComponent->SetConfiguration(gridConfig); + + m_gridEntity->CreateComponent(azrtti_typeid()); + m_gridEntity->Activate(); + + OnDocumentOpened(AZ::Uuid::CreateNull()); + + // Attempt to apply the default lighting preset + AZ::Render::LightingPresetPtr lightingPreset; + MaterialViewportRequestBus::BroadcastResult(lightingPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); + OnLightingPresetSelected(lightingPreset); + + // Attempt to apply the default model preset + AZ::Render::ModelPresetPtr modelPreset; + MaterialViewportRequestBus::BroadcastResult(modelPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection); + OnModelPresetSelected(modelPreset); + + m_viewportController->Init(m_cameraEntity->GetId(), m_modelEntity->GetId(), m_iblEntity->GetId()); + + // Apply user settinngs restored since last run + AZStd::intrusive_ptr viewportSettings = + AZ::UserSettings::CreateFind(AZ::Crc32("MaterialViewportSettings"), AZ::UserSettings::CT_GLOBAL); + + OnGridEnabledChanged(viewportSettings->m_enableGrid); + OnShadowCatcherEnabledChanged(viewportSettings->m_enableShadowCatcher); + OnAlternateSkyboxEnabledChanged(viewportSettings->m_enableAlternateSkybox); + OnFieldOfViewChanged(viewportSettings->m_fieldOfView); + OnDisplayMapperOperationTypeChanged(viewportSettings->m_displayMapperOperationType); + + AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect(); + MaterialViewportNotificationBus::Handler::BusConnect(); + AZ::TickBus::Handler::BusConnect(); + AZ::TransformNotificationBus::MultiHandler::BusConnect(m_cameraEntity->GetId()); + + GetControllerList()->Add(m_viewportController); + } + + MaterialViewportWidget::~MaterialViewportWidget() + { + AZ::TransformNotificationBus::MultiHandler::BusDisconnect(); + AZ::TickBus::Handler::BusDisconnect(); + AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect(); + MaterialViewportNotificationBus::Handler::BusDisconnect(); + AZ::Data::AssetBus::Handler::BusDisconnect(); + + AzFramework::EntityContextId entityContextId; + AzFramework::GameEntityContextRequestBus::BroadcastResult( + entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId); + + AzFramework::EntityContextRequestBus::Event( + entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_iblEntity); + m_iblEntity = nullptr; + + AzFramework::EntityContextRequestBus::Event( + entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity); + m_modelEntity = nullptr; + + AzFramework::EntityContextRequestBus::Event( + entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_shadowCatcherEntity); + m_shadowCatcherEntity = nullptr; + + AzFramework::EntityContextRequestBus::Event( + entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_gridEntity); + m_gridEntity = nullptr; + + AzFramework::EntityContextRequestBus::Event( + entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_cameraEntity); + m_cameraEntity = nullptr; + + AzFramework::EntityContextRequestBus::Event( + entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_postProcessEntity); + m_postProcessEntity = nullptr; + + for (DirectionalLightHandle& handle : m_lightHandles) + { + m_directionalLightFeatureProcessor->ReleaseLight(handle); + } + m_lightHandles.clear(); + + auto sceneSystem = AzFramework::SceneSystemInterface::Get(); + AZ_Assert(sceneSystem, "MaterialViewportWidget was unable to get the scene system during destruction."); + AZStd::shared_ptr mainScene = sceneSystem->GetScene(AzFramework::Scene::MainSceneName); + // This should never happen unless scene creation has changed. + AZ_Assert(mainScene, "Main scenes missing during system component destruction"); + mainScene->UnsetSubsystem(m_scene); + + m_swapChainPass = nullptr; + AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene); + m_scene = nullptr; + } + + void MaterialViewportWidget::OnDocumentOpened(const AZ::Uuid& documentId) + { + AZ::Data::Instance materialInstance; + MaterialDocumentRequestBus::EventResult(materialInstance, documentId, &MaterialDocumentRequestBus::Events::GetInstance); + + AZ::Render::MaterialAssignmentMap materials; + auto& materialAssignment = materials[AZ::Render::DefaultMaterialAssignmentId]; + materialAssignment.m_materialInstance = materialInstance; + materialAssignment.m_materialInstancePreCreated = true; + + AZ::Render::MaterialComponentRequestBus::Event( + m_modelEntity->GetId(), &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialOverrides, materials); + } + + void MaterialViewportWidget::OnLightingPresetSelected(AZ::Render::LightingPresetPtr preset) + { + if (!preset) + { + return; + } + + AZ::Render::ImageBasedLightFeatureProcessorInterface* iblFeatureProcessor = + m_scene->GetFeatureProcessor(); + AZ::Render::PostProcessFeatureProcessorInterface* postProcessFeatureProcessor = + m_scene->GetFeatureProcessor(); + + AZ::Render::ExposureControlSettingsInterface* exposureControlSettingInterface = + postProcessFeatureProcessor->GetOrCreateSettingsInterface(m_postProcessEntity->GetId()) + ->GetOrCreateExposureControlSettingsInterface(); + + Camera::Configuration cameraConfig; + Camera::CameraRequestBus::EventResult( + cameraConfig, m_cameraEntity->GetId(), &Camera::CameraRequestBus::Events::GetCameraConfiguration); + + bool enableAlternateSkybox = false; + MaterialViewportRequestBus::BroadcastResult(enableAlternateSkybox, &MaterialViewportRequestBus::Events::GetAlternateSkyboxEnabled); + + preset->ApplyLightingPreset( + iblFeatureProcessor, m_skyboxFeatureProcessor, exposureControlSettingInterface, m_directionalLightFeatureProcessor, + cameraConfig, m_lightHandles, m_shadowCatcherMaterial, m_shadowCatcherOpacityPropertyIndex, enableAlternateSkybox); + } + + void MaterialViewportWidget::OnLightingPresetChanged(AZ::Render::LightingPresetPtr preset) + { + AZ::Render::LightingPresetPtr selectedPreset; + MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); + if (selectedPreset == preset) + { + OnLightingPresetSelected(preset); + } + } + + void MaterialViewportWidget::OnModelPresetSelected(AZ::Render::ModelPresetPtr preset) + { + if (!preset) + { + return; + } + + if (!preset->m_modelAsset.GetId().IsValid()) + { + AZ_Warning( + "MaterialViewportWidget", false, "Attempting to set invalid model for preset: '%s'\n.", preset->m_displayName.c_str()); + return; + } + + if (preset->m_modelAsset.GetId() == m_modelAssetId) + { + return; + } + + AZ::Render::MeshComponentRequestBus::Event( + m_modelEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetModelAsset, preset->m_modelAsset); + + m_modelAssetId = preset->m_modelAsset.GetId(); + + AZ::Data::AssetBus::Handler::BusDisconnect(); + AZ::Data::AssetBus::Handler::BusConnect(m_modelAssetId); + } + + void MaterialViewportWidget::OnModelPresetChanged(AZ::Render::ModelPresetPtr preset) + { + AZ::Render::ModelPresetPtr selectedPreset; + MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection); + if (selectedPreset == preset) + { + OnModelPresetSelected(preset); + } + } + + void MaterialViewportWidget::OnShadowCatcherEnabledChanged(bool enable) + { + AZ::Render::MeshComponentRequestBus::Event( + m_shadowCatcherEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetVisibility, enable); + } + + void MaterialViewportWidget::OnGridEnabledChanged(bool enable) + { + if (m_gridEntity) + { + if (enable && m_gridEntity->GetState() == AZ::Entity::State::Init) + { + m_gridEntity->Activate(); + } + else if (!enable && m_gridEntity->GetState() == AZ::Entity::State::Active) + { + m_gridEntity->Deactivate(); + } + } + } + + void MaterialViewportWidget::OnAlternateSkyboxEnabledChanged(bool enable) + { + AZ_UNUSED(enable); + AZ::Render::LightingPresetPtr selectedPreset; + MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection); + OnLightingPresetSelected(selectedPreset); + } + + void MaterialViewportWidget::OnFieldOfViewChanged(float fieldOfView) + { + MaterialEditorViewportInputControllerRequestBus::Broadcast( + &MaterialEditorViewportInputControllerRequestBus::Handler::SetFieldOfView, fieldOfView); + } + + void MaterialViewportWidget::OnDisplayMapperOperationTypeChanged(AZ::Render::DisplayMapperOperationType operationType) + { + AZ::Render::DisplayMapperConfigurationDescriptor desc; + desc.m_operationType = operationType; + m_displayMapperFeatureProcessor->RegisterDisplayMapperConfiguration(desc); + } + + void MaterialViewportWidget::OnAssetReady(AZ::Data::Asset asset) + { + if (m_modelAssetId == asset.GetId()) + { + MaterialEditorViewportInputControllerRequestBus::Broadcast(&MaterialEditorViewportInputControllerRequestBus::Handler::Reset); + AZ::Data::AssetBus::Handler::BusDisconnect(asset.GetId()); + } + } + + void MaterialViewportWidget::OnTick(float deltaTime, AZ::ScriptTimePoint time) + { + AtomToolsFramework::RenderViewportWidget::OnTick(deltaTime, time); + + m_renderPipeline->AddToRenderTickOnce(); + + PerformanceMonitorRequestBus::Broadcast(&PerformanceMonitorRequestBus::Handler::GatherMetrics); + + if (m_shadowCatcherMaterial) + { + // Compile the m_shadowCatcherMaterial in OnTick because changes can only be compiled once per frame. + // This is ignored when a compile isn't needed. + m_shadowCatcherMaterial->Compile(); + } + } + + void MaterialViewportWidget::OnTransformChanged(const AZ::Transform&, const AZ::Transform&) + { + const AZ::EntityId* currentBusId = AZ::TransformNotificationBus::GetCurrentBusId(); + if (m_cameraEntity && currentBusId && *currentBusId == m_cameraEntity->GetId() && m_directionalLightFeatureProcessor) + { + auto transform = AZ::Transform::CreateIdentity(); + AZ::TransformBus::EventResult(transform, m_cameraEntity->GetId(), &AZ::TransformBus::Events::GetWorldTM); + for (const DirectionalLightHandle& id : m_lightHandles) + { + m_directionalLightFeatureProcessor->SetCameraTransform(id, transform); + } + } } } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.h index 2a71dcc1df..8a660c6603 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/MaterialViewportWidget.h @@ -5,42 +5,115 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #if !defined(Q_MOC_RUN) +#include +#include +#include +#include +#include +#include +#include #include +#include +#include AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT #include AZ_POP_DISABLE_WARNING #endif -#include +namespace AZ +{ + namespace Render + { + class DisplayMapperFeatureProcessorInterface; + } + + class Entity; + class Component; + + namespace RPI + { + class SwapChainPass; + class WindowContext; + } // namespace RPI +} // namespace AZ namespace Ui { class MaterialViewportWidget; } -namespace AZ -{ - namespace RPI - { - class WindowContext; - } -} - namespace MaterialEditor { - class MaterialViewportRenderer; - class MaterialViewportWidget : public AtomToolsFramework::RenderViewportWidget + , public AZ::Data::AssetBus::Handler + , public AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler + , public MaterialViewportNotificationBus::Handler + , public AZ::TransformNotificationBus::MultiHandler { public: MaterialViewportWidget(QWidget* parent = nullptr); + ~MaterialViewportWidget(); + + private: + // AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler interface overrides... + void OnDocumentOpened(const AZ::Uuid& documentId) override; + + // MaterialViewportNotificationBus::Handler interface overrides... + void OnLightingPresetSelected(AZ::Render::LightingPresetPtr preset) override; + void OnLightingPresetChanged(AZ::Render::LightingPresetPtr preset) override; + void OnModelPresetSelected(AZ::Render::ModelPresetPtr preset) override; + void OnModelPresetChanged(AZ::Render::ModelPresetPtr preset) override; + void OnShadowCatcherEnabledChanged(bool enable) override; + void OnGridEnabledChanged(bool enable) override; + void OnAlternateSkyboxEnabledChanged(bool enable) override; + void OnFieldOfViewChanged(float fieldOfView) override; + void OnDisplayMapperOperationTypeChanged(AZ::Render::DisplayMapperOperationType operationType) override; + + // AZ::Data::AssetBus::Handler interface overrides... + void OnAssetReady(AZ::Data::Asset asset) override; + + // AZ::TickBus::Handler interface overrides... + void OnTick(float deltaTime, AZ::ScriptTimePoint time) override; + + // AZ::TransformNotificationBus::MultiHandler overrides... + void OnTransformChanged(const AZ::Transform&, const AZ::Transform&) override; + + using DirectionalLightHandle = AZ::Render::DirectionalLightFeatureProcessorInterface::LightHandle; + + AZ::Data::Instance m_swapChainPass; + AZStd::string m_defaultPipelineAssetPath = "passes/MainRenderPipeline.azasset"; + AZ::RPI::RenderPipelinePtr m_renderPipeline; + AZ::RPI::ScenePtr m_scene; + AZ::Render::DirectionalLightFeatureProcessorInterface* m_directionalLightFeatureProcessor = {}; + AZ::Render::DisplayMapperFeatureProcessorInterface* m_displayMapperFeatureProcessor = {}; + + AZ::Entity* m_cameraEntity = {}; + AZ::Component* m_cameraComponent = {}; + + AZ::Entity* m_postProcessEntity = {}; + + AZ::Entity* m_modelEntity = {}; + AZ::Data::AssetId m_modelAssetId; + + AZ::Entity* m_gridEntity = {}; + + AZ::Entity* m_shadowCatcherEntity = {}; + AZ::Data::Instance m_shadowCatcherMaterial; + AZ::RPI::MaterialPropertyIndex m_shadowCatcherOpacityPropertyIndex; + + AZStd::vector m_lightHandles; + + AZ::Entity* m_iblEntity = {}; + AZ::Render::SkyBoxFeatureProcessorInterface* m_skyboxFeatureProcessor = {}; + + AZStd::shared_ptr m_viewportController; QScopedPointer m_ui; - AZStd::unique_ptr m_renderer; }; } // namespace MaterialEditor diff --git a/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake b/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake index 9d1e2b22f8..f7a15d2bcc 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake +++ b/Gems/Atom/Tools/MaterialEditor/Code/materialeditor_files.cmake @@ -49,8 +49,6 @@ set(FILES Source/Viewport/MaterialViewportWidget.cpp Source/Viewport/MaterialViewportWidget.h Source/Viewport/MaterialViewportWidget.ui - Source/Viewport/MaterialViewportRenderer.cpp - Source/Viewport/MaterialViewportRenderer.h Source/Viewport/PerformanceMonitorComponent.cpp Source/Viewport/PerformanceMonitorComponent.h From 1643c68fa7f133ff68eb7405e43e5a22f2901de5 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sun, 23 Jan 2022 18:26:31 -0800 Subject: [PATCH 098/136] chore: fix compiling errors Signed-off-by: Michael Pollind --- .../Input/QtEventToAzInputMapperTests.cpp | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp b/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp index 31193f6f05..78a08af6cb 100644 --- a/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp @@ -562,7 +562,7 @@ namespace UnitTest AZ::Vector2 accumulatedPosition(0.0f,0.0f); for(const auto& pos: m_azCursorPositions) { - accumulatedPosition += (pos.m_normalizedPositionDelta * AZ::Vector2(WidgetSize.width(), WidgetSize.height())); + accumulatedPosition += (pos.m_normalizedPositionDelta * AZ::Vector2((float)WidgetSize.width(), (float)WidgetSize.height())); } // validate @@ -584,106 +584,106 @@ namespace UnitTest // verify CursorModeWrappedX wrapping MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedX, 40, - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height() / 2), QPoint(40, 0), - QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height() / 2), "CursorModeWrappedX_Test_Right" }, MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedX, 40, - QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height() / 2), QPoint(-40, 0), - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2), "CursorModeWrappedX_Test_Left" }, MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedX, 40, - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, 20.0f), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, 20), QPoint(0, -40), - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, -20.0f), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, -20), "CursorModeWrappedX_Test_Top" }, MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedX, 40, - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() - 20), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() - 20), QPoint(0, 40), - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() + 20), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() + 20), "CursorModeWrappedX_Test_Bottom" }, // verify CursorModeWrappedY wrapping MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedY, 40, - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2), QPoint(40, 0), - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() + 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() + 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2), "CursorModeWrappedY_Test_Right" }, MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedY, 40, - QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height() / 2), QPoint(-40, 0), - QPoint(-20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(-20, QtEventToAzInputMapperFixture::WidgetSize.height() / 2), "CursorModeWrappedY_Test_Left" }, MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedY, 40, - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, 20.0f), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, 20), QPoint(0, -40), - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() - 20.0f), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() - 20), "CursorModeWrappedY_Test_Top" }, MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedY, 40, - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() - 20), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() - 20), QPoint(0, 40), - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, 20), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, 20), "CursorModeWrappedY_Test_Bottom" }, // verify CursorModeWrapped wrapping MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrapped, 40, - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2), QPoint(40, 0), - QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height()/2), "CursorModeWrapped_Test_Right" }, MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrapped, 40, - QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height() / 2), QPoint(-40, 0), - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2.0f), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2), "CursorModeWrapped_Test_Left" }, MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrapped, 40, - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, 20.0f), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, 20), QPoint(0, -40), - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() - 20.0f), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() - 20), "CursorModeWrapped_Test_Top" }, MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrapped, 40, - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() - 20), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() - 20), QPoint(0, 40), - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, 20), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, 20), "CursorModeWrapped_Test_Bottom" }, // verify CursorModeCaptured MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeCaptured, 40, - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() / 2.0f), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() / 2), QPoint(0, 40), - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() / 2.0f), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() / 2), "CursorModeCaptured" }, // verify CursorModeNone MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeNone, 40, - QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f, QtEventToAzInputMapperFixture::WidgetSize.height() / 2.0f), - QPoint(40.0f, 0), - QPoint((QtEventToAzInputMapperFixture::WidgetSize.width() / 2.0f) + 40.0f, (QtEventToAzInputMapperFixture::WidgetSize.height() / 2.0f)), + QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() / 2), + QPoint(40, 0), + QPoint((QtEventToAzInputMapperFixture::WidgetSize.width() / 2) + 40, (QtEventToAzInputMapperFixture::WidgetSize.height() / 2)), "CursorModeNone" } ), From 3113b8be03c02b12d9b94b1ae5d4d5eae471a948 Mon Sep 17 00:00:00 2001 From: Steve Pham <82231385+spham-amzn@users.noreply.github.com> Date: Sun, 23 Jan 2022 23:17:25 -0800 Subject: [PATCH 099/136] Fix for 'Cannot Find PThread' when using GCC (#7097) * Fix for 'Cannot Find PThread' when using GCC Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> * Fix error when COMPILATION_C and COMPILATION_CXX handling in ly_append_configurations_options Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> * Add missing 'PARENT_SCOPE' when appending to the CMAKE_C_FLAGS and CMAKE_CXX_FLAGS Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> * Fix appending of CMAKE_C_FLAGS and CMAKE_CXX_FLAGS Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> * Workaround for C/C++ compilation flag settings for gcc. COMPILATION_C/COMPILATION_CXX is wiping out COMPILATION, so define each one separately with no sharing Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> * Remove unnecessary gcc ignore warnings for C files Signed-off-by: Steve Pham <82231385+spham-amzn@users.noreply.github.com> --- cmake/Configurations.cmake | 13 +++++----- .../Common/GCC/Configurations_gcc.cmake | 24 +++++++++++-------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/cmake/Configurations.cmake b/cmake/Configurations.cmake index 63af3d8810..20d94024bb 100644 --- a/cmake/Configurations.cmake +++ b/cmake/Configurations.cmake @@ -42,6 +42,8 @@ include(cmake/ConfigurationTypes.cmake) # \arg:LINK_SHARED # \arg:LINK_SHARED_${CONFIGURATION} # +# Note: COMPILATION_C/COMPILATION_CXX are mutually exclusive with COMPILATION. You can only specify COMPILATION for C/C++ flags or +# a combination of COMPILATION_C/COMPILATION_CXX for the separate c/c++ flags separately. function(ly_append_configurations_options) set(options) @@ -80,15 +82,14 @@ function(ly_append_configurations_options) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILATION_STR}" PARENT_SCOPE) endif() if(ly_append_configurations_options_COMPILATION_C) - string(REPLACE ";" " " COMPILATION_STR "${ly_append_configurations_options_COMPILATION}") - string(APPEND CMAKE_C_FLAGS " " ${COMPILATION_STR}) - set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} PARENT_SCOPE) + string(REPLACE ";" " " COMPILATION_STR "${ly_append_configurations_options_COMPILATION_C}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COMPILATION_STR}" PARENT_SCOPE) endif() if(ly_append_configurations_options_COMPILATION_CXX) - string(REPLACE ";" " " COMPILATION_STR "${ly_append_configurations_options_COMPILATION}") - string(APPEND CMAKE_CXX_FLAGS " " ${COMPILATION_STR}) - set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} PARENT_SCOPE) + string(REPLACE ";" " " COMPILATION_STR "${ly_append_configurations_options_COMPILATION_CXX}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILATION_STR}" PARENT_SCOPE) endif() + if(ly_append_configurations_options_LINK) string(REPLACE ";" " " LINK_STR "${ly_append_configurations_options_LINK}") set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} ${LINK_STR}" PARENT_SCOPE) diff --git a/cmake/Platform/Common/GCC/Configurations_gcc.cmake b/cmake/Platform/Common/GCC/Configurations_gcc.cmake index 17c2474fb8..3db96306ee 100644 --- a/cmake/Platform/Common/GCC/Configurations_gcc.cmake +++ b/cmake/Platform/Common/GCC/Configurations_gcc.cmake @@ -20,7 +20,17 @@ endif() ly_append_configurations_options( - COMPILATION + + COMPILATION_C + -fno-exceptions + -fvisibility=hidden + -Wall + -Werror + + ${LY_GCC_GCOV_FLAGS} + ${LY_GCC_GPROF_FLAGS} + + COMPILATION_CXX -fno-exceptions -fvisibility=hidden -Wall @@ -40,10 +50,8 @@ ly_append_configurations_options( -Wno-unused-value -Wno-unused-variable -Wno-format-truncation - -Wno-reorder -Wno-uninitialized -Wno-array-bounds - -Wno-class-memaccess -Wno-nonnull-compare -Wno-strict-aliasing -Wno-unused-result @@ -58,18 +66,14 @@ ly_append_configurations_options( -Wno-enum-compare -Wno-int-in-bool-context -Wno-sequence-point - -Wno-delete-non-virtual-dtor -Wno-comment - -Wno-reorder -Wno-restrict -Wno-format-overflow - - COMPILATION_C - -Wno-absolute-value - - COMPILATION_CXX -fvisibility-inlines-hidden -Wno-invalid-offsetof + -Wno-class-memaccess + -Wno-delete-non-virtual-dtor + -Wno-reorder COMPILATION_DEBUG -O0 # No optimization From 59409822446d896aed127c587eda277c1d47cde1 Mon Sep 17 00:00:00 2001 From: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> Date: Mon, 24 Jan 2022 10:41:32 +0000 Subject: [PATCH 100/136] Ensure render geometry is refreshed when the mesh component controller is moved (#6452) * ensure render geometry is refreshed when the mesh component controller is moved Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * cache bus pointer and send update notification when mesh changes Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * add integration test to detect MeshComponentController notification to IntersectionNotificationBus Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * remove optimize off Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * update build visibility for AtomLyIntegration editor static lib Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> * move runtime dependencies to gem module Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com> --- .../AzFramework/Render/Intersector.h | 26 ++-- .../CommonFeatures/Code/CMakeLists.txt | 50 +++++++- .../Source/Mesh/MeshComponentController.cpp | 36 ++++-- .../Source/Mesh/MeshComponentController.h | 3 +- .../CommonFeatures/Code/Tests/Main.cpp | 39 ++++++ .../Tests/MeshComponentControllerTests.cpp | 116 ++++++++++++++++++ ...egration_commonfeatures_editor_files.cmake | 1 - ...ion_commonfeatures_editor_test_files.cmake | 11 ++ 8 files changed, 253 insertions(+), 29 deletions(-) create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Tests/Main.cpp create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/Tests/MeshComponentControllerTests.cpp create mode 100644 Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_test_files.cmake diff --git a/Code/Framework/AzFramework/AzFramework/Render/Intersector.h b/Code/Framework/AzFramework/AzFramework/Render/Intersector.h index acd6553c32..ba11996a65 100644 --- a/Code/Framework/AzFramework/AzFramework/Render/Intersector.h +++ b/Code/Framework/AzFramework/AzFramework/Render/Intersector.h @@ -5,25 +5,23 @@ * SPDX-License-Identifier: Apache-2.0 OR MIT * */ + #pragma once #include #include #include - #include +#include #include #include -#include - namespace AzFramework { - namespace RenderGeometry { - //! Implementation of IntersectorBus interface, this class contains a cached AABB list - //! of the connected entities to the intersection bus and calculates performant ray intersections against them + //! Implementation of IntersectorBus interface, this class contains a cached AABB list of the connected + //! entities to the intersection bus and calculates efficient ray intersections against them. class Intersector final : public IntersectorBus::Handler , protected IntersectionNotificationBus::Handler @@ -34,32 +32,32 @@ namespace AzFramework Intersector(AzFramework::EntityContextId contextId); ~Intersector(); - // IntersectorBus + // IntersectorBus overrides ... RayResult RayIntersect(const RayRequest& ray) override; - // IntersectionNotifications + // IntersectionNotificationBus overrides ... void OnEntityConnected(AZ::EntityId entityId) override; void OnEntityDisconnected(AZ::EntityId entityId) override; void OnGeometryChanged(AZ::EntityId entityId) override; private: - struct EntityData { EntityData(AZ::EntityId id, AZ::Aabb aabb) : m_id(id) , m_aabb(aabb) - , m_ref(1) {} + , m_ref(1) + { + } AZ::EntityId m_id; AZ::Aabb m_aabb; int m_ref; }; - + class EntityDataList { public: - int AddRef(AZ::EntityId entityId); int RemoveRef(AZ::EntityId entityId); void Update(const EntityData& newData); @@ -88,5 +86,5 @@ namespace AzFramework AZStd::vector> m_candidatesSortedByDist; AzFramework::EntityContextId m_contextId; }; - } -} + } // namespace RenderGeometry +} // namespace AzFramework diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt b/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt index 3234db2292..7c31751421 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/CMakeLists.txt @@ -77,8 +77,7 @@ ly_create_alias(NAME AtomLyIntegration_CommonFeatures.Servers NAMESPACE Gem if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME AtomLyIntegration_CommonFeatures.Editor GEM_MODULE - + NAME AtomLyIntegration_CommonFeatures.Editor.Static STATIC NAMESPACE Gem AUTOUIC AUTOMOC @@ -98,7 +97,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) PRIVATE ATOMLYINTEGRATION_FEATURE_COMMON_EDITOR BUILD_DEPENDENCIES - PRIVATE + PUBLIC Gem::AtomLyIntegration_CommonFeatures.Static Gem::Atom_RPI.Edit Gem::AtomToolsFramework.Static @@ -108,6 +107,24 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Legacy::Editor.Headers Legacy::EditorCommon Legacy::CryCommon + ) + + ly_add_target( + NAME AtomLyIntegration_CommonFeatures.Editor GEM_MODULE + NAMESPACE Gem + FILES_CMAKE + atomlyintegration_commonfeatures_shared_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Source + PUBLIC + Include + COMPILE_DEFINITIONS + PRIVATE + ATOMLYINTEGRATION_FEATURE_COMMON_EDITOR + BUILD_DEPENDENCIES + PRIVATE + Gem::AtomLyIntegration_CommonFeatures.Editor.Static RUNTIME_DEPENDENCIES Gem::Atom_RPI.Editor Gem::Atom_Feature_Common.Editor @@ -128,6 +145,33 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS) Gem::AtomLyIntegration_CommonFeatures.Editor Gem::GradientSignal.Tools ) + + ################################################################################ + # Tests + ################################################################################ + if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) + ly_add_target( + NAME AtomLyIntegration_CommonFeatures.Editor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} + NAMESPACE Gem + FILES_CMAKE + atomlyintegration_commonfeatures_editor_test_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Tests + Source + BUILD_DEPENDENCIES + PRIVATE + AZ::AzTest + AZ::AzTestShared + AZ::AzToolsFramework + AZ::AzToolsFrameworkTestCommon + Gem::AtomLyIntegration_CommonFeatures.Static + Gem::AtomLyIntegration_CommonFeatures.Editor.Static + ) + ly_add_googletest( + NAME Gem::AtomLyIntegration_CommonFeatures.Editor.Tests + ) + endif() endif() # AtomLyIntegration_CommonFeatures gem targets are required as part of the Editor and AssetProcessor diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index a68ad24adf..e26d328e17 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -82,7 +82,6 @@ namespace AZ ->Field("MinimumScreenCoverage", &MeshComponentConfig::m_minimumScreenCoverage) ->Field("QualityDecayRate", &MeshComponentConfig::m_qualityDecayRate); } - } bool MeshComponentConfig::IsAssetSet() @@ -225,33 +224,42 @@ namespace AZ { } + static AzFramework::EntityContextId FindOwningContextId(const AZ::EntityId entityId) + { + AzFramework::EntityContextId contextId = AzFramework::EntityContextId::CreateNull(); + AzFramework::EntityIdContextQueryBus::EventResult( + contextId, entityId, &AzFramework::EntityIdContextQueries::GetOwningContextId); + return contextId; + } + void MeshComponentController::Activate(const AZ::EntityComponentIdPair& entityComponentIdPair) { const AZ::EntityId entityId = entityComponentIdPair.GetEntityId(); m_entityComponentIdPair = entityComponentIdPair; m_transformInterface = TransformBus::FindFirstHandler(entityId); - AZ_Warning("MeshComponentController", m_transformInterface, "Unable to attach to a TransformBus handler. This mesh will always be rendered at the origin."); + AZ_Warning( + "MeshComponentController", m_transformInterface, + "Unable to attach to a TransformBus handler. This mesh will always be rendered at the origin."); m_meshFeatureProcessor = RPI::Scene::GetFeatureProcessorForEntity(entityId); AZ_Error("MeshComponentController", m_meshFeatureProcessor, "Unable to find a MeshFeatureProcessorInterface on the entityId."); m_cachedNonUniformScale = AZ::Vector3::CreateOne(); AZ::NonUniformScaleRequestBus::EventResult(m_cachedNonUniformScale, entityId, &AZ::NonUniformScaleRequests::GetScale); - AZ::NonUniformScaleRequestBus::Event(entityId, &AZ::NonUniformScaleRequests::RegisterScaleChangedEvent, - m_nonUniformScaleChangedHandler); + AZ::NonUniformScaleRequestBus::Event( + entityId, &AZ::NonUniformScaleRequests::RegisterScaleChangedEvent, m_nonUniformScaleChangedHandler); + const auto entityContextId = FindOwningContextId(entityId); MeshComponentRequestBus::Handler::BusConnect(entityId); TransformNotificationBus::Handler::BusConnect(entityId); MaterialReceiverRequestBus::Handler::BusConnect(entityId); MaterialComponentNotificationBus::Handler::BusConnect(entityId); AzFramework::BoundsRequestBus::Handler::BusConnect(entityId); - AzFramework::EntityContextId contextId; - AzFramework::EntityIdContextQueryBus::EventResult( - contextId, entityId, &AzFramework::EntityIdContextQueries::GetOwningContextId); - AzFramework::RenderGeometry::IntersectionRequestBus::Handler::BusConnect({entityId, contextId}); + AzFramework::RenderGeometry::IntersectionRequestBus::Handler::BusConnect({ entityId, entityContextId }); + AzFramework::RenderGeometry::IntersectionNotificationBus::Bind(m_intersectionNotificationBus, entityContextId); - //Buses must be connected before RegisterModel in case requests are made as a result of HandleModelChange + // Buses must be connected before RegisterModel in case requests are made as a result of HandleModelChange RegisterModel(); } @@ -291,6 +299,11 @@ namespace AZ { m_meshFeatureProcessor->SetTransform(m_meshHandle, world, m_cachedNonUniformScale); } + + // ensure the render geometry is kept in sync with any changes to the entity the mesh is on + AzFramework::RenderGeometry::IntersectionNotificationBus::Event( + m_intersectionNotificationBus, &AzFramework::RenderGeometry::IntersectionNotificationBus::Events::OnGeometryChanged, + m_entityComponentIdPair.GetEntityId()); } void MeshComponentController::HandleNonUniformScaleChange(const AZ::Vector3& nonUniformScale) @@ -301,7 +314,7 @@ namespace AZ m_meshFeatureProcessor->SetTransform(m_meshHandle, m_transformInterface->GetWorldTM(), m_cachedNonUniformScale); } } - + RPI::ModelMaterialSlotMap MeshComponentController::GetModelMaterialSlots() const { Data::Asset modelAsset = GetModelAsset(); @@ -369,6 +382,9 @@ namespace AZ MeshComponentNotificationBus::Event(entityId, &MeshComponentNotificationBus::Events::OnModelReady, m_configuration.m_modelAsset, model); MaterialReceiverNotificationBus::Event(entityId, &MaterialReceiverNotificationBus::Events::OnMaterialAssignmentsChanged); AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(entityId); + AzFramework::RenderGeometry::IntersectionNotificationBus::Event( + m_intersectionNotificationBus, &AzFramework::RenderGeometry::IntersectionNotificationBus::Events::OnGeometryChanged, + m_entityComponentIdPair.GetEntityId()); } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h index 76cf6a1b39..cecd744b80 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h @@ -162,6 +162,8 @@ namespace AZ bool m_isVisible = true; MeshComponentConfig m_configuration; AZ::Vector3 m_cachedNonUniformScale = AZ::Vector3::CreateOne(); + //! Cached bus to use to notify RenderGeometry::Intersector the entity/component has changed. + AzFramework::RenderGeometry::IntersectionNotificationBus::BusPtr m_intersectionNotificationBus; MeshFeatureProcessorInterface::ModelChangedEvent::Handler m_changeEventHandler { @@ -173,6 +175,5 @@ namespace AZ [&](const AZ::Vector3& nonUniformScale) { HandleNonUniformScaleChange(nonUniformScale); } }; }; - } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Tests/Main.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Tests/Main.cpp new file mode 100644 index 0000000000..2d75cf96f5 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Tests/Main.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +#include + +class AtomLyIntegrationHook : public AZ::Test::ITestEnvironment +{ +public: + void SetupEnvironment() override + { + AZ::AllocatorInstance::Create(); + } + + void TeardownEnvironment() override + { + AZ::AllocatorInstance::Destroy(); + } +}; + +// required to support running integration tests with Qt +AZTEST_EXPORT int AZ_UNIT_TEST_HOOK_NAME(int argc, char** argv) +{ + ::testing::InitGoogleMock(&argc, argv); + QApplication app(argc, argv); + AZ::Test::printUnusedParametersWarning(argc, argv); + AZ::Test::addTestEnvironments({ DEFAULT_UNIT_TEST_ENV, new AtomLyIntegrationHook }); + int result = RUN_ALL_TESTS(); + return result; +} + +IMPLEMENT_TEST_EXECUTABLE_MAIN(); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Tests/MeshComponentControllerTests.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Tests/MeshComponentControllerTests.cpp new file mode 100644 index 0000000000..bc1bf3a247 --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Tests/MeshComponentControllerTests.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include + +#include +#include + +namespace UnitTest +{ + static AzFramework::EntityContextId FindOwningContextId(const AZ::EntityId entityId) + { + AzFramework::EntityContextId contextId = AzFramework::EntityContextId::CreateNull(); + AzFramework::EntityIdContextQueryBus::EventResult(contextId, entityId, &AzFramework::EntityIdContextQueries::GetOwningContextId); + return contextId; + } + + class IntersectionNotificationDetector : public AzFramework::RenderGeometry::IntersectionNotificationBus::Handler + { + public: + void Connect(const AzFramework::EntityContextId& entityContextId); + void Disconnect(); + + // IntersectionNotificationBus overrides ... + void OnEntityConnected(AZ::EntityId entityId) override; + void OnEntityDisconnected(AZ::EntityId entityId) override; + void OnGeometryChanged(AZ::EntityId entityId) override; + + AZ::EntityId m_lastEntityIdChanged; + }; + + void IntersectionNotificationDetector::Connect(const AzFramework::EntityContextId& entityContextId) + { + AzFramework::RenderGeometry::IntersectionNotificationBus::Handler::BusConnect(entityContextId); + } + + void IntersectionNotificationDetector::Disconnect() + { + AzFramework::RenderGeometry::IntersectionNotificationBus::Handler::BusDisconnect(); + } + + void IntersectionNotificationDetector::OnEntityConnected([[maybe_unused]] AZ::EntityId entityId) + { + } + + void IntersectionNotificationDetector::OnEntityDisconnected([[maybe_unused]] AZ::EntityId entityId) + { + } + + void IntersectionNotificationDetector::OnGeometryChanged(AZ::EntityId entityId) + { + m_lastEntityIdChanged = entityId; + } + + class MeshComponentControllerFixture : public ToolsApplicationFixture + { + public: + void SetUpEditorFixtureImpl() override + { + m_meshComponentDescriptor = AZStd::unique_ptr(AZ::Render::MeshComponent::CreateDescriptor()); + m_meshComponentDescriptor->Reflect(GetApplication()->GetSerializeContext()); + + m_editorMeshComponentDescriptor = + AZStd::unique_ptr(AZ::Render::EditorMeshComponent::CreateDescriptor()); + m_editorMeshComponentDescriptor->Reflect(GetApplication()->GetSerializeContext()); + + m_entityId1 = CreateDefaultEditorEntity("Entity1"); + m_entityIds.push_back(m_entityId1); + + m_intersectionNotificationDetector.Connect(FindOwningContextId(m_entityId1)); + } + + void TearDownEditorFixtureImpl() override + { + bool entityDestroyed = false; + AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult( + entityDestroyed, &AzToolsFramework::EditorEntityContextRequestBus::Events::DestroyEditorEntity, m_entityId1); + + m_intersectionNotificationDetector.Disconnect(); + + m_meshComponentDescriptor.reset(); + m_editorMeshComponentDescriptor.reset(); + } + + AZ::EntityId m_entityId1; + AzToolsFramework::EntityIdList m_entityIds; + AZStd::unique_ptr m_meshComponentDescriptor; + AZStd::unique_ptr m_editorMeshComponentDescriptor; + IntersectionNotificationDetector m_intersectionNotificationDetector; + }; + + TEST_F(MeshComponentControllerFixture, IntersectionNotificationBusIsNotifiedWhenMeshComponentControllerTransformIsModified) + { + auto* entity1 = AzToolsFramework::GetEntityById(m_entityId1); + entity1->Deactivate(); + entity1->CreateComponent(); + // note: RPI::Scene::GetFeatureProcessorForEntity(...) returns nullptr + // and so m_meshFeatureProcessor is null + AZ_TEST_START_TRACE_SUPPRESSION; + entity1->Activate(); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + + AZ::TransformBus::Event( + m_entityId1, &AZ::TransformBus::Events::SetWorldTM, AZ::Transform::CreateTranslation(AZ::Vector3(1.0f, 2.0f, 3.0f))); + + using ::testing::Eq; + EXPECT_THAT(m_entityId1, Eq(m_intersectionNotificationDetector.m_lastEntityIdChanged)); + } +} // namespace UnitTest diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake index 0dea725d70..018795dcf2 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_files.cmake @@ -10,7 +10,6 @@ set(FILES Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentNotificationBus.h Include/AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h Include/AtomLyIntegration/CommonFeatures/ReflectionProbe/EditorReflectionProbeBus.h - Source/Module.cpp Source/Animation/EditorAttachmentComponent.h Source/Animation/EditorAttachmentComponent.cpp Source/EditorCommonFeaturesSystemComponent.h diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_test_files.cmake b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_test_files.cmake new file mode 100644 index 0000000000..5a58124e0a --- /dev/null +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/atomlyintegration_commonfeatures_editor_test_files.cmake @@ -0,0 +1,11 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + Tests/Main.cpp + Tests/MeshComponentControllerTests.cpp) From d412f3cc502d598464422444ea991cd0cfb0ab84 Mon Sep 17 00:00:00 2001 From: greerdv Date: Mon, 24 Jan 2022 12:38:15 +0000 Subject: [PATCH 101/136] update with feedback from PR Signed-off-by: greerdv --- .../Source/EditorShapeColliderComponent.cpp | 17 ++++++++--------- .../Code/Source/EditorShapeColliderComponent.h | 4 ++-- .../Code/Tests/ShapeColliderComponentTests.cpp | 16 +++++++++------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp index bdf70fc227..d99a76f306 100644 --- a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp +++ b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.cpp @@ -55,7 +55,7 @@ namespace PhysX m_colliderConfig.SetPropertyVisibility(Physics::ColliderConfiguration::Offset, false); } - AZ::Crc32 EditorShapeColliderComponent::SubdivisionCountVisibility() + AZ::Crc32 EditorShapeColliderComponent::SubdivisionCountVisibility() const { if (m_shapeType == ShapeType::Cylinder) { @@ -65,7 +65,7 @@ namespace PhysX return AZ::Edit::PropertyVisibility::Hide; } - AZ::Crc32 EditorShapeColliderComponent::SingleSidedVisibility() + AZ::Crc32 EditorShapeColliderComponent::SingleSidedVisibility() const { if ((m_shapeType == ShapeType::QuadSingleSided || m_shapeType == ShapeType::QuadDoubleSided) && GetEntity()->FindComponent() == nullptr) @@ -124,16 +124,16 @@ namespace PhysX void EditorShapeColliderComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided) { - provided.push_back(AZ_CRC("PhysicsWorldBodyService", 0x944da0cc)); - provided.push_back(AZ_CRC("PhysXColliderService", 0x4ff43f7c)); - provided.push_back(AZ_CRC("PhysXTriggerService", 0x3a117d7b)); - provided.push_back(AZ_CRC("PhysXShapeColliderService", 0x98a7e779)); + provided.push_back(AZ_CRC_CE("PhysicsWorldBodyService")); + provided.push_back(AZ_CRC_CE("PhysXColliderService")); + provided.push_back(AZ_CRC_CE("PhysXTriggerService")); + provided.push_back(AZ_CRC_CE("PhysXShapeColliderService")); } void EditorShapeColliderComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) { - required.push_back(AZ_CRC("TransformService", 0x8ee22c50)); - required.push_back(AZ_CRC("ShapeService", 0xe86aa5fe)); + required.push_back(AZ_CRC_CE("TransformService")); + required.push_back(AZ_CRC_CE("ShapeService")); } void EditorShapeColliderComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible) @@ -422,7 +422,6 @@ namespace PhysX SetShapeConfig(ShapeType::QuadSingleSided, shapeConfig); } - else { // it's not possible to create a perfectly 2d convex in PhysX, so the best we can do is a very thin box diff --git a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.h b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.h index 0f5350b781..09d5f803fc 100644 --- a/Gems/PhysX/Code/Source/EditorShapeColliderComponent.h +++ b/Gems/PhysX/Code/Source/EditorShapeColliderComponent.h @@ -105,9 +105,9 @@ namespace PhysX void RefreshUiProperties(); AZ::u32 OnSubdivisionCountChange(); - AZ::Crc32 SubdivisionCountVisibility(); + AZ::Crc32 SubdivisionCountVisibility() const; void OnSingleSidedChange(); - AZ::Crc32 SingleSidedVisibility(); + AZ::Crc32 SingleSidedVisibility() const; // AZ::Component void Activate() override; diff --git a/Gems/PhysX/Code/Tests/ShapeColliderComponentTests.cpp b/Gems/PhysX/Code/Tests/ShapeColliderComponentTests.cpp index c164e5de63..c9dcbe64d1 100644 --- a/Gems/PhysX/Code/Tests/ShapeColliderComponentTests.cpp +++ b/Gems/PhysX/Code/Tests/ShapeColliderComponentTests.cpp @@ -470,7 +470,7 @@ namespace PhysXEditorTests void SetTrigger(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent, bool isTrigger) { - SetBoolValueOnComponent(editorShapeColliderComponent, AZ_CRC("Trigger", 0x1a6b0f5d), isTrigger); + SetBoolValueOnComponent(editorShapeColliderComponent, AZ_CRC_CE("Trigger"), isTrigger); } bool GetBoolValueFromComponent(AZ::Component* component, AZ::Crc32 name) @@ -489,17 +489,17 @@ namespace PhysXEditorTests bool IsTrigger(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent) { - return GetBoolValueFromComponent(editorShapeColliderComponent, AZ_CRC("Trigger")); + return GetBoolValueFromComponent(editorShapeColliderComponent, AZ_CRC_CE("Trigger")); } void SetSingleSided(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent, bool singleSided) { - SetBoolValueOnComponent(editorShapeColliderComponent, AZ_CRC("SingleSided"), singleSided); + SetBoolValueOnComponent(editorShapeColliderComponent, AZ_CRC_CE("SingleSided"), singleSided); } bool IsSingleSided(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent) { - return GetBoolValueFromComponent(editorShapeColliderComponent, AZ_CRC("SingleSided")); + return GetBoolValueFromComponent(editorShapeColliderComponent, AZ_CRC_CE("SingleSided")); } EntityPtr CreateRigidBox(const AZ::Vector3& boxDimensions, const AZ::Vector3& position) @@ -636,7 +636,6 @@ namespace PhysXEditorTests EXPECT_NEAR(aabb.GetMin().GetY(), -0.6f, 1e-3f); EXPECT_NEAR(aabb.GetMax().GetX(), 2.7f, 1e-3f); EXPECT_NEAR(aabb.GetMax().GetY(), 0.6f, 1e-3f); - EXPECT_TRUE(true); } TEST_P(PhysXEditorParamBoolFixture, EditorShapeColliderComponent_TriggerSettingIsRememberedWhenSwitchingToQuadAndBack) @@ -731,9 +730,12 @@ namespace PhysXEditorTests EntityPtr gameQuadEntity = CreateActiveGameEntityFromEditorEntity(editorQuadEntity.get()); EntityPtr gameBoxEntity = CreateActiveGameEntityFromEditorEntity(editorBoxEntity.get()); - // give the box enough upward velocity to rise above the level of the quad and simulate + // give the box enough upward velocity to rise above the level of the quad + // simulate for enough time that the box would have reached the top of its trajectory and fallen back past the starting point if + // it hadn't collided with the top of the quad + const int numTimesteps = 100; Physics::RigidBodyRequestBus::Event(gameBoxEntity->GetId(), &Physics::RigidBodyRequests::SetLinearVelocity, AZ::Vector3::CreateAxisZ(6.0f)); - PhysX::TestUtils::UpdateScene(m_defaultScene, AzPhysics::SystemConfiguration::DefaultFixedTimestep, 200); + PhysX::TestUtils::UpdateScene(m_defaultScene, AzPhysics::SystemConfiguration::DefaultFixedTimestep, numTimesteps); // the box should travel through the base of the quad because it has no collision from that direction // and land on the top surface of the quad, which does have collision From 7b649656bc870de433e0d6a8db6eb63b230a6cc5 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 24 Jan 2022 07:30:39 -0800 Subject: [PATCH 102/136] chore: use numeric cast for QtEventTOAzInputMapperTest Signed-off-by: Michael Pollind --- .../Tests/Input/QtEventToAzInputMapperTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp b/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp index 78a08af6cb..8222a115f6 100644 --- a/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp +++ b/Code/Framework/AzToolsFramework/Tests/Input/QtEventToAzInputMapperTests.cpp @@ -562,7 +562,7 @@ namespace UnitTest AZ::Vector2 accumulatedPosition(0.0f,0.0f); for(const auto& pos: m_azCursorPositions) { - accumulatedPosition += (pos.m_normalizedPositionDelta * AZ::Vector2((float)WidgetSize.width(), (float)WidgetSize.height())); + accumulatedPosition += (pos.m_normalizedPositionDelta * AZ::Vector2(aznumeric_cast(WidgetSize.width()), aznumeric_cast(WidgetSize.height()))); } // validate From 37c0b661f94ffbde91364ff8536dc916dcc48c6c Mon Sep 17 00:00:00 2001 From: moraaar Date: Mon, 24 Jan 2022 15:49:33 +0000 Subject: [PATCH 103/136] Added blast asset, whose fbx works with Atom, to help testing Blast Gem (#7110) Signed-off-by: moraaar --- .../Destruction/cinder_wall_complex.blast | Bin 0 -> 330848 bytes .../Assets/Destruction/cinder_wall_complex.fbx | 3 +++ 2 files changed, 3 insertions(+) create mode 100644 AutomatedTesting/Assets/Destruction/cinder_wall_complex.blast create mode 100644 AutomatedTesting/Assets/Destruction/cinder_wall_complex.fbx diff --git a/AutomatedTesting/Assets/Destruction/cinder_wall_complex.blast b/AutomatedTesting/Assets/Destruction/cinder_wall_complex.blast new file mode 100644 index 0000000000000000000000000000000000000000..fcf67594c77c4fb51cc722d3d982a5b806a55fb4 GIT binary patch literal 330848 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⁡oo-r}+m3wDXFz&_Uv{b#sOK&*O#B9dC$e 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 literal 0 HcmV?d00001 diff --git a/AutomatedTesting/Assets/Destruction/cinder_wall_complex.fbx b/AutomatedTesting/Assets/Destruction/cinder_wall_complex.fbx new file mode 100644 index 0000000000..62c305c35e --- /dev/null +++ b/AutomatedTesting/Assets/Destruction/cinder_wall_complex.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7f94f2634eacb4d7bee20dacc45edef96e4d268f1adb7960b8aa8f3b6e2906ed +size 6867609 From c7d1c4603f80174b57ae217dbb801a3875d77499 Mon Sep 17 00:00:00 2001 From: mrieggeramzn <61609885+mrieggeramzn@users.noreply.github.com> Date: Mon, 24 Jan 2022 09:24:20 -0800 Subject: [PATCH 104/136] Removing lux core (whats left of it) (#7089) * Removing lux core (whats left of it) Signed-off-by: mrieggeramzn * Removing files recommended by NLawson and EPapp Signed-off-by: mrieggeramzn --- Gems/Atom/Feature/Common/Code/CMakeLists.txt | 1 - .../Common/Clang/atom_feature_common_clang.cmake | 7 ------- .../Common/GCC/atom_feature_common_gcc.cmake | 13 ------------- .../Common/MSVC/atom_feature_common_msvc.cmake | 7 ------- 4 files changed, 28 deletions(-) delete mode 100644 Gems/Atom/Feature/Common/Code/Source/Platform/Common/Clang/atom_feature_common_clang.cmake delete mode 100644 Gems/Atom/Feature/Common/Code/Source/Platform/Common/GCC/atom_feature_common_gcc.cmake delete mode 100644 Gems/Atom/Feature/Common/Code/Source/Platform/Common/MSVC/atom_feature_common_msvc.cmake diff --git a/Gems/Atom/Feature/Common/Code/CMakeLists.txt b/Gems/Atom/Feature/Common/Code/CMakeLists.txt index a832c46539..0d779cc3ea 100644 --- a/Gems/Atom/Feature/Common/Code/CMakeLists.txt +++ b/Gems/Atom/Feature/Common/Code/CMakeLists.txt @@ -18,7 +18,6 @@ ly_add_target( ${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake PLATFORM_INCLUDE_FILES ${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake - ${common_source_dir}/${PAL_TRAIT_COMPILER_ID}/atom_feature_common_${PAL_TRAIT_COMPILER_ID_LOWERCASE}.cmake INCLUDE_DIRECTORIES PRIVATE . diff --git a/Gems/Atom/Feature/Common/Code/Source/Platform/Common/Clang/atom_feature_common_clang.cmake b/Gems/Atom/Feature/Common/Code/Source/Platform/Common/Clang/atom_feature_common_clang.cmake deleted file mode 100644 index 7a325ca97e..0000000000 --- a/Gems/Atom/Feature/Common/Code/Source/Platform/Common/Clang/atom_feature_common_clang.cmake +++ /dev/null @@ -1,7 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. -# For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# diff --git a/Gems/Atom/Feature/Common/Code/Source/Platform/Common/GCC/atom_feature_common_gcc.cmake b/Gems/Atom/Feature/Common/Code/Source/Platform/Common/GCC/atom_feature_common_gcc.cmake deleted file mode 100644 index b3f7867308..0000000000 --- a/Gems/Atom/Feature/Common/Code/Source/Platform/Common/GCC/atom_feature_common_gcc.cmake +++ /dev/null @@ -1,13 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. -# For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -set_source_files_properties( - Source/LuxCore/LuxCoreRenderer.cpp - PROPERTIES - COMPILE_OPTIONS -fexceptions -) diff --git a/Gems/Atom/Feature/Common/Code/Source/Platform/Common/MSVC/atom_feature_common_msvc.cmake b/Gems/Atom/Feature/Common/Code/Source/Platform/Common/MSVC/atom_feature_common_msvc.cmake deleted file mode 100644 index 7a325ca97e..0000000000 --- a/Gems/Atom/Feature/Common/Code/Source/Platform/Common/MSVC/atom_feature_common_msvc.cmake +++ /dev/null @@ -1,7 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. -# For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# From 0d2204917e1d6ac6a3e598df041890666bec5312 Mon Sep 17 00:00:00 2001 From: Scott Romero <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 24 Jan 2022 09:49:13 -0800 Subject: [PATCH 105/136] [development] enabled mouse wheel scrolling in the Profiler gem visualizer (#6930) Resolves #6698 Signed-off-by: AMZN-ScottR 24445312+AMZN-ScottR@users.noreply.github.com --- Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp index 27397f05f7..3e071570bd 100644 --- a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp +++ b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp @@ -536,8 +536,7 @@ namespace Profiler ImGui::Columns(1, "TimelineColumn", true); // Timeline - if (ImGui::BeginChild( - "Timeline", { 0, 0 }, true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) + if (ImGui::BeginChild("Timeline", { 0, 0 }, true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) { // Find the next frame boundary after the viewport's right bound and draw until that tick auto nextFrameBoundaryItr = AZStd::lower_bound(m_frameEndTicks.begin(), m_frameEndTicks.end(), m_viewportEndTick); From 7bf7b03dd290af04e169ab6ea037e1f8b24d7962 Mon Sep 17 00:00:00 2001 From: SWMasterson Date: Mon, 24 Jan 2022 09:50:37 -0800 Subject: [PATCH 106/136] Added base level for tests, updated automation to use prefabs, and restored sandboxed tests (#6993) Signed-off-by: Sean Masterson --- .../Gem/PythonTests/Atom/TestSuite_Main.py | 10 +++- .../Gem/PythonTests/Atom/TestSuite_Sandbox.py | 10 ---- ...ntsLevel_DiffuseGlobalIlluminationAdded.py | 6 +-- ...ditorComponentsLevel_DisplayMapperAdded.py | 4 +- .../hydra_AtomEditorComponents_BloomAdded.py | 4 +- .../hydra_AtomEditorComponents_DecalAdded.py | 3 +- ...a_AtomEditorComponents_DeferredFogAdded.py | 4 +- ..._AtomEditorComponents_DepthOfFieldAdded.py | 4 +- ...mEditorComponents_DiffuseProbeGridAdded.py | 4 +- ...mEditorComponents_DirectionalLightAdded.py | 4 +- ...AtomEditorComponents_DisplayMapperAdded.py | 4 +- ...omEditorComponents_EntityReferenceAdded.py | 4 +- ...omEditorComponents_ExposureControlAdded.py | 4 +- ...EditorComponents_GlobalSkylightIBLAdded.py | 4 +- .../hydra_AtomEditorComponents_GridAdded.py | 4 +- ...omEditorComponents_HDRColorGradingAdded.py | 4 +- ...ra_AtomEditorComponents_HDRiSkyboxAdded.py | 4 +- .../hydra_AtomEditorComponents_LightAdded.py | 4 +- ...mEditorComponents_LookModificationAdded.py | 4 +- ...ydra_AtomEditorComponents_MaterialAdded.py | 4 +- .../hydra_AtomEditorComponents_MeshAdded.py | 4 +- ...orComponents_OcclusionCullingPlaneAdded.py | 4 +- ...a_AtomEditorComponents_PhysicalSkyAdded.py | 4 +- ...nents_PostFXGradientWeightModifierAdded.py | 4 +- ...a_AtomEditorComponents_PostFXLayerAdded.py | 4 +- ...ponents_PostFXRadiusWeightModifierAdded.py | 4 +- ...mponents_PostFxShapeWeightModifierAdded.py | 4 +- ...omEditorComponents_ReflectionProbeAdded.py | 4 +- .../hydra_AtomEditorComponents_SSAOAdded.py | 4 +- .../Graphics/base_empty/base_empty.prefab | 53 +++++++++++++++++++ .../Levels/Graphics/base_empty/tags.txt | 12 +++++ 31 files changed, 153 insertions(+), 41 deletions(-) create mode 100644 AutomatedTesting/Levels/Graphics/base_empty/base_empty.prefab create mode 100644 AutomatedTesting/Levels/Graphics/base_empty/tags.txt diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py index f1e66ac492..cca20bbf8c 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py @@ -21,7 +21,7 @@ TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests") @pytest.mark.parametrize("launcher_platform", ['windows_editor']) class TestAutomation(EditorTestSuite): - enable_prefab_system = False + enable_prefab_system = True @pytest.mark.test_case_id("C36525657") class AtomEditorComponents_BloomAdded(EditorSharedTest): @@ -120,6 +120,14 @@ class TestAutomation(EditorTestSuite): class AtomEditorComponents_SSAOAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_SSAOAdded as test_module + @pytest.mark.test_case_id("C36529666") + class AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded as test_module + + @pytest.mark.test_case_id("C36525660") + class AtomEditorComponentsLevel_DisplayMapperAdded(EditorSharedTest): + from Atom.tests import hydra_AtomEditorComponentsLevel_DisplayMapperAdded as test_module + class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest): from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py index bd0477a1db..5299e55a2b 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Sandbox.py @@ -26,13 +26,3 @@ class TestAutomation(EditorTestSuite): @pytest.mark.test_case_id("C36525660") class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module - - # this test causes editor to crash when using slices. once automation transitions to prefabs it should pass - @pytest.mark.test_case_id("C36529666") - class AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded as test_module - - # this test causes editor to crash when using slices. once automation transitions to prefabs it should pass - @pytest.mark.test_case_id("C36525660") - class AtomEditorComponentsLevel_DisplayMapperAdded(EditorSharedTest): - from Atom.tests import hydra_AtomEditorComponentsLevel_DisplayMapperAdded as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded.py index ddcd5c3c46..0c9b39e354 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded.py @@ -60,7 +60,7 @@ def AtomEditorComponentsLevel_DiffuseGlobalIllumination_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Add Diffuse Global Illumination level component to the level entity. @@ -86,10 +86,10 @@ def AtomEditorComponentsLevel_DiffuseGlobalIllumination_AddedToEntity(): # 4. Set Quality Level property to Low diffuse_global_illumination_component.set_component_property_value( - AtomComponentProperties.diffuse_global_illumination('Quality Level', GLOBAL_ILLUMINATION_QUALITY['Low'])) + AtomComponentProperties.diffuse_global_illumination('Quality Level'), GLOBAL_ILLUMINATION_QUALITY['Low']) quality = diffuse_global_illumination_component.get_component_property_value( AtomComponentProperties.diffuse_global_illumination('Quality Level')) - Report.result(diffuse_global_illumination_quality, quality == GLOBAL_ILLUMINATION_QUALITY['Low']) + Report.result(Tests.diffuse_global_illumination_quality, quality == GLOBAL_ILLUMINATION_QUALITY['Low']) # 5. Enter/Exit game mode. TestHelper.enter_game_mode(Tests.enter_game_mode) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DisplayMapperAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DisplayMapperAdded.py index c050dd76d4..f9660957bb 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DisplayMapperAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponentsLevel_DisplayMapperAdded.py @@ -67,7 +67,7 @@ def AtomEditorComponentsLevel_DisplayMapper_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Add Display Mapper level component to the level entity. @@ -102,7 +102,7 @@ def AtomEditorComponentsLevel_DisplayMapper_AddedToEntity(): display_mapper_component.set_component_property_value( AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True) Report.result( - Test.enable_ldr_color_grading_lut, + Tests.enable_ldr_color_grading_lut, display_mapper_component.get_component_property_value( AtomComponentProperties.display_mapper('Enable LDR color grading LUT')) is True) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py index 56b22eb20d..ce29a1de88 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_BloomAdded.py @@ -97,7 +97,7 @@ def AtomEditorComponents_Bloom_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create an Bloom entity with no components. @@ -170,10 +170,12 @@ def AtomEditorComponents_Bloom_AddedToEntity(): # 13. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, bloom_entity.exists()) # 14. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not bloom_entity.exists()) # 15. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DecalAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DecalAdded.py index e840cf3cf1..eb5e24e3a6 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DecalAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DecalAdded.py @@ -95,7 +95,7 @@ def AtomEditorComponents_Decal_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Decal entity with no components. @@ -162,6 +162,7 @@ def AtomEditorComponents_Decal_AddedToEntity(): # 11. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not decal_entity.exists()) # 12. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DeferredFogAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DeferredFogAdded.py index 71163ece94..f1578cbf8d 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DeferredFogAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DeferredFogAdded.py @@ -97,7 +97,7 @@ def AtomEditorComponents_DeferredFog_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create an Deferred Fog entity with no components. @@ -174,10 +174,12 @@ def AtomEditorComponents_DeferredFog_AddedToEntity(): # 13. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, deferred_fog_entity.exists()) # 14. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not deferred_fog_entity.exists()) # 15. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DepthOfFieldAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DepthOfFieldAdded.py index e2c5f9c77d..3913420981 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DepthOfFieldAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DepthOfFieldAdded.py @@ -107,7 +107,7 @@ def AtomEditorComponents_DepthOfField_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a DepthOfField entity with no components. @@ -189,10 +189,12 @@ def AtomEditorComponents_DepthOfField_AddedToEntity(): # 15. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, depth_of_field_entity.exists()) # 16. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not depth_of_field_entity.exists()) # 17. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DiffuseProbeGridAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DiffuseProbeGridAdded.py index f42c091057..04b4f7876b 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DiffuseProbeGridAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DiffuseProbeGridAdded.py @@ -90,7 +90,7 @@ def AtomEditorComponents_DiffuseProbeGrid_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Diffuse Probe Grid entity with no components. @@ -168,10 +168,12 @@ def AtomEditorComponents_DiffuseProbeGrid_AddedToEntity(): # 12. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, diffuse_probe_grid_entity.exists()) # 13. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not diffuse_probe_grid_entity.exists()) # 14. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DirectionalLightAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DirectionalLightAdded.py index f3ffc0f366..19cfbedcd5 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DirectionalLightAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DirectionalLightAdded.py @@ -95,7 +95,7 @@ def AtomEditorComponents_DirectionalLight_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Directional Light entity with no components. @@ -168,10 +168,12 @@ def AtomEditorComponents_DirectionalLight_AddedToEntity(): # 12. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, directional_light_entity.exists()) # 13. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not directional_light_entity.exists()) # 14. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py index 558d69046e..d3ea669eab 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_DisplayMapperAdded.py @@ -91,7 +91,7 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Display Mapper entity with no components. @@ -166,10 +166,12 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity(): # 11. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, display_mapper_entity.exists()) # 12. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not display_mapper_entity.exists()) # 13. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py index dddcca64fa..ec402f0f5f 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_EntityReferenceAdded.py @@ -81,7 +81,7 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create an Entity Reference entity with no components. @@ -139,10 +139,12 @@ def AtomEditorComponents_EntityReference_AddedToEntity(): # 9. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, entity_reference_entity.exists()) # 10. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not entity_reference_entity.exists()) # 11. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ExposureControlAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ExposureControlAdded.py index 6fa9660539..f60f0e18be 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ExposureControlAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ExposureControlAdded.py @@ -101,7 +101,7 @@ def AtomEditorComponents_ExposureControl_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Creation of Exposure Control entity with no components. @@ -169,10 +169,12 @@ def AtomEditorComponents_ExposureControl_AddedToEntity(): # 12. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, exposure_control_entity.exists()) # 13. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not exposure_control_entity.exists()) # 14. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GlobalSkylightIBLAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GlobalSkylightIBLAdded.py index 7f0c38e289..0e8e6fa43e 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GlobalSkylightIBLAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GlobalSkylightIBLAdded.py @@ -99,7 +99,7 @@ def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Global Skylight (IBL) entity with no components. @@ -176,10 +176,12 @@ def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity(): # 11. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, global_skylight_entity.exists()) # 12. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not global_skylight_entity.exists()) # 13. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GridAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GridAdded.py index a77a1f50a4..3c6d261f22 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GridAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_GridAdded.py @@ -82,7 +82,7 @@ def AtomEditorComponents_Grid_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Grid entity with no components. @@ -139,10 +139,12 @@ def AtomEditorComponents_Grid_AddedToEntity(): # 9. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, grid_entity.exists()) # 10. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not grid_entity.exists()) # 11. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRColorGradingAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRColorGradingAdded.py index 4972079fcd..5846206e50 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRColorGradingAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRColorGradingAdded.py @@ -96,7 +96,7 @@ def AtomEditorComponents_HDRColorGrading_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create an HDR Color Grading entity with no components. @@ -173,10 +173,12 @@ def AtomEditorComponents_HDRColorGrading_AddedToEntity(): # 13. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, hdr_color_grading_entity.exists()) # 14. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not hdr_color_grading_entity.exists()) # 15. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRiSkyboxAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRiSkyboxAdded.py index 0f96bc5424..fc093b60db 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRiSkyboxAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_HDRiSkyboxAdded.py @@ -87,7 +87,7 @@ def AtomEditorComponents_HDRiSkybox_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create an HDRi Skybox with no components. @@ -158,10 +158,12 @@ def AtomEditorComponents_HDRiSkybox_AddedToEntity(): # 10. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, hdri_skybox_entity.exists()) # 11. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not hdri_skybox_entity.exists()) # 12. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py index 249671556d..75a04612a3 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightAdded.py @@ -89,7 +89,7 @@ def AtomEditorComponents_Light_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Light entity with no components. @@ -144,10 +144,12 @@ def AtomEditorComponents_Light_AddedToEntity(): # 9. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, light_entity.exists()) # 10. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not light_entity.exists()) # 11. Look for errors asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LookModificationAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LookModificationAdded.py index afb8033426..149af73151 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LookModificationAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LookModificationAdded.py @@ -104,7 +104,7 @@ def AtomEditorComponents_LookModification_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create an Look Modification entity with no components. @@ -192,10 +192,12 @@ def AtomEditorComponents_LookModification_AddedToEntity(): # 14. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, look_modification_entity.exists()) # 15. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not look_modification_entity.exists()) # 16. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py index c613bb23e7..919a6753f4 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MaterialAdded.py @@ -102,7 +102,7 @@ def AtomEditorComponents_Material_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Material entity with no components. @@ -184,10 +184,12 @@ def AtomEditorComponents_Material_AddedToEntity(): # 16. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, material_entity.exists()) # 17. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not material_entity.exists()) # 18. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py index 9d56753961..a87ee75b53 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_MeshAdded.py @@ -87,7 +87,7 @@ def AtomEditorComponents_Mesh_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Mesh entity with no components. @@ -151,10 +151,12 @@ def AtomEditorComponents_Mesh_AddedToEntity(): # 10. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, mesh_entity.exists()) # 11. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not mesh_entity.exists()) # 12. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py index 4226ae3dfe..56bb5eb68c 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_OcclusionCullingPlaneAdded.py @@ -80,7 +80,7 @@ def AtomEditorComponents_OcclusionCullingPlane_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a occlusion culling plane entity with no components. @@ -140,10 +140,12 @@ def AtomEditorComponents_OcclusionCullingPlane_AddedToEntity(): # 9. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, occlusion_culling_plane_entity.exists()) # 10. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not occlusion_culling_plane_entity.exists()) # 11. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py index fa8c626016..e0c558811e 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PhysicalSkyAdded.py @@ -89,7 +89,7 @@ def AtomEditorComponents_PhysicalSky_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Physical Sky entity with no components. @@ -146,10 +146,12 @@ def AtomEditorComponents_PhysicalSky_AddedToEntity(): # 9. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, physical_sky_entity.exists()) # 10. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not physical_sky_entity.exists()) # 11. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py index 6e4ae2d9ac..b36267433f 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXGradientWeightModifierAdded.py @@ -92,7 +92,7 @@ def AtomEditorComponents_PostFXGradientWeightModifier_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a PostFX Gradient Weight Modifier entity with no components. @@ -162,10 +162,12 @@ def AtomEditorComponents_PostFXGradientWeightModifier_AddedToEntity(): # 12. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, postfx_gradient_weight_entity.exists()) # 13. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not postfx_gradient_weight_entity.exists()) # 14. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py index efef4c0a43..07fffb9bde 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXLayerAdded.py @@ -80,7 +80,7 @@ def AtomEditorComponents_postfx_layer_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a PostFX Layer entity with no components. @@ -137,10 +137,12 @@ def AtomEditorComponents_postfx_layer_AddedToEntity(): # 9. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, postfx_layer_entity.exists()) # 10. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not postfx_layer_entity.exists()) # 11. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded.py index 228ddfcdc5..616233d2d2 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded.py @@ -92,7 +92,7 @@ def AtomEditorComponents_PostFXRadiusWeightModifier_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Post FX Radius Weight Modifier entity with no components. @@ -161,10 +161,12 @@ def AtomEditorComponents_PostFXRadiusWeightModifier_AddedToEntity(): # 12. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, postfx_radius_weight_entity.exists()) # 13. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not postfx_radius_weight_entity.exists()) # 14. Look for errors and asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py index 0a37ac6bf7..5f7d571a18 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_PostFxShapeWeightModifierAdded.py @@ -98,7 +98,7 @@ def AtomEditorComponents_postfx_shape_weight_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a PostFx Shape Weight Modifier entity with no components. @@ -188,10 +188,12 @@ def AtomEditorComponents_postfx_shape_weight_AddedToEntity(): # 15. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, postfx_shape_weight_entity.exists()) # 16. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not postfx_shape_weight_entity.exists()) # 17. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ReflectionProbeAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ReflectionProbeAdded.py index 70adf9143a..85156b4db6 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ReflectionProbeAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_ReflectionProbeAdded.py @@ -97,7 +97,7 @@ def AtomEditorComponents_ReflectionProbe_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a Reflection Probe entity with no components. @@ -183,10 +183,12 @@ def AtomEditorComponents_ReflectionProbe_AddedToEntity(): # 13. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, reflection_probe_entity.exists()) # 14. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not reflection_probe_entity.exists()) # 15. Look for errors or asserts. diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_SSAOAdded.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_SSAOAdded.py index 15f40f8b70..09f77c4a9f 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_SSAOAdded.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_SSAOAdded.py @@ -94,7 +94,7 @@ def AtomEditorComponents_SSAO_AddedToEntity(): # Test setup begins. # Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level. TestHelper.init_idle() - TestHelper.open_level("", "Base") + TestHelper.open_level("Graphics", "base_empty") # Test steps begin. # 1. Create a SSAO entity with no components. @@ -163,10 +163,12 @@ def AtomEditorComponents_SSAO_AddedToEntity(): # 12. UNDO deletion. general.undo() + general.idle_wait_frames(1) Report.result(Tests.deletion_undo, ssao_entity.exists()) # 13. REDO deletion. general.redo() + general.idle_wait_frames(1) Report.result(Tests.deletion_redo, not ssao_entity.exists()) # 14. Look for errors and asserts. diff --git a/AutomatedTesting/Levels/Graphics/base_empty/base_empty.prefab b/AutomatedTesting/Levels/Graphics/base_empty/base_empty.prefab new file mode 100644 index 0000000000..f7e42e7731 --- /dev/null +++ b/AutomatedTesting/Levels/Graphics/base_empty/base_empty.prefab @@ -0,0 +1,53 @@ +{ + "ContainerEntity": { + "Id": "Entity_[1146574390643]", + "Name": "Level", + "Components": { + "Component_[10641544592923449938]": { + "$type": "EditorInspectorComponent", + "Id": 10641544592923449938 + }, + "Component_[12039882709170782873]": { + "$type": "EditorOnlyEntityComponent", + "Id": 12039882709170782873 + }, + "Component_[12265484671603697631]": { + "$type": "EditorPendingCompositionComponent", + "Id": 12265484671603697631 + }, + "Component_[14126657869720434043]": { + "$type": "EditorEntitySortComponent", + "Id": 14126657869720434043 + }, + "Component_[15230859088967841193]": { + "$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent", + "Id": 15230859088967841193, + "Parent Entity": "" + }, + "Component_[16239496886950819870]": { + "$type": "EditorDisabledCompositionComponent", + "Id": 16239496886950819870 + }, + "Component_[5688118765544765547]": { + "$type": "EditorEntityIconComponent", + "Id": 5688118765544765547 + }, + "Component_[6545738857812235305]": { + "$type": "SelectionComponent", + "Id": 6545738857812235305 + }, + "Component_[7247035804068349658]": { + "$type": "EditorPrefabComponent", + "Id": 7247035804068349658 + }, + "Component_[9307224322037797205]": { + "$type": "EditorLockComponent", + "Id": 9307224322037797205 + }, + "Component_[9562516168917670048]": { + "$type": "EditorVisibilityComponent", + "Id": 9562516168917670048 + } + } + } +} \ No newline at end of file diff --git a/AutomatedTesting/Levels/Graphics/base_empty/tags.txt b/AutomatedTesting/Levels/Graphics/base_empty/tags.txt new file mode 100644 index 0000000000..0d6c1880e7 --- /dev/null +++ b/AutomatedTesting/Levels/Graphics/base_empty/tags.txt @@ -0,0 +1,12 @@ +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 +0,0,0,0,0,0 From 2b7b975a88ecd90a59376d94aae3c0ad37020ac2 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Mon, 24 Jan 2022 12:38:29 -0600 Subject: [PATCH 107/136] Fixed missing include compile issue Signed-off-by: Chris Galvan --- Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp b/Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp index cf042dc4ac..0640271c37 100644 --- a/Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp +++ b/Gems/AudioEngineWwise/Code/Source/Engine/FileIOHandler_wwise.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include From 1cf7d57b3fffa89367218cc3a82cc6172e4fdd8a Mon Sep 17 00:00:00 2001 From: Junbo Liang <68558268+junbo75@users.noreply.github.com> Date: Mon, 24 Jan 2022 11:20:15 -0800 Subject: [PATCH 108/136] Update deployment scripts to support AWSI automation tests on Linux (#7038) * Update deployment scripts to support AWSI automation tests on Linux Signed-off-by: Junbo Liang <68558268+junbo75@users.noreply.github.com> --- .../Gem/PythonTests/AWS/CMakeLists.txt | 6 ------ AutomatedTesting/Gem/PythonTests/AWS/README.md | 2 +- .../PythonTests/AWS/common/aws_credentials.py | 4 ++++ .../Gem/PythonTests/AWS/common/aws_utils.py | 2 +- .../Gem/PythonTests/AWS/common/constants.py | 4 +++- scripts/build/Platform/Linux/build_config.json | 4 ++-- .../Platform/Linux/deploy_cdk_applications.sh | 17 ++++++++++------- .../Platform/Linux/destroy_cdk_applications.sh | 16 ++++++++++------ scripts/build/Platform/Linux/pipeline.json | 14 -------------- .../Windows/deploy_cdk_applications.cmd | 4 ++++ .../Windows/destroy_cdk_applications.cmd | 3 +++ scripts/build/Platform/Windows/pipeline.json | 14 -------------- 12 files changed, 38 insertions(+), 52 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/AWS/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/AWS/CMakeLists.txt index c8629bbe8b..10e90ecbfc 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/AWS/CMakeLists.txt @@ -12,12 +12,6 @@ ################################################################################ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) - # Only enable AWS automated tests on Windows - set(SUPPORTED_PLATFORMS "Windows" "Linux") - if (NOT "${PAL_PLATFORM_NAME}" IN_LIST SUPPORTED_PLATFORMS) - return() - endif() - ly_add_pytest( NAME AutomatedTesting::AWSTests TEST_SUITE awsi diff --git a/AutomatedTesting/Gem/PythonTests/AWS/README.md b/AutomatedTesting/Gem/PythonTests/AWS/README.md index a25f39d9c2..73ef685261 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/README.md +++ b/AutomatedTesting/Gem/PythonTests/AWS/README.md @@ -3,7 +3,7 @@ ## Prerequisites 1. Build the O3DE Editor and AutomatedTesting.GameLauncher in Profile. 2. Install the latest version of NodeJs. -3. AWS CLI is installed and configured following [Configuration and Credential File Settings](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html). +3. AWS CLI is installed and AWS crendentials are configured via [environment variables](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html) or [default profile](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html). 4. [AWS Cloud Development Kit (CDK)](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html#getting_started_install) is installed. ## Deploy CDK Applications diff --git a/AutomatedTesting/Gem/PythonTests/AWS/common/aws_credentials.py b/AutomatedTesting/Gem/PythonTests/AWS/common/aws_credentials.py index c6401f2828..d0bbfe7c3e 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/common/aws_credentials.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/common/aws_credentials.py @@ -68,6 +68,10 @@ class AwsCredentials: if (len(self._credentials.sections()) == 0) and (not self._credentials_file_exists): os.remove(self._credentials_path) return + + credentials_file_dir = os.path.dirname(self._credentials_path) + if not os.path.isdir(credentials_file_dir): + os.makedirs(credentials_file_dir) with open(self._credentials_path, 'w+') as credential_file: self._credentials.write(credential_file) diff --git a/AutomatedTesting/Gem/PythonTests/AWS/common/aws_utils.py b/AutomatedTesting/Gem/PythonTests/AWS/common/aws_utils.py index 92f3762e71..2a5efbd03f 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/common/aws_utils.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/common/aws_utils.py @@ -16,7 +16,7 @@ logging.getLogger('nose').setLevel(logging.WARNING) class AwsUtils: def __init__(self, arn: str, session_name: str, region_name: str): - local_session = boto3.Session(profile_name='default') + local_session = boto3.Session() local_sts_client = local_session.client('sts') self._local_account_id = local_sts_client.get_caller_identity()["Account"] logger.info(f'Local Account Id: {self._local_account_id}') diff --git a/AutomatedTesting/Gem/PythonTests/AWS/common/constants.py b/AutomatedTesting/Gem/PythonTests/AWS/common/constants.py index b12aca5f29..a38974073a 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/common/constants.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/common/constants.py @@ -6,11 +6,13 @@ SPDX-License-Identifier: Apache-2.0 OR MIT """ import os +import platform # ARN of the IAM role to assume for retrieving temporary AWS credentials ASSUME_ROLE_ARN = os.environ.get('ASSUME_ROLE_ARN', 'arn:aws:iam::645075835648:role/o3de-automation-tests') # Name of the AWS project deployed by the CDK applications -AWS_PROJECT_NAME = os.environ.get('O3DE_AWS_PROJECT_NAME', 'AWSAUTO') +AWS_PROJECT_NAME = os.environ.get('O3DE_AWS_PROJECT_NAME').upper() if os.environ.get('O3DE_AWS_PROJECT_NAME') else \ + (os.environ.get('BRANCH_NAME', '') + '-' + os.environ.get('PIPELINE_NAME', '') + '-' + platform.system()).upper() # Region for the existing CloudFormation stacks used by the automation tests AWS_REGION = os.environ.get('O3DE_AWS_DEPLOY_REGION', 'us-east-1') # Name of the default resource mapping config file used by the automation tests diff --git a/scripts/build/Platform/Linux/build_config.json b/scripts/build/Platform/Linux/build_config.json index f61f91169a..c8f8752609 100644 --- a/scripts/build/Platform/Linux/build_config.json +++ b/scripts/build/Platform/Linux/build_config.json @@ -185,11 +185,11 @@ "COMMAND": "build_test_linux.sh", "PARAMETERS": { "CONFIGURATION": "profile", - "OUTPUT_DIRECTORY": "build\\linux", + "OUTPUT_DIRECTORY": "build/linux", "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DLY_PARALLEL_LINK_JOBS=4", "CMAKE_LY_PROJECTS": "AutomatedTesting", "CMAKE_TARGET": "TEST_SUITE_awsi", - "CTEST_OPTIONS": "-L \"(SUITE_awsi)\" --no-tests=error", + "CTEST_OPTIONS": "-L (SUITE_awsi) --no-tests=error", "TEST_RESULTS": "True" } }, diff --git a/scripts/build/Platform/Linux/deploy_cdk_applications.sh b/scripts/build/Platform/Linux/deploy_cdk_applications.sh index 9a0a31397e..cccc796bdb 100755 --- a/scripts/build/Platform/Linux/deploy_cdk_applications.sh +++ b/scripts/build/Platform/Linux/deploy_cdk_applications.sh @@ -1,5 +1,5 @@ -#!/bin/bash - +#!/usr/bin/env bash +# # Copyright (c) Contributors to the Open 3D Engine Project. # For complete copyright and license terms please see the LICENSE at the root of this distribution. # @@ -8,7 +8,7 @@ # Deploy the CDK applications for AWS gems (Linux only) -SOURCE_DIRECTORY=$(dirname "$0") +SOURCE_DIRECTORY=$PWD PATH=$SOURCE_DIRECTORY/python:$PATH GEM_DIRECTORY=$SOURCE_DIRECTORY/Gems @@ -80,11 +80,14 @@ fi # Set temporary AWS credentials from the assume role credentials=$(aws sts assume-role --query Credentials.[SecretAccessKey,SessionToken,AccessKeyId] --output text --role-arn $ASSUME_ROLE_ARN --role-session-name o3de-Automation-session) -AWS_SECRET_ACCESS_KEY=$(echo "$credentials" | cut -d' ' -f1) -AWS_SESSION_TOKEN=$(echo "$credentials" | cut -d' ' -f2) -AWS_ACCESS_KEY_ID=$(echo "$credentials" | cut -d' ' -f3) +export AWS_SECRET_ACCESS_KEY=$(echo $credentials | cut -d' ' -f1) +export AWS_SESSION_TOKEN=$(echo $credentials | cut -d' ' -f2) +export AWS_ACCESS_KEY_ID=$(echo $credentials | cut -d' ' -f3) -O3DE_AWS_DEPLOY_ACCOUNT=$(echo "$ASSUME_ROLE_ARN" | cut -d':' -f5) +export O3DE_AWS_DEPLOY_ACCOUNT=$(echo "$ASSUME_ROLE_ARN" | cut -d':' -f5) +if [[ -z "$O3DE_AWS_PROJECT_NAME" ]]; then + export O3DE_AWS_PROJECT_NAME=$BRANCH_NAME-$PIPELINE_NAME-Linux +fi # Bootstrap and deploy the CDK applications echo [cdk_bootstrap] Bootstrap CDK diff --git a/scripts/build/Platform/Linux/destroy_cdk_applications.sh b/scripts/build/Platform/Linux/destroy_cdk_applications.sh index 54f84911a6..fd91e1a786 100755 --- a/scripts/build/Platform/Linux/destroy_cdk_applications.sh +++ b/scripts/build/Platform/Linux/destroy_cdk_applications.sh @@ -11,7 +11,7 @@ # 1) Node.js is installed # 2) Node.js version >= 10.13.0, except for versions 13.0.0 - 13.6.0. A version in active long-term support is recommended. -SOURCE_DIRECTORY=$(dirname "$0") +SOURCE_DIRECTORY=$PWD PATH=$SOURCE_DIRECTORY/python:$PATH GEM_DIRECTORY=$SOURCE_DIRECTORY/Gems @@ -70,12 +70,12 @@ echo [cdk_installation] Install the current version of nodejs nvm install node echo [cdk_installation] Install the latest version of CDK -if ! sudo npm uninstall -g aws-cdk; +if ! npm uninstall -g aws-cdk; then echo [cdk_bootstrap] Failed to uninstall the current version of CDK exit 1 fi -if ! sudo npm install -g aws-cdk@latest; +if ! npm install -g aws-cdk@latest; then echo [cdk_bootstrap] Failed to install the latest version of CDK exit 1 @@ -83,9 +83,13 @@ fi # Set temporary AWS credentials from the assume role credentials=$(aws sts assume-role --query Credentials.[SecretAccessKey,SessionToken,AccessKeyId] --output text --role-arn $ASSUME_ROLE_ARN --role-session-name o3de-Automation-session) -AWS_SECRET_ACCESS_KEY=$(echo "$credentials" | cut -d' ' -f1) -AWS_SESSION_TOKEN=$(echo "$credentials" | cut -d' ' -f2) -AWS_ACCESS_KEY_ID=$(echo "$credentials" | cut -d' ' -f3) +export AWS_SECRET_ACCESS_KEY=$(echo $credentials | cut -d' ' -f1) +export AWS_SESSION_TOKEN=$(echo $credentials | cut -d' ' -f2) +export AWS_ACCESS_KEY_ID=$(echo $credentials | cut -d' ' -f3) + +if [[ -z "$O3DE_AWS_PROJECT_NAME" ]]; then + export O3DE_AWS_PROJECT_NAME=$BRANCH_NAME-$PIPELINE_NAME-Linux +fi ERROR_EXISTS=0 DestroyCDKApplication AWSCore diff --git a/scripts/build/Platform/Linux/pipeline.json b/scripts/build/Platform/Linux/pipeline.json index e9667d312d..605adf1837 100644 --- a/scripts/build/Platform/Linux/pipeline.json +++ b/scripts/build/Platform/Linux/pipeline.json @@ -16,13 +16,6 @@ }, "PIPELINE_JENKINS_PARAMETERS": { "nightly-incremental": [ - { - "parameter_name": "O3DE_AWS_PROJECT_NAME", - "parameter_type": "string", - "default_value": "", - "use_last_run_value": true, - "description": "The name of the O3DE project that stacks should be deployed for." - }, { "parameter_name": "O3DE_AWS_DEPLOY_REGION", "parameter_type": "string", @@ -46,13 +39,6 @@ } ], "nightly-clean": [ - { - "parameter_name": "O3DE_AWS_PROJECT_NAME", - "parameter_type": "string", - "default_value": "", - "use_last_run_value": true, - "description": "The name of the O3DE project that stacks should be deployed for." - }, { "parameter_name": "O3DE_AWS_DEPLOY_REGION", "parameter_type": "string", diff --git a/scripts/build/Platform/Windows/deploy_cdk_applications.cmd b/scripts/build/Platform/Windows/deploy_cdk_applications.cmd index f3d68d2fe8..fca0835bd8 100644 --- a/scripts/build/Platform/Windows/deploy_cdk_applications.cmd +++ b/scripts/build/Platform/Windows/deploy_cdk_applications.cmd @@ -49,6 +49,10 @@ FOR /f "tokens=1,2,3" %%a IN ('CALL aws sts assume-role --query Credentials.[Sec ) FOR /F "tokens=4 delims=:" %%a IN ("%ASSUME_ROLE_ARN%") DO SET O3DE_AWS_DEPLOY_ACCOUNT=%%a +IF "%O3DE_AWS_PROJECT_NAME%"=="" ( + SET O3DE_AWS_PROJECT_NAME=%BRANCH_NAME%-%PIPELINE_NAME%-Windows +) + REM Bootstrap and deploy the CDK applications ECHO [cdk_bootstrap] Bootstrap CDK CALL cdk bootstrap aws://%O3DE_AWS_DEPLOY_ACCOUNT%/%O3DE_AWS_DEPLOY_REGION% diff --git a/scripts/build/Platform/Windows/destroy_cdk_applications.cmd b/scripts/build/Platform/Windows/destroy_cdk_applications.cmd index dacc9d327a..fe57619ff9 100644 --- a/scripts/build/Platform/Windows/destroy_cdk_applications.cmd +++ b/scripts/build/Platform/Windows/destroy_cdk_applications.cmd @@ -48,6 +48,9 @@ FOR /f "tokens=1,2,3" %%a IN ('CALL aws sts assume-role --query Credentials.[Sec SET AWS_ACCESS_KEY_ID=%%c ) FOR /F "tokens=4 delims=:" %%a IN ("%ASSUME_ROLE_ARN%") DO SET O3DE_AWS_DEPLOY_ACCOUNT=%%a +IF "%O3DE_AWS_PROJECT_NAME%"=="" ( + SET O3DE_AWS_PROJECT_NAME=%BRANCH_NAME%-%PIPELINE_NAME%-Windows +) SET ERROR_EXISTS=0 CALL :DestroyCDKApplication AWSCore,ERROR_EXISTS diff --git a/scripts/build/Platform/Windows/pipeline.json b/scripts/build/Platform/Windows/pipeline.json index 28d8437408..47e6af2d10 100644 --- a/scripts/build/Platform/Windows/pipeline.json +++ b/scripts/build/Platform/Windows/pipeline.json @@ -16,13 +16,6 @@ }, "PIPELINE_JENKINS_PARAMETERS": { "nightly-incremental": [ - { - "parameter_name": "O3DE_AWS_PROJECT_NAME", - "parameter_type": "string", - "default_value": "", - "use_last_run_value": true, - "description": "The name of the O3DE project that stacks should be deployed for." - }, { "parameter_name": "O3DE_AWS_DEPLOY_REGION", "parameter_type": "string", @@ -46,13 +39,6 @@ } ], "nightly-clean": [ - { - "parameter_name": "O3DE_AWS_PROJECT_NAME", - "parameter_type": "string", - "default_value": "", - "use_last_run_value": true, - "description": "The name of the O3DE project that stacks should be deployed for." - }, { "parameter_name": "O3DE_AWS_DEPLOY_REGION", "parameter_type": "string", From b1caed0f8ea5cf8ed14b6daf0d65c1cf7eea2dae Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Mon, 24 Jan 2022 11:22:50 -0800 Subject: [PATCH 109/136] Introduce shortcut labeling in "Find in Viewport" context menu item in the Outliner (#7095) Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp index c499d0f92f..31bb067603 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp @@ -890,6 +890,7 @@ namespace AzToolsFramework m_actionGoToEntitiesInViewport = new QAction(tr("Find in viewport"), this); m_actionGoToEntitiesInViewport->setShortcutContext(Qt::WidgetWithChildrenShortcut); + m_actionGoToEntitiesInViewport->setShortcut(tr("Z")); connect(m_actionGoToEntitiesInViewport, &QAction::triggered, this, &EntityOutlinerWidget::GoToEntitiesInViewport); addAction(m_actionGoToEntitiesInViewport); } From f34d3a822e06ac1a12b42a18cb5b18afa15eabf2 Mon Sep 17 00:00:00 2001 From: bosnichd Date: Mon, 24 Jan 2022 13:47:44 -0700 Subject: [PATCH 110/136] Add a ray cast API to the terrain system, implement it, and use it so entities can be placed on top of terrain. (#6895) * Add a ray cast API to the terrain system, implement it, and use it so entities can be placed on top of terrain. Still to do: - Unit tests - Profiling/benchmarks - Optimization (if needed, may not be now after updating to use the iterative approach, but one option could be to use SIMD to ray cast against both triangles at once) Signed-off-by: bosnichd * Fix typos. Signed-off-by: bosnichd * Added a FindNearestIntersectionIterative to use in place of the first-pass FindnearestIntersectionRecursive attempt. Signed-off-by: bosnichd * Remove some functions that are no longer being used. Signed-off-by: bosnichd * Remove a unicode character from a comment to fix the validation build. Signed-off-by: bosnichd * Remove another unicode character from a comment to fix the validation build. Signed-off-by: bosnichd * Update to bail out as soon as t > 1.0f Signed-off-by: bosnichd --- .../AzFramework/Render/IntersectorInterface.h | 2 +- .../Terrain/TerrainDataRequestBus.h | 7 + .../Mocks/Terrain/MockTerrainDataRequestBus.h | 4 + .../Viewport/ViewportMessages.cpp | 13 +- .../TerrainRaycast/TerrainRaycastContext.cpp | 392 ++++++++++++++++++ .../TerrainRaycast/TerrainRaycastContext.h | 62 +++ .../Source/TerrainSystem/TerrainSystem.cpp | 11 + .../Code/Source/TerrainSystem/TerrainSystem.h | 6 + Gems/Terrain/Code/terrain_files.cmake | 2 + 9 files changed, 494 insertions(+), 5 deletions(-) create mode 100644 Gems/Terrain/Code/Source/TerrainRaycast/TerrainRaycastContext.cpp create mode 100644 Gems/Terrain/Code/Source/TerrainRaycast/TerrainRaycastContext.h diff --git a/Code/Framework/AzFramework/AzFramework/Render/IntersectorInterface.h b/Code/Framework/AzFramework/AzFramework/Render/IntersectorInterface.h index 44e1290911..10ea51dd75 100644 --- a/Code/Framework/AzFramework/AzFramework/Render/IntersectorInterface.h +++ b/Code/Framework/AzFramework/AzFramework/Render/IntersectorInterface.h @@ -24,7 +24,7 @@ namespace AzFramework //! IntersectorBus::EventResult(result, editorContextId, &IntersectorInterface::RayIntersect, ray); //! //! Raycast against all entities - //! RayResultAggregator rayResult; + //! AZ::EBusReduceResult rayResult; //! IntersectorBus::BroadCastResult(rayResult, &IntersectorInterface::RayIntersect, ray); // class IntersectorInterface diff --git a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h index 8b29f2a554..f9ef264ab1 100644 --- a/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h +++ b/Code/Framework/AzFramework/AzFramework/Terrain/TerrainDataRequestBus.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include namespace AzFramework @@ -185,6 +187,11 @@ namespace AzFramework SurfacePointRegionFillCallback perPositionCallback, Sampler sampleFilter = Sampler::DEFAULT) const = 0; + //! Get the terrain raycast entity context id. + virtual EntityContextId GetTerrainRaycastEntityContextId() const = 0; + + //! Given a ray, return the closest intersection with terrain. + virtual RenderGeometry::RayResult GetClosestIntersection(const RenderGeometry::RayRequest& ray) const = 0; private: // Private variations of the GetSurfacePoint API exposed to BehaviorContext that returns a value instead of diff --git a/Code/Framework/AzFramework/Tests/Mocks/Terrain/MockTerrainDataRequestBus.h b/Code/Framework/AzFramework/Tests/Mocks/Terrain/MockTerrainDataRequestBus.h index 52ac28ef63..f5af0ff486 100644 --- a/Code/Framework/AzFramework/Tests/Mocks/Terrain/MockTerrainDataRequestBus.h +++ b/Code/Framework/AzFramework/Tests/Mocks/Terrain/MockTerrainDataRequestBus.h @@ -102,5 +102,9 @@ namespace UnitTest ProcessSurfaceWeightsFromRegion, void(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler)); MOCK_CONST_METHOD4( ProcessSurfacePointsFromRegion, void(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler)); + MOCK_CONST_METHOD0( + GetTerrainRaycastEntityContextId, AzFramework::EntityContextId()); + MOCK_CONST_METHOD1( + GetClosestIntersection, AzFramework::RenderGeometry::RayResult(const AzFramework::RenderGeometry::RayRequest&)); }; } // namespace UnitTest diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.cpp index 24b3c95310..610b9ec854 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.cpp @@ -7,6 +7,7 @@ */ #include +#include #include namespace AzToolsFramework @@ -66,15 +67,19 @@ namespace AzToolsFramework AZ::Vector3 FindClosestPickIntersection(const AzFramework::RenderGeometry::RayRequest& rayRequest, const float defaultDistance) { - AzFramework::RenderGeometry::RayResult renderGeometryIntersectionResult; + // attempt a ray intersection with any visible mesh or terrain and return the intersection position if successful + AZ::EBusReduceResult renderGeometryIntersectionResult; AzFramework::RenderGeometry::IntersectorBus::EventResult( renderGeometryIntersectionResult, AzToolsFramework::GetEntityContextId(), &AzFramework::RenderGeometry::IntersectorBus::Events::RayIntersect, rayRequest); + AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult( + renderGeometryIntersectionResult, + &AzFramework::Terrain::TerrainDataRequests::GetClosestIntersection, + rayRequest); - // attempt a ray intersection with any visible mesh and return the intersection position if successful - if (renderGeometryIntersectionResult) + if (renderGeometryIntersectionResult.value) { - return renderGeometryIntersectionResult.m_worldPosition; + return renderGeometryIntersectionResult.value.m_worldPosition; } else { diff --git a/Gems/Terrain/Code/Source/TerrainRaycast/TerrainRaycastContext.cpp b/Gems/Terrain/Code/Source/TerrainRaycast/TerrainRaycastContext.cpp new file mode 100644 index 0000000000..d42388db60 --- /dev/null +++ b/Gems/Terrain/Code/Source/TerrainRaycast/TerrainRaycastContext.cpp @@ -0,0 +1,392 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +#include +#include + +using namespace Terrain; + +namespace +{ + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Convenience function to clamp a value to the given grid resolution, rounding up. + inline float ClampToGridRoundUp(float value, float gridResolution) + { + return ceil(value / gridResolution) * gridResolution; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Convenience function to clamp a value to the given grid resolution, rounding down. + inline float ClampToGridRoundDown(float value, float gridResolution) + { + return floor(value / gridResolution) * gridResolution; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Convenience function to find the nearest intersection (if any) between an AABB and a ray. + inline void FindNearestIntersection(const AZ::Aabb& aabb, + const AZ::Vector3& rayStart, + const AZ::Vector3& rayDirection, + const AZ::Vector3& rayDirectionReciprocal, + AzFramework::RenderGeometry::RayResult& result) + { + float intersectionT; + float intersectionEndT; + AZ::Vector3 intersectionNormal; + const int intersectionResult = AZ::Intersect::IntersectRayAABB(rayStart, + rayDirection, + rayDirectionReciprocal, + aabb, + intersectionT, + intersectionEndT, + intersectionNormal); + if (intersectionResult != AZ::Intersect::ISECT_RAY_AABB_NONE) + { + result.m_worldPosition = rayStart + (rayDirection * intersectionT); + result.m_worldNormal = intersectionNormal; + result.m_distance = rayDirection.GetLength() * intersectionT; + } + else + { + result.m_distance = FLT_MAX; + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Convenience function to find the nearest intersection (if any) between a triangle and a ray. + // This is an implementation of the Moller-Trumbore intersection algorithm. I first attempted to use + // the existing AZ::Intersect::IntersectSegmentTriangleCCW, which appears to use the same algorithm, + // but it takes a line segment as opposed to a ray and was not returning the expected results. Once + // I've written some tests I can go back and try it again to figure out what is different, but this + // is all likely to get replaced with an optimized SIMD version anyway so this should be ok for now. + inline void FindNearestIntersection(const AZ::Vector3& vertexA, + const AZ::Vector3& vertexB, + const AZ::Vector3& vertexC, + const AZ::Vector3& rayStart, + const AZ::Vector3& rayDirection, + AzFramework::RenderGeometry::RayResult& result) + { + const AZ::Vector3 edgeAB = vertexB - vertexA; + const AZ::Vector3 edgeAC = vertexC - vertexA; + const AZ::Vector3 pVec = rayDirection.Cross(edgeAC); + const float det = edgeAB.Dot(pVec); + if (AZ::IsClose(det, 0.0f)) + { + // The ray is parallel to the triangle. + return; + } + + const float detInv = 1.0f / det; + const AZ::Vector3 tVec = rayStart - vertexA; + const float u = detInv * tVec.Dot(pVec); + if (u < 0.0f || u > 1.0f) + { + // No intersection. + return; + } + + const AZ::Vector3 qVec = tVec.Cross(edgeAB); + const float v = detInv * rayDirection.Dot(qVec); + if (v < 0.0 || u + v > 1.0) + { + // No intersection. + return; + } + + const float t = detInv * edgeAC.Dot(qVec); + if (t > FLT_EPSILON) + { + result.m_worldPosition = rayStart + (rayDirection * t); + result.m_worldNormal = edgeAB.Cross(edgeAC); + result.m_distance = rayDirection.GetLength() * t; + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Convenience function to get the terrain height values at each corner of an AABB, triangulate them, + // and then find the nearest intersection (if any) between the resulting triangles and the given ray. + inline void TriangulateAndFindNearestIntersection(const TerrainSystem& terrainSystem, + const AZ::Aabb& aabb, + const AZ::Vector3& rayStart, + const AZ::Vector3& rayDirection, + const AZ::Vector3& rayDirectionReciprocal, + AzFramework::RenderGeometry::RayResult& result) + { + // Obtain the height values at each corner of the AABB. + const AZ::Vector3& aabbMin = aabb.GetMin(); + const AZ::Vector3& aabbMax = aabb.GetMax(); + AZ::Vector3 point0 = aabbMin; + AZ::Vector3 point2 = aabbMax; + AZ::Vector3 point1(point0.GetX(), point2.GetY(), 0.0f); + AZ::Vector3 point3(point2.GetX(), point0.GetY(), 0.0f); + point0.SetZ(terrainSystem.GetHeight(point0, AzFramework::Terrain::TerrainDataRequests::Sampler::DEFAULT)); + point1.SetZ(terrainSystem.GetHeight(point1, AzFramework::Terrain::TerrainDataRequests::Sampler::DEFAULT)); + point2.SetZ(terrainSystem.GetHeight(point2, AzFramework::Terrain::TerrainDataRequests::Sampler::DEFAULT)); + point3.SetZ(terrainSystem.GetHeight(point3, AzFramework::Terrain::TerrainDataRequests::Sampler::DEFAULT)); + + // Construct a smaller AABB that tightly encloses the four terrain points. + const float refinedMinZ = AZStd::GetMin(AZStd::GetMin(AZStd::GetMin(point0.GetZ(), point1.GetZ()), point2.GetZ()), point3.GetZ()); + const float refinedMaxZ = AZStd::GetMax(AZStd::GetMax(AZStd::GetMax(point0.GetZ(), point1.GetZ()), point2.GetZ()), point3.GetZ()); + const AZ::Vector3 refinedMin(aabbMin.GetX(), aabbMin.GetY(), refinedMinZ); + const AZ::Vector3 refinedMax(aabbMax.GetX(), aabbMax.GetY(), refinedMaxZ); + const AZ::Aabb refinedAABB = AZ::Aabb::CreateFromMinMax(refinedMin, refinedMax); + + // Check for a hit against the refined AABB. + float intersectionT; + float intersectionEndT; + const int intersectionResult = AZ::Intersect::IntersectRayAABB2(rayStart, + rayDirectionReciprocal, + refinedAABB, + intersectionT, + intersectionEndT); + if (intersectionResult == AZ::Intersect::ISECT_RAY_AABB_NONE) + { + return; + } + + // Finally, triangulate the four terrain points and check for a hit, + // splitting using the top-left -> bottom-right diagonal so to match + // the current behavior of the terrain physics and rendering systems. + AzFramework::RenderGeometry::RayResult bottomLeftIntersectionResult; + FindNearestIntersection(rayStart, + rayDirection, + point0, + point3, + point1, + bottomLeftIntersectionResult); + + AzFramework::RenderGeometry::RayResult topRightIntersectionResult; + FindNearestIntersection(rayStart, + rayDirection, + point2, + point1, + point3, + topRightIntersectionResult); + + if (bottomLeftIntersectionResult) + { + result = !topRightIntersectionResult || bottomLeftIntersectionResult.m_distance < topRightIntersectionResult.m_distance ? + bottomLeftIntersectionResult : + topRightIntersectionResult; + } + else if (topRightIntersectionResult) + { + result = topRightIntersectionResult; + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Iterative function that divides an AABB encompasing terrain points into columns (or a voxel grid) + // of size equal to the given grid resolution, steps along the ray visiting each voxel it intersects + // in order from nearest to farthest, then obtains the terrain height values at each corner in order + // to triangulate them and find the nearest intersection (if any) between the triangles and the ray. + // + // Visualization: + // - X: Column intersection but no triangle hit found + // - T: Column intersection with a triangle hit found + // ________________________________________ + // | | | | | | | | | + // |____|____|____|____|____|____|____|____| Ray + // | | | | | | | | | / + // |____|____|____|____|____|____|____|____| / + // | | | | | | | | X |/ + // |____|____|____|____|____|____|____|____/ + // | | | | | | | | X /| + // |____|____|____|____|____|____|____|__/_| + // | | | | | | | | /X | + // |____|____|____|____|____|____|____|/___| + // | | | | | | | X / X | + // |____|____|____|____|____|____|___/|____| + // | | | | | | | T/ | | + // |____|____|____|____|____|____|____|____| + // | | | | | | | | | + // |____|____|____|____|____|____|____|____| + inline void FindNearestIntersectionIterative(const TerrainSystem& terrainSystem, + const AZ::Vector2& terrainResolution, + const AZ::Aabb& terrainWorldBounds, + const AZ::Vector3& rayStart, + const AZ::Vector3& rayEnd, + AzFramework::RenderGeometry::RayResult& result) + { + // Find the nearest intersection (if any) between the ray and terrain world bounds. + // Note that the ray might (and often will) start inside the terrain world bounds. + const AZ::Vector3 rayDirection = rayEnd - rayStart; + const AZ::Vector3 rayDirectionReciprocal = rayDirection.GetReciprocal(); + FindNearestIntersection(terrainWorldBounds, + rayStart, + rayDirection, + rayDirectionReciprocal, + result); + if (!result) + { + // The ray does not intersect the terrain world bounds. + return; + } + + // The terrain world can be visualized as a grid of columns, + // where the terrain resolution determines the dimensions of + // each column, or a voxel grid with one cell in z dimension. + // + // Starting at the voxel containing the initial intersection, + // we want to step along the ray and visit each voxel the ray + // intersects in order from nearest to furthest until we find + // an intersection with the terrain or the ray exits the grid. + const AZ::Vector3& initialIntersection = result.m_worldPosition; + const float initialIntersectionX = initialIntersection.GetX(); + const float initialIntersectionY = initialIntersection.GetY(); + const float initialIntersectionZ = initialIntersection.GetZ(); + const float gridResolutionX = terrainResolution.GetX(); + const float gridResolutionY = terrainResolution.GetY(); + const float gridResolutionZ = terrainWorldBounds.GetMax().GetZ() - terrainWorldBounds.GetMin().GetZ(); + float initialVoxelMinX = ClampToGridRoundDown(initialIntersectionX, gridResolutionX); + float initialVoxelMinY = ClampToGridRoundDown(initialIntersectionY, gridResolutionY); + float initialVoxelMinZ = terrainWorldBounds.GetMin().GetZ(); + float initialVoxelMaxX = ClampToGridRoundUp(initialIntersectionX, gridResolutionX); + float initialVoxelMaxY = ClampToGridRoundUp(initialIntersectionY, gridResolutionY); + float initialVoxelMaxZ = terrainWorldBounds.GetMax().GetZ(); + + // For each axis calculate the distance t we need to move along + // the ray in order to fully traverse a voxel in that dimension. + const float rayDirectionX = rayDirection.GetX(); + const float rayDirectionY = rayDirection.GetY(); + const float rayDirectionZ = rayDirection.GetZ(); + const float stepX = AZ::GetSign(rayDirectionX) * gridResolutionX; + const float stepY = AZ::GetSign(rayDirectionY) * gridResolutionY; + const float stepZ = AZ::GetSign(rayDirectionZ) * gridResolutionZ; + const float tDeltaX = rayDirectionX ? + stepX / rayDirectionX : + std::numeric_limits::max(); + const float tDeltaY = rayDirectionY ? + stepY / rayDirectionY : + std::numeric_limits::max(); + const float tDeltaZ = rayDirectionZ ? + stepZ / rayDirectionZ : + std::numeric_limits::max(); + + // For each axis, calculate the distance t we need to move along the ray + // from the initial intersection point to the next voxel along that axis. + const float offsetX = stepX < 0.0f ? + initialVoxelMinX - initialIntersectionX : + initialVoxelMaxX - initialIntersectionX; + const float offsetY = stepY < 0.0f ? + initialVoxelMinY - initialIntersectionY : + initialVoxelMaxY - initialIntersectionY; + const float offsetZ = stepZ < 0.0f ? + initialVoxelMinZ - initialIntersectionZ : + initialVoxelMaxZ - initialIntersectionZ; + float tMaxX = rayDirectionX ? + offsetX / rayDirectionX : + std::numeric_limits::max(); + float tMaxY = rayDirectionY ? + offsetY / rayDirectionY : + std::numeric_limits::max(); + float tMaxZ = rayDirectionZ ? + offsetZ / rayDirectionZ : + std::numeric_limits::max(); + + // Calculate the min/max voxel grid value on each axis by expanding + // the terrain world bounds so they align with the grid resolution. + const float voxelGridMinX = ClampToGridRoundDown(terrainWorldBounds.GetMin().GetX(), gridResolutionX); + const float voxelGridMinY = ClampToGridRoundDown(terrainWorldBounds.GetMin().GetY(), gridResolutionY); + const float voxelGridMinZ = terrainWorldBounds.GetMin().GetZ(); + const float voxelGridMaxX = ClampToGridRoundUp(terrainWorldBounds.GetMax().GetX(), gridResolutionX); + const float voxelGridMaxY = ClampToGridRoundUp(terrainWorldBounds.GetMax().GetY(), gridResolutionY); + const float voxelGridMaxZ = terrainWorldBounds.GetMax().GetZ(); + + // Using the initial voxel values, construct an AABB representing the current voxel, + // then grab references to AABBs min/max vectors so we can manipulate them directly. + AZ::Aabb currentVoxel = AZ::Aabb::CreateFromMinMax({initialVoxelMinX, initialVoxelMinY, initialVoxelMinZ}, + {initialVoxelMaxX, initialVoxelMaxY, initialVoxelMaxZ}); + AZ::Vector3& currentVoxelMin = const_cast(currentVoxel.GetMin()); + AZ::Vector3& currentVoxelMax = const_cast(currentVoxel.GetMax()); + const AZ::Vector3 stepVecX(stepX, 0.0f, 0.0f); + const AZ::Vector3 stepVecY(0.0f, stepY, 0.0f); + const AZ::Vector3 stepVecZ(0.0f, 0.0f, stepZ); + + // Now we can step along the ray and visit each voxel the ray + // intersects in order from nearest to furthest until we find + // an intersection with the terrain or the ray exits the grid. + result = AzFramework::RenderGeometry::RayResult(); + while (currentVoxel.GetMin().GetX() <= voxelGridMaxX && + currentVoxel.GetMax().GetX() >= voxelGridMinX && + currentVoxel.GetMin().GetY() <= voxelGridMaxY && + currentVoxel.GetMax().GetY() >= voxelGridMinY && + currentVoxel.GetMin().GetZ() <= voxelGridMaxZ && + currentVoxel.GetMax().GetZ() >= voxelGridMinZ && + tMaxX <= 1.0f && tMaxY <= 1.0f && tMaxZ <= 1.0f) + { + TriangulateAndFindNearestIntersection(terrainSystem, + currentVoxel, + rayStart, + rayDirection, + rayDirectionReciprocal, + result); + if (result) + { + // Intersection found. + break; + } + + // Step to the next voxel. + if (tMaxX < tMaxY && tMaxX < tMaxZ) + { + currentVoxelMin += stepVecX; + currentVoxelMax += stepVecX; + tMaxX += tDeltaX; + } + else if (tMaxY < tMaxZ) + { + currentVoxelMin += stepVecY; + currentVoxelMax += stepVecY; + tMaxY += tDeltaY; + } + else + { + currentVoxelMin += stepVecZ; + currentVoxelMax += stepVecZ; + tMaxZ += tDeltaZ; + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +TerrainRaycastContext::TerrainRaycastContext(TerrainSystem& terrainSystem) + : m_terrainSystem(terrainSystem) + , m_entityContextId(AzFramework::EntityContextId::CreateRandom()) +{ + AzFramework::RenderGeometry::IntersectorBus::Handler::BusConnect(m_entityContextId); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +TerrainRaycastContext::~TerrainRaycastContext() +{ + AzFramework::RenderGeometry::IntersectorBus::Handler::BusDisconnect(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +AzFramework::RenderGeometry::RayResult TerrainRaycastContext::RayIntersect( + const AzFramework::RenderGeometry::RayRequest& ray) +{ + const AZ::Aabb terrainWorldBounds = m_terrainSystem.GetTerrainAabb(); + const AZ::Vector2 terrainResolution = m_terrainSystem.GetTerrainHeightQueryResolution(); + AzFramework::RenderGeometry::RayResult rayIntersectionResult; + FindNearestIntersectionIterative(m_terrainSystem, + terrainResolution, + terrainWorldBounds, + ray.m_startWorldPosition, + ray.m_endWorldPosition, + rayIntersectionResult); + + // If needed we could call m_terrainSystem.FindBestAreaEntityAtPosition in order to set + // rayIntersectionResult.m_entityAndComponent, but I'm not sure whether that is correct. + return rayIntersectionResult; +} diff --git a/Gems/Terrain/Code/Source/TerrainRaycast/TerrainRaycastContext.h b/Gems/Terrain/Code/Source/TerrainRaycast/TerrainRaycastContext.h new file mode 100644 index 0000000000..a5a50848c3 --- /dev/null +++ b/Gems/Terrain/Code/Source/TerrainRaycast/TerrainRaycastContext.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#include + +//////////////////////////////////////////////////////////////////////////////////////////////////// +namespace Terrain +{ + class TerrainSystem; + + //////////////////////////////////////////////////////////////////////////////////////////////// + class TerrainRaycastContext : public AzFramework::RenderGeometry::IntersectorBus::Handler + { + public: + //////////////////////////////////////////////////////////////////////////////////////////// + //! Constructor + //! \param[in] terrainSystem The terrain system that owns this terrain raycast context + TerrainRaycastContext(TerrainSystem& terrainSystem); + + //////////////////////////////////////////////////////////////////////////////////////////// + // Disable copying + AZ_DISABLE_COPY_MOVE(TerrainRaycastContext); + + //////////////////////////////////////////////////////////////////////////////////////////// + //! Destructor + ~TerrainRaycastContext(); + + //////////////////////////////////////////////////////////////////////////////////////////// + //! Access to the terrain raycast context's entity context id + //! \return The terrain raycast context's entity context id + inline AzFramework::EntityContextId GetEntityContextId() const { return m_entityContextId; } + + //////////////////////////////////////////////////////////////////////////////////////////// + //! \ref AzFramework::RenderGeometry::RayIntersect + AzFramework::RenderGeometry::RayResult RayIntersect(const AzFramework::RenderGeometry::RayRequest& ray) override; + + protected: + //////////////////////////////////////////////////////////////////////////////////////////// + // RenderGeometry::IntersectorBus inherits from RenderGeometry::IntersectionNotifications, + // so we must override the following pure virtual functions. We could potentially implement + // them using TerrainSystem::m_registeredAreas, but right now that would not serve a purpose. + ///@{ + //! Unused pure virtual override + void OnEntityConnected(AZ::EntityId) override {} + void OnEntityDisconnected(AZ::EntityId) override {} + void OnGeometryChanged(AZ::EntityId) override {} + ///@} + + private: + //////////////////////////////////////////////////////////////////////////////////////////// + // Variables + TerrainSystem& m_terrainSystem; //!< Terrain system that owns this terrain raycast context + AzFramework::EntityContextId m_entityContextId; //!< This object's entity context id + }; +} // namespace Terrain diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp index 4dfa03ed53..35e6992db3 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.cpp @@ -51,6 +51,7 @@ bool TerrainLayerPriorityComparator::operator()(const AZ::EntityId& layer1id, co } TerrainSystem::TerrainSystem() + : m_terrainRaycastContext(*this) { Terrain::TerrainSystemServiceRequestBus::Handler::BusConnect(); AZ::TickBus::Handler::BusConnect(); @@ -438,6 +439,16 @@ void TerrainSystem::GetSurfacePointFromFloats( GetSurfacePoint(AZ::Vector3(x, y, 0.0f), outSurfacePoint, sampleFilter, terrainExistsPtr); } +AzFramework::EntityContextId TerrainSystem::GetTerrainRaycastEntityContextId() const +{ + return m_terrainRaycastContext.GetEntityContextId(); +} + +AzFramework::RenderGeometry::RayResult TerrainSystem::GetClosestIntersection( + const AzFramework::RenderGeometry::RayRequest& ray) const +{ + return m_terrainRaycastContext.RayIntersect(ray); +} AZ::EntityId TerrainSystem::FindBestAreaEntityAtPosition(float x, float y, AZ::Aabb& bounds) const { diff --git a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h index 3e489730d0..1cdb6e52b1 100644 --- a/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h +++ b/Gems/Terrain/Code/Source/TerrainSystem/TerrainSystem.h @@ -23,6 +23,7 @@ #include #include +#include #include namespace Terrain @@ -187,6 +188,9 @@ namespace Terrain AzFramework::Terrain::SurfacePointRegionFillCallback perPositionCallback, Sampler sampleFilter = Sampler::DEFAULT) const override; + AzFramework::EntityContextId GetTerrainRaycastEntityContextId() const override; + AzFramework::RenderGeometry::RayResult GetClosestIntersection( + const AzFramework::RenderGeometry::RayRequest& ray) const override; private: void ClampPosition(float x, float y, AZ::Vector2& outPosition, AZ::Vector2& normalizedDelta) const; @@ -230,5 +234,7 @@ namespace Terrain mutable AZStd::shared_mutex m_areaMutex; AZStd::map m_registeredAreas; + + mutable TerrainRaycastContext m_terrainRaycastContext; }; } // namespace Terrain diff --git a/Gems/Terrain/Code/terrain_files.cmake b/Gems/Terrain/Code/terrain_files.cmake index ab19d33618..4b994c2587 100644 --- a/Gems/Terrain/Code/terrain_files.cmake +++ b/Gems/Terrain/Code/terrain_files.cmake @@ -27,6 +27,8 @@ set(FILES Source/Components/TerrainWorldDebuggerComponent.h Source/Components/TerrainWorldRendererComponent.cpp Source/Components/TerrainWorldRendererComponent.h + Source/TerrainRaycast/TerrainRaycastContext.cpp + Source/TerrainRaycast/TerrainRaycastContext.h Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.cpp Source/TerrainRenderer/Components/TerrainSurfaceMaterialsListComponent.h Source/TerrainRenderer/Components/TerrainMacroMaterialComponent.cpp From 640fe70c56f7a5aaaf244d9913f88acc6899fd16 Mon Sep 17 00:00:00 2001 From: Allen Jackson <23512001+jackalbe@users.noreply.github.com> Date: Mon, 24 Jan 2022 15:09:15 -0600 Subject: [PATCH 111/136] Combining the original scene manifest with the new manifest (#7083) * Combining the original scene manifest with the new manifest to allow the OnPrepareForExport to execute Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com> * fixing comment Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com> --- .../Blast/Editor/Scripts/blast_asset_builder.py | 2 +- .../Editor/Scripts/blast_chunk_processor.py | 17 ++++++++++++++--- Gems/Blast/Editor/Scripts/bootstrap.py | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Gems/Blast/Editor/Scripts/blast_asset_builder.py b/Gems/Blast/Editor/Scripts/blast_asset_builder.py index a570489ed1..cd17360f9f 100644 --- a/Gems/Blast/Editor/Scripts/blast_asset_builder.py +++ b/Gems/Blast/Editor/Scripts/blast_asset_builder.py @@ -15,7 +15,7 @@ manifest that writes out asset chunk data for .blast files import os, traceback, binascii, sys, json, pathlib import azlmbr.math import azlmbr.asset -import azlmbr.asset.entity +import azlmbr.entity import azlmbr.asset.builder import azlmbr.bus diff --git a/Gems/Blast/Editor/Scripts/blast_chunk_processor.py b/Gems/Blast/Editor/Scripts/blast_chunk_processor.py index d112f465e9..500577716b 100644 --- a/Gems/Blast/Editor/Scripts/blast_chunk_processor.py +++ b/Gems/Blast/Editor/Scripts/blast_chunk_processor.py @@ -12,10 +12,10 @@ into a scene manifest This is also a SceneAPI script that executes from a foo.fbx.assetinfo scene manifest that writes out asset chunk data for .blast files """ -import os, traceback, binascii, sys, json, pathlib +import os, traceback, binascii, sys, json, pathlib, logging import azlmbr.math import azlmbr.asset -import azlmbr.asset.entity +import azlmbr.entity import azlmbr.asset.builder import azlmbr.bus @@ -24,6 +24,14 @@ import azlmbr.bus # blastChunksAssetType = azlmbr.math.Uuid_CreateString('{993F0B0F-37D9-48C6-9CC2-E27D3F3E343E}', 0) +def log_exception_traceback(): + """ + Outputs an exception stacktrace. + """ + data = traceback.format_exc() + logger = logging.getLogger('python') + logger.error(data) + def export_chunk_asset(scene, outputDirectory, platformIdentifier, productList): import azlmbr.scene import azlmbr.object @@ -97,7 +105,7 @@ def get_mesh_node_names(sceneGraph): return meshDataList def update_manifest(scene): - import uuid, os + import uuid, os, json import azlmbr.scene as sceneApi import azlmbr.scene.graph from scene_api import scene_data as sceneData @@ -116,6 +124,9 @@ def update_manifest(scene): meshGroup['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, sourceFilenameOnly + chunkPath)) + '}' sceneManifest.mesh_group_select_node(meshGroup, chunkPath) + # combine both scene manifests so the OnPrepareForExport will be called + originalManifest = json.loads(scene.manifest.ExportToJson()) + sceneManifest.manifest["values"].append(originalManifest["values"][0]) return sceneManifest.export() sceneJobHandler = None diff --git a/Gems/Blast/Editor/Scripts/bootstrap.py b/Gems/Blast/Editor/Scripts/bootstrap.py index 93004d474f..aa7e7625e8 100755 --- a/Gems/Blast/Editor/Scripts/bootstrap.py +++ b/Gems/Blast/Editor/Scripts/bootstrap.py @@ -6,7 +6,7 @@ SPDX-License-Identifier: Apache-2.0 OR MIT """ try: import azlmbr.asset - import azlmbr.asset.entity + import azlmbr.entity import azlmbr.asset.builder import blast_asset_builder except: From d1143770e0f985d00ae743614334db761c9f329e Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Mon, 24 Jan 2022 13:17:16 -0800 Subject: [PATCH 112/136] Prefab Focus Mode | Fixes to viewport top toolbar (#7094) * Fixes to the viewport top toolbar. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Additional checks to prevent issues if widgets aren't set up correctly. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> * Add asserts to catch UI changes that would break this class. Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- Code/Editor/ViewPane.cpp | 37 +++++++++---------- Code/Editor/ViewportTitleDlg.cpp | 24 +++++++++--- Code/Editor/ViewportTitleDlg.h | 2 + Code/Editor/ViewportTitleDlg.ui | 15 ++++++++ .../AzQtComponents/Components/ToolBarArea.cpp | 3 +- .../Prefab/PrefabViewportFocusPathHandler.cpp | 3 ++ 6 files changed, 57 insertions(+), 27 deletions(-) diff --git a/Code/Editor/ViewPane.cpp b/Code/Editor/ViewPane.cpp index 90b44d9c9d..99b4c5a1cc 100644 --- a/Code/Editor/ViewPane.cpp +++ b/Code/Editor/ViewPane.cpp @@ -87,29 +87,15 @@ public: } // Handle labels with submenus - if (auto toolLabel = qobject_cast(toolWidget)) + if (auto toolLabel = qobject_cast(toolWidget)) { if (!toolLabel->isVisible()) { // Manually turn the custom context menus into submenus - if (toolLabel->objectName() == "m_fovStaticCtrl") + if (toolLabel->menu()) { - QAction* newAction = menu->addMenu(m_viewportDlg->GetFovMenu()); - newAction->setText(QString("FOV: %1").arg(toolLabel->text())); - } - else if (toolLabel->objectName() == "m_ratioStaticCtrl") - { - QAction* newAction = menu->addMenu(m_viewportDlg->GetAspectMenu()); - newAction->setText(QString("Ratio: %1").arg(toolLabel->text())); - } - else if (toolLabel->objectName() == "m_sizeStaticCtrl") - { - QAction* newAction = menu->addMenu(m_viewportDlg->GetResolutionMenu()); - newAction->setText(QString("%1").arg(toolLabel->text())); - } - else - { - // Don't add actions for other Labels + QAction* action = menu->addMenu(toolLabel->menu()); + action->setText(toolLabel->text()); continue; } } @@ -179,14 +165,25 @@ CLayoutViewPane::CLayoutViewPane(QWidget* parent) toolbar->installEventFilter(&m_viewportTitleDlg); toolbar->setContextMenuPolicy(Qt::CustomContextMenu); connect(toolbar, &QWidget::customContextMenuRequested, &m_viewportTitleDlg, &QWidget::customContextMenuRequested); - setContextMenuPolicy(Qt::NoContextMenu); - + if (QToolButton* expansion = AzQtComponents::ToolBar::getToolBarExpansionButton(toolbar)) { expansion->installEventFilter(m_expanderWatcher); } + AzQtComponents::BreadCrumbs* prefabsBreadcrumbs = + qobject_cast(toolbar->findChild("m_prefabFocusPath")); + QToolButton* backButton = qobject_cast(toolbar->findChild("m_prefabFocusBackButton")); + + AZ_Assert(prefabsBreadcrumbs, "Could not find Prefabs Breadcrumbs widget on CLayoutViewPane initialization!"); + AZ_Assert(backButton, "Could not find Prefabs Breadcrumbs back button on CLayoutViewPane initialization!"); + + if (prefabsBreadcrumbs && backButton) + { + m_viewportTitleDlg.InitializePrefabViewportFocusPathHandler(prefabsBreadcrumbs, backButton); + } + m_id = -1; } diff --git a/Code/Editor/ViewportTitleDlg.cpp b/Code/Editor/ViewportTitleDlg.cpp index 90aa044d25..bbd9eaaa10 100644 --- a/Code/Editor/ViewportTitleDlg.cpp +++ b/Code/Editor/ViewportTitleDlg.cpp @@ -383,12 +383,7 @@ void CViewportTitleDlg::OnInitDialog() bool isPrefabSystemEnabled = false; AzFramework::ApplicationRequests::Bus::BroadcastResult(isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled); - if (isPrefabSystemEnabled) - { - m_prefabViewportFocusPathHandler = new AzToolsFramework::Prefab::PrefabViewportFocusPathHandler(); - m_prefabViewportFocusPathHandler->Initialize(m_ui->m_prefabFocusPath, m_ui->m_prefabFocusBackButton); - } - else + if (!isPrefabSystemEnabled) { m_ui->m_prefabFocusPath->setEnabled(false); m_ui->m_prefabFocusBackButton->setEnabled(false); @@ -397,6 +392,23 @@ void CViewportTitleDlg::OnInitDialog() } } +void CViewportTitleDlg::InitializePrefabViewportFocusPathHandler(AzQtComponents::BreadCrumbs* breadcrumbsWidget, QToolButton* backButton) +{ + if (m_prefabViewportFocusPathHandler != nullptr) + { + return; + } + + bool isPrefabSystemEnabled = false; + AzFramework::ApplicationRequests::Bus::BroadcastResult(isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled); + + if (isPrefabSystemEnabled) + { + m_prefabViewportFocusPathHandler = new AzToolsFramework::Prefab::PrefabViewportFocusPathHandler(); + m_prefabViewportFocusPathHandler->Initialize(breadcrumbsWidget, backButton); + } +} + ////////////////////////////////////////////////////////////////////////// void CViewportTitleDlg::SetTitle(const QString& title) { diff --git a/Code/Editor/ViewportTitleDlg.h b/Code/Editor/ViewportTitleDlg.h index b8da7f20ea..8d8b06b96d 100644 --- a/Code/Editor/ViewportTitleDlg.h +++ b/Code/Editor/ViewportTitleDlg.h @@ -70,6 +70,8 @@ public: QMenu* const GetAspectMenu(); QMenu* const GetResolutionMenu(); + void InitializePrefabViewportFocusPathHandler(AzQtComponents::BreadCrumbs* breadcrumbsWidget, QToolButton* backButton); + Q_SIGNALS: void ActionTriggered(int command); diff --git a/Code/Editor/ViewportTitleDlg.ui b/Code/Editor/ViewportTitleDlg.ui index 7ba6361cf9..1711bdaf90 100644 --- a/Code/Editor/ViewportTitleDlg.ui +++ b/Code/Editor/ViewportTitleDlg.ui @@ -80,6 +80,9 @@ Camera settings + + Camera settings + :/Menu/camera.svg:/Menu/camera.svg @@ -91,6 +94,9 @@ Debug information + + Debug information + :/Menu/debug.svg:/Menu/debug.svg @@ -105,6 +111,9 @@ Toggle viewport helpers + + Toggle viewport helpers + :/Menu/helpers.svg:/Menu/helpers.svg @@ -119,6 +128,9 @@ Viewport resolution + + Viewport resolution + :/Menu/resolution.svg:/Menu/resolution.svg @@ -130,6 +142,9 @@ Other settings + + Other settings + :/Menu/menu.svg:/Menu/menu.svg diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToolBarArea.cpp b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToolBarArea.cpp index b1ef0a670b..14633dcb78 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/ToolBarArea.cpp +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/ToolBarArea.cpp @@ -32,7 +32,8 @@ namespace AzQtComponents { if (QWidget* widget = item->widget()) { - toolbar->addWidget(widget); + QAction* action = toolbar->addWidget(widget); + action->setObjectName(widget->objectName()); } else if (item->spacerItem()) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp index c1fc9138d1..275079371a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp @@ -73,6 +73,9 @@ namespace AzToolsFramework::Prefab { // Push new Path m_breadcrumbsWidget->pushPath(m_prefabFocusPublicInterface->GetPrefabFocusPath(m_editorEntityContextId).c_str()); + + // If root instance is focused, disable the back button; else enable it. + m_backButton->setEnabled(m_prefabFocusPublicInterface->GetPrefabFocusPathLength(m_editorEntityContextId) > 1); } } // namespace AzToolsFramework::Prefab From 075f5ce6931838971706ac8ace940ee457129db7 Mon Sep 17 00:00:00 2001 From: Junbo Liang <68558268+junbo75@users.noreply.github.com> Date: Mon, 24 Jan 2022 14:20:33 -0800 Subject: [PATCH 113/136] Reimplement the GCC fix for the AWS jobs using forward declare (#7088) * Revert the recent AWSApiRequestJob and ServiceRequestJob and use forward declaring to fix the GCC issue Signed-off-by: Junbo Liang <68558268+junbo75@users.noreply.github.com> --- .../Code/Include/Framework/AWSApiRequestJob.h | 149 ++++++++-------- .../Include/Framework/ServiceRequestJob.h | 161 +++++++++--------- 2 files changed, 162 insertions(+), 148 deletions(-) diff --git a/Gems/AWSCore/Code/Include/Framework/AWSApiRequestJob.h b/Gems/AWSCore/Code/Include/Framework/AWSApiRequestJob.h index 816e9bc4b4..e70aa37f58 100644 --- a/Gems/AWSCore/Code/Include/Framework/AWSApiRequestJob.h +++ b/Gems/AWSCore/Code/Include/Framework/AWSApiRequestJob.h @@ -177,6 +177,11 @@ namespace AWSCore using OnSuccessFunction = AZStd::function; using OnFailureFunction = AZStd::function; + class Function; + + template + static AwsApiRequestJob* Create(OnSuccessFunction onSuccess, OnFailureFunction onFailure = OnFailureFunction{}, IConfig* config = GetDefaultConfig()); + static Config* GetDefaultConfig() { static AwsApiJobConfigHolder s_configHolder{}; @@ -188,10 +193,6 @@ namespace AWSCore { } - RequestType request; - ResultType result; - ErrorType error; - /// Override AZ:Job defined method to reset request state when /// the job object is reused. void Reset(bool isClearDependent) override @@ -209,35 +210,11 @@ namespace AWSCore return m_wasSuccess; } + RequestType request; + ResultType result; + ErrorType error; + protected: - - /// Constructor for creating AwsApiRequestJob Jobs that can handle queued responses - /// for OnSuccess, OnFailure, and DoCleanup - AwsApiRequestJob(OnSuccessFunction onSuccess, - OnFailureFunction onFailure, - IConfig* config = GetDefaultConfig() - ) : AwsApiClientJobType(false, config) - , m_queueOnSuccess{ true } - , m_onSuccess{ onSuccess } - , m_queueOnFailure{ true } - , m_onFailure{ onFailure } - , m_queueDelete{ true } - { - } - - bool m_wasSuccess{ false }; - - // Flag and optional function call to queue for onSuccess events - bool m_queueOnSuccess{ false }; - OnSuccessFunction m_onSuccess{}; - - // Flag and optional function call to queue for onFailure events - bool m_queueOnFailure{ false }; - OnFailureFunction m_onFailure{}; - - // Flag to queue the delete during the DoCleanup calls - bool m_queueDelete{ false }; - void Process() override { @@ -295,56 +272,86 @@ namespace AWSCore /// Called when request has completed successfully. virtual void OnSuccess() { - if (m_queueOnSuccess) - { - AZStd::function callbackHandler = [this]() - { - if (m_onSuccess) - { - m_onSuccess(this); - } - delete this; - }; - AZ::TickBus::QueueFunction(callbackHandler); - } } /// Called when the request fails. virtual void OnFailure() { - if (m_queueOnFailure) - { - AZStd::function callbackHandler = [this]() - { - if (m_onFailure) - { - m_onFailure(this); - } - delete this; - }; - AZ::TickBus::QueueFunction(callbackHandler); - } } - /// Called when request can't process and still requires cleanup (Specifically for our derived class Function which does not use auto delete) + /// Called when request can't process and still requires cleanup (Specifically for the derived class AwsApiRequestJob::Function which does not use auto delete) virtual void DoCleanup() { - if (m_queueDelete) - { - AZStd::function callbackHandler = [this]() - { - delete this; - }; - AZ::TickBus::QueueFunction(callbackHandler); - } } - public: - template - static AwsApiRequestJob* Create(OnSuccessFunction onSuccess, OnFailureFunction onFailure = OnFailureFunction{}, IConfig* config = GetDefaultConfig()) - { - return azcreate(AwsApiRequestJob, (onSuccess, onFailure, config), Allocator); - } + bool m_wasSuccess{ false }; }; + /// A specialization of AwsApiRequestJob that lets you provide functions + /// that are called on success or failure of the request. + template + class AwsApiRequestJob::Function + : public AwsApiRequestJob + { + public: + // To use a different allocator, extend this class and use this macro. + AZ_CLASS_ALLOCATOR(Function, AZ::SystemAllocator, 0); + + Function(OnSuccessFunction onSuccess, OnFailureFunction onFailure = OnFailureFunction{}, IConfig* config = GetDefaultConfig()) + : AwsApiRequestJobType( + false, config) // No auto delete - we need to perform our callbacks on the main thread so we queue them through tickbus + , m_onSuccess{ onSuccess } + , m_onFailure{ onFailure } + { + } + + private: + void OnSuccess() override + { + AZStd::function callbackHandler = [this]() + { + if (m_onSuccess) + { + m_onSuccess(this); + } + delete this; + }; + AZ::TickBus::QueueFunction(callbackHandler); + } + + void OnFailure() override + { + AZStd::function callbackHandler = [this]() + { + if (m_onFailure) + { + m_onFailure(this); + } + delete this; + }; + AZ::TickBus::QueueFunction(callbackHandler); + } + + // Code doesn't use auto delete - this allows code to make sure things get cleaned up in cases where success or failure can't be + // called. + void DoCleanup() override + { + AZStd::function callbackHandler = [this]() + { + delete this; + }; + AZ::TickBus::QueueFunction(callbackHandler); + } + + OnSuccessFunction m_onSuccess; + OnFailureFunction m_onFailure; + }; + + template + template + AwsApiRequestJob* AwsApiRequestJob::Create( + OnSuccessFunction onSuccess, OnFailureFunction onFailure, IConfig* config) + { + return azcreate(Function, (onSuccess, onFailure, config), Allocator); + } } // namespace AWSCore diff --git a/Gems/AWSCore/Code/Include/Framework/ServiceRequestJob.h b/Gems/AWSCore/Code/Include/Framework/ServiceRequestJob.h index d3eac4983a..0c2429b9bb 100644 --- a/Gems/AWSCore/Code/Include/Framework/ServiceRequestJob.h +++ b/Gems/AWSCore/Code/Include/Framework/ServiceRequestJob.h @@ -150,6 +150,11 @@ namespace AWSCore using OnSuccessFunction = AZStd::function; using OnFailureFunction = AZStd::function; + class Function; + + template + static ServiceRequestJob* Create(OnSuccessFunction onSuccess, OnFailureFunction onFailure = OnFailureFunction{}, IConfig* config = GetDefaultConfig()); + static Config* GetDefaultConfig() { static AwsApiJobConfigHolder s_configHolder{}; @@ -212,45 +217,6 @@ namespace AWSCore } protected: - /// The URL created by appending the API path to the service URL. - /// The path may contain {param} format parameters. The - /// RequestType::parameters.BuildRequest method is responsible - /// for replacing these parts of the url. - const Aws::String& m_requestUrl; - - /// Constructor for creating ServiceRequestJob Jobs that can handle queued responses - /// for OnSuccess, OnFailure, and DoCleanup - ServiceRequestJob(OnSuccessFunction onSuccess, - OnFailureFunction onFailure, - IConfig* config = GetDefaultConfig() - ) : ServiceClientJobType{ false, config } - , m_requestUrl{ config->GetRequestUrl() } - , m_queueOnSuccess{ true } - , m_onSuccess{ onSuccess } - , m_queueOnFailure{ true } - , m_onFailure{ onFailure } - , m_queueDelete{ true } - { - } - - // Flag and optional function call to queue for onSuccess events - bool m_queueOnSuccess{ false }; - OnSuccessFunction m_onSuccess{}; - - // Flag and optional function call to queue for onFailure events - bool m_queueOnFailure{ false }; - OnFailureFunction m_onFailure{}; - - // Flag to queue the delete during the DoCleanup calls - bool m_queueDelete{ false }; - - std::shared_ptr m_AWSAuthSigner{ nullptr }; - - // Passed in configuration contains the AWS Credentials to use. If this request requires credentials - // check in the constructor and set this bool to indicate if we're not valid before placing the credentials - // in the m_AWSAuthSigner - bool m_missingCredentials{ false }; - /// Called to prepare the request. By default no changes /// are made to the parameters object. Override to defer the preparation /// of parameters until running on the job's worker thread, @@ -270,50 +236,31 @@ namespace AWSCore /// Called when a request completes without error. virtual void OnSuccess() { - if (m_queueOnSuccess) - { - AZStd::function callbackHandler = [this]() - { - if (m_onSuccess) - { - m_onSuccess(this); - } - delete this; - }; - AZ::TickBus::QueueFunction(callbackHandler); - } } /// Called when an error occurs. virtual void OnFailure() { - if (m_queueOnFailure) - { - AZStd::function callbackHandler = [this]() - { - if (m_onFailure) - { - m_onFailure(this); - } - delete this; - }; - AZ::TickBus::QueueFunction(callbackHandler); - } } /// Provided so derived functions that do not auto delete can clean up virtual void DoCleanup() { - if (m_queueDelete) - { - AZStd::function callbackHandler = [this]() - { - delete this; - }; - AZ::TickBus::QueueFunction(callbackHandler); - } } + /// The URL created by appending the API path to the service URL. + /// The path may contain {param} format parameters. The + /// RequestType::parameters.BuildRequest method is responsible + /// for replacing these parts of the url. + const Aws::String& m_requestUrl; + + std::shared_ptr m_AWSAuthSigner{ nullptr }; + + // Passed in configuration contains the AWS Credentials to use. If this request requires credentials + // check in the constructor and set this bool to indicate if we're not valid before placing the credentials + // in the m_AWSAuthSigner + bool m_missingCredentials{ false }; + private: bool BuildRequest(RequestBuilder& request) override { @@ -658,13 +605,73 @@ namespace AWSCore AZ_Printf(logRequestsChannel, "Response Body:\n"); PrintRequestOutput(responseContent); } - public: - template - static ServiceRequestJob* Create(OnSuccessFunction onSuccess, OnFailureFunction onFailure = OnFailureFunction{}, IConfig* config = GetDefaultConfig()) - { - return azcreate(ServiceRequestJob, (onSuccess, onFailure, config), Allocator); - } }; + + /// A derived class that calls lambda functions on job completion. + template + class ServiceRequestJob::Function + : public ServiceRequestJob + { + public: + // To use a different allocator, extend this class and use this macro. + AZ_CLASS_ALLOCATOR(Function, AZ::SystemAllocator, 0); + + Function(OnSuccessFunction onSuccess, OnFailureFunction onFailure = OnFailureFunction{}, IConfig* config = GetDefaultConfig()) + : ServiceRequestJob(false, config) // No auto delete - The Function class will handle it with the DoCleanup() function + , m_onSuccess{ onSuccess } + , m_onFailure{ onFailure } + { + } + + private: + void OnSuccess() override + { + AZStd::function callbackHandler = [this]() + { + if (m_onSuccess) + { + m_onSuccess(this); + } + delete this; + }; + AZ::TickBus::QueueFunction(callbackHandler); + } + + void OnFailure() override + { + AZStd::function callbackHandler = [this]() + { + if (m_onFailure) + { + m_onFailure(this); + } + delete this; + }; + AZ::TickBus::QueueFunction(callbackHandler); + } + + // Code doesn't use auto delete - this ensure things get cleaned up in cases when code can't call success or failure + void DoCleanup() override + { + AZStd::function callbackHandler = [this]() + { + delete this; + }; + AZ::TickBus::QueueFunction(callbackHandler); + } + + OnSuccessFunction m_onSuccess; + OnFailureFunction m_onFailure; + + }; + + template + template + ServiceRequestJob* ServiceRequestJob::Create( + OnSuccessFunction onSuccess, OnFailureFunction onFailure, IConfig* config) + { + return azcreate(Function, (onSuccess, onFailure, config), Allocator); + } } // namespace AWSCore From a3fbcae81fda93a1b7a67828439d2dd390d08a34 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Jan 2022 14:47:38 -0800 Subject: [PATCH 114/136] Bump urllib3 in /scripts/build/build_node/Platform/Linux (#7119) Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.26.4 to 1.26.5. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/1.26.4...1.26.5) --- updated-dependencies: - dependency-name: urllib3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- scripts/build/build_node/Platform/Linux/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/build/build_node/Platform/Linux/requirements.txt b/scripts/build/build_node/Platform/Linux/requirements.txt index 1a466c03f8..7f0536a98e 100644 --- a/scripts/build/build_node/Platform/Linux/requirements.txt +++ b/scripts/build/build_node/Platform/Linux/requirements.txt @@ -36,8 +36,8 @@ requests==2.25.1 \ traceback2==1.4.0 \ --hash=sha256:05acc67a09980c2ecfedd3423f7ae0104839eccb55fc645773e1caa0951c3030 \ --hash=sha256:8253cebec4b19094d67cc5ed5af99bf1dba1285292226e98a31929f87a5d6b23 -urllib3==1.26.4 \ - --hash=sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df \ - --hash=sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937 +urllib3==1.26.5 \ + --hash=sha256:753a0374df26658f99d826cfe40394a686d05985786d946fbe4165b5148f5a7c \ + --hash=sha256:a7acd0977125325f516bda9735fa7142b909a8d01e8b2e4c8108d0984e6e0098 tempfile2==0.1.1 \ --hash=sha256:77fdd256c16804053d3d588168b79595099ea5e874c3fb171893b0ababd10340 From b83fc89c7440104527f84e66be6965c8b86d1cc6 Mon Sep 17 00:00:00 2001 From: Neil Widmaier Date: Mon, 24 Jan 2022 15:03:27 -0800 Subject: [PATCH 115/136] Making requested changes to LevelLoadTest Signed-off-by: Neil Widmaier --- .../Gem/PythonTests/Atom/TestSuite_Main.py | 4 ++ .../Atom/atom_utils/atom_constants.py | 2 + .../Atom/tests/hydra_Atom_LevelLoadTest.py | 45 +++++++------------ 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py index cca20bbf8c..8fc9838b52 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main.py @@ -23,6 +23,10 @@ class TestAutomation(EditorTestSuite): enable_prefab_system = True + @pytest.mark.test_case_id("C36529679") + class AtomLevelLoadTest_Editor(EditorSharedTest): + from Atom.tests import hydra_Atom_LevelLoadTest as test_module + @pytest.mark.test_case_id("C36525657") class AtomEditorComponents_BloomAdded(EditorSharedTest): from Atom.tests import hydra_AtomEditorComponents_BloomAdded as test_module diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py index e6d6ac7fb1..393d71f0b2 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_constants.py @@ -32,6 +32,8 @@ GLOBAL_ILLUMINATION_QUALITY = { 'High': 2, } +# Level list used in Editor Level Load Test +LEVEL_LIST = ["hermanubis", "hermanubis_high", "macbeth_shaderballs", "PbrMaterialChart", "ShadowTest", "Sponza"] class AtomComponentProperties: """ diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_Atom_LevelLoadTest.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_Atom_LevelLoadTest.py index 77886e2123..1efcbe4d01 100644 --- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_Atom_LevelLoadTest.py +++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_Atom_LevelLoadTest.py @@ -23,10 +23,9 @@ def Atom_LevelLoadTest(): 1) Create tuple with level load success and failure messages 2) Open the level using the python test tools command 3) Verify level is loaded using a separate command, and report success/failure - 4) Create tuple with success and failure messages for entering gameplay - 5) Enter gameplay and report result - 6) Create tuple with success and failure messages for exiting gameplay - 7) Exit Gameplay and report result + 4) Enter gameplay and report result using a tuple + 5) Exit Gameplay and report result using a tuple + 6) Look for errors or asserts. :return: None """ @@ -34,45 +33,33 @@ def Atom_LevelLoadTest(): import azlmbr.legacy.general as general from editor_python_test_tools.utils import Report, Tracer, TestHelper - - level_list = ["hermanubis", "hermanubis_high", "macbeth_shaderballs", "PbrMaterialChart", "ShadowTest", "Sponza"] + from Atom.atom_utils.atom_constants import LEVEL_LIST with Tracer() as error_tracer: - # - for level in level_list: + for level in LEVEL_LIST: # 1. Create tuple with level load success and failure messages - level_check_tupple = (f"loaded {level}", f"failed to load {level}") + level_check_tuple = (f"loaded {level}", f"failed to load {level}") # 2. Open the level using the python test tools command TestHelper.init_idle() - TestHelper.open_level("graphics", level) + TestHelper.open_level("Graphics", level) # 3. Verify level is loaded using a separate command, and report success/failure - load_success = general.get_current_level_name() - Report.info(load_success) - if load_success == level: - level_match = True - else: - level_match = False - Report.info(level_match) - Report.result(level_check_tupple, level_match) + Report.result(level_check_tuple, level == general.get_current_level_name()) - # 4. Create tuple with success and failure messages for entering gameplay - Enter_game_mode_tupple = (f"{level} entered gameplay successfully ", f"{level} failed to enter gameplay") + # 4. Enter gameplay and report result using a tuple + enter_game_mode_tuple = (f"{level} entered gameplay successfully ", f"{level} failed to enter gameplay") + TestHelper.enter_game_mode(enter_game_mode_tuple) + general.idle_wait_frames(1) - # 5. Enter gameplay and report result - TestHelper.enter_game_mode(Enter_game_mode_tupple) - - # 6. Create tuple with success and failure messages for exiting gameplay - Exit_game_mode_tupple = (f"{level} exited gameplay successfully ", f"{level} failed to exit gameplay") - - # 7. Exit Gameplay and report result - TestHelper.exit_game_mode(Exit_game_mode_tupple) + # 5. Exit gameplay and report result using a tuple + exit_game_mode_tuple = (f"{level} exited gameplay successfully ", f"{level} failed to exit gameplay") + TestHelper.exit_game_mode(exit_game_mode_tuple) - # 11. Look for errors or asserts. + # 6. Look for errors or asserts. TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0) for error_info in error_tracer.errors: Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}") From f3e9e41f4f8e13860d7a25ffc352d5f8d0d5383c Mon Sep 17 00:00:00 2001 From: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Date: Mon, 24 Jan 2022 17:09:08 -0600 Subject: [PATCH 116/136] Adding partial implementation of C++20 concepts and range functions for AZStd::span (#7102) * Adding partial implementation of C++20 concepts and range functions for AZStd::span The new concepts to discovered existing issues with the PathIterator and deque::iterator classes PathIterator wasn't properly an input_iterator and therefore the Path classes weren't a range due to an incorrect const_iterator alias The deque::iterator classes was missing the operator+ friend function that accepted a (ptrdiff_t, deque::iterator) to fulfill the random_access_iterator concepts The AZStd implementations of (uninitialized_)copy(_n), (uninitialized_)move(_n) and (uninitialized_)file(_n) have been optimized to use memcpy and memset based on fulfilling the contiguous_iterator concept Fixed invalid AZStd::vector inserts in FrameGraphExecuter.cpp and SliceditorEntityOwnershipService.cpp The code was trying to copy the underlying addresses for vector to a vector using insert, which it was doing by using memcpy. relates to #6749 Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed the `fixed_vector` emplace function to not move initialized elements using uninitialized_move. This was causing initialized elements of the fixed_vector to be overwritten with the element at the emplace position. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Fixed clang warnings about variables that are set, but never read Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the `az_has_builtin_is_constant_evaluated` define to not have "()" as is not a macro. This helps prevent users from using `az_has_builtin_is_constant_evaluated` define in a situation where they want to know if the function is being evaluated in a compile time context. In that case they need to use the `az_builtin_is_constant_evaluated()` macro (which of course looks quite similiar) but does not have the word "has" in it.. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Updated the AZStd span class to be C++20 compliant. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Changed phrase "DoesNotCompiles" to be more grammatically correct. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Added more unit test for AZStd span Fixed an the the return type of the subspan template overload to account for the source span having a dynamic extent. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Removed unused variable from span unit test. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/IO/Path/Path.cpp | 30 +- Code/Framework/AzCore/AzCore/IO/Path/Path.h | 21 +- Code/Framework/AzCore/AzCore/IO/Path/Path.inl | 32 +- .../AzCore/AzCore/IO/Path/PathParser.inl | 17 +- Code/Framework/AzCore/AzCore/PlatformDef.h | 8 +- .../AzCore/AzCore/std/azstd_files.cmake | 7 + Code/Framework/AzCore/AzCore/std/base.h | 2 + .../AzCore/AzCore/std/concepts/concepts.h | 840 ++++++++++++ .../AzCore/AzCore/std/containers/deque.h | 10 +- .../AzCore/std/containers/fixed_vector.h | 25 +- .../AzCore/AzCore/std/containers/span.h | 202 ++- .../AzCore/AzCore/std/containers/span.inl | 276 ++-- .../AzCore/AzCore/std/createdestroy.h | 634 +++++---- .../AzCore/AzCore/std/function/invoke.h | 8 + Code/Framework/AzCore/AzCore/std/iterator.h | 63 +- .../AzCore/std/iterator/iterator_primitives.h | 200 +++ .../AzCore/AzCore/std/ranges/iter_move.h | 81 ++ .../AzCore/AzCore/std/ranges/ranges.h | 1157 +++++++++++++++++ .../AzCore/AzCore/std/string/fixed_string.h | 10 +- .../AzCore/AzCore/std/string/fixed_string.inl | 24 +- .../AzCore/AzCore/std/string/string.h | 57 +- .../AzCore/AzCore/std/string/string_view.h | 32 +- .../AzCore/std/typetraits/common_reference.h | 230 ++++ .../AzCore/std/typetraits/is_convertible.h | 16 +- .../AzCore/std/typetraits/is_destructible.h | 3 + .../AzCore/std/typetraits/is_floating_point.h | 3 + .../AzCore/std/typetraits/is_integral.h | 3 + .../AzCore/AzCore/std/typetraits/is_same.h | 4 + .../AzCore/AzCore/std/typetraits/typetraits.h | 2 + .../AzCore/AzCore/std/utility/declval.h | 15 + .../AzCore/AzCore/std/utility/move.h | 19 + Code/Framework/AzCore/AzCore/std/utils.h | 11 +- .../AzCore/Tests/AZStd/ConceptsTests.cpp | 202 +++ .../AzCore/Tests/AZStd/Iterators.cpp | 162 ++- .../AzCore/Tests/AZStd/RangesTests.cpp | 583 +++++++++ .../AzCore/Tests/AZStd/SpanTests.cpp | 249 ++++ .../AzCore/Tests/AZStd/TypeTraits.cpp | 721 +++++----- .../AzCore/Tests/azcoretests_files.cmake | 3 + .../AssetBrowser/Views/EntryDelegate.cpp | 6 +- .../SliceEditorEntityOwnershipService.cpp | 7 +- .../Code/Source/RHI/FrameGraphExecuter.cpp | 16 +- .../EMotionFXAtom/Code/Source/ActorAsset.cpp | 10 +- Gems/EMotionFX/Code/EMotionFX/Source/Mesh.cpp | 2 + .../Code/Tests/TestAssetCode/MeshFactory.cpp | 2 + .../TerrainRenderer/TerrainMeshManager.cpp | 32 +- 45 files changed, 4998 insertions(+), 1039 deletions(-) create mode 100644 Code/Framework/AzCore/AzCore/std/concepts/concepts.h create mode 100644 Code/Framework/AzCore/AzCore/std/iterator/iterator_primitives.h create mode 100644 Code/Framework/AzCore/AzCore/std/ranges/iter_move.h create mode 100644 Code/Framework/AzCore/AzCore/std/ranges/ranges.h create mode 100644 Code/Framework/AzCore/AzCore/std/typetraits/common_reference.h create mode 100644 Code/Framework/AzCore/AzCore/std/utility/declval.h create mode 100644 Code/Framework/AzCore/AzCore/std/utility/move.h create mode 100644 Code/Framework/AzCore/Tests/AZStd/ConceptsTests.cpp create mode 100644 Code/Framework/AzCore/Tests/AZStd/RangesTests.cpp create mode 100644 Code/Framework/AzCore/Tests/AZStd/SpanTests.cpp diff --git a/Code/Framework/AzCore/AzCore/IO/Path/Path.cpp b/Code/Framework/AzCore/AzCore/IO/Path/Path.cpp index 6e4dfdaa63..028ffaf535 100644 --- a/Code/Framework/AzCore/AzCore/IO/Path/Path.cpp +++ b/Code/Framework/AzCore/AzCore/IO/Path/Path.cpp @@ -15,9 +15,9 @@ namespace AZ::IO // Class template instantations template class BasicPath; template class BasicPath; - template class PathIterator; - template class PathIterator; - template class PathIterator; + template class PathIterator; + template class PathIterator; + template class PathIterator; // Swap function instantiations template void swap(Path& lhs, Path& rhs) noexcept; @@ -38,16 +38,16 @@ namespace AZ::IO const typename BasicPath::value_type* rhs); // Iterator compare instantiations - template bool operator==(const PathIterator& lhs, - const PathIterator& rhs); - template bool operator==(const PathIterator& lhs, - const PathIterator& rhs); - template bool operator==(const PathIterator& lhs, - const PathIterator& rhs); - template bool operator!=(const PathIterator& lhs, - const PathIterator& rhs); - template bool operator!=(const PathIterator& lhs, - const PathIterator& rhs); - template bool operator!=(const PathIterator& lhs, - const PathIterator& rhs); + template bool operator==(const PathIterator& lhs, + const PathIterator& rhs); + template bool operator==(const PathIterator& lhs, + const PathIterator& rhs); + template bool operator==(const PathIterator& lhs, + const PathIterator& rhs); + template bool operator!=(const PathIterator& lhs, + const PathIterator& rhs); + template bool operator!=(const PathIterator& lhs, + const PathIterator& rhs); + template bool operator!=(const PathIterator& lhs, + const PathIterator& rhs); } diff --git a/Code/Framework/AzCore/AzCore/IO/Path/Path.h b/Code/Framework/AzCore/AzCore/IO/Path/Path.h index 7f89809294..235310a5da 100644 --- a/Code/Framework/AzCore/AzCore/IO/Path/Path.h +++ b/Code/Framework/AzCore/AzCore/IO/Path/Path.h @@ -43,9 +43,9 @@ namespace AZ::IO public: using string_view_type = AZStd::string_view; using value_type = char; - using const_iterator = const PathIterator; + using const_iterator = PathIterator; using iterator = const_iterator; - friend PathIterator; + friend const_iterator; // constructors and destructor constexpr PathView() = default; @@ -319,9 +319,9 @@ namespace AZ::IO using value_type = typename StringType::value_type; using traits_type = typename StringType::traits_type; using string_view_type = AZStd::string_view; - using const_iterator = const PathIterator; + using const_iterator = PathIterator; using iterator = const_iterator; - friend PathIterator; + friend const_iterator; // constructors and destructor constexpr BasicPath() = default; @@ -692,7 +692,7 @@ namespace AZ::IO friend PathType; using iterator_category = AZStd::bidirectional_iterator_tag; - using value_type = PathType; + using value_type = AZStd::remove_cv_t; using difference_type = ptrdiff_t; using pointer = const value_type*; using reference = const value_type&; @@ -703,8 +703,9 @@ namespace AZ::IO constexpr PathIterator() = default; constexpr PathIterator(const PathIterator&) = default; - + constexpr PathIterator(PathIterator&&) noexcept = default; constexpr PathIterator& operator=(const PathIterator&) = default; + constexpr PathIterator& operator=(PathIterator&&) noexcept = default; constexpr reference operator*() const; @@ -733,10 +734,10 @@ namespace AZ::IO ParserState m_state{ Singular }; }; - template - constexpr bool operator==(const PathIterator& lhs, const PathIterator& rhs); - template - constexpr bool operator!=(const PathIterator& lhs, const PathIterator& rhs); + template + constexpr bool operator==(const PathIterator& lhs, const PathIterator& rhs); + template + constexpr bool operator!=(const PathIterator& lhs, const PathIterator& rhs); } #include diff --git a/Code/Framework/AzCore/AzCore/IO/Path/Path.inl b/Code/Framework/AzCore/AzCore/IO/Path/Path.inl index ab991e1750..bde2353112 100644 --- a/Code/Framework/AzCore/AzCore/IO/Path/Path.inl +++ b/Code/Framework/AzCore/AzCore/IO/Path/Path.inl @@ -399,7 +399,7 @@ namespace AZ::IO constexpr auto PathView::begin() const -> const_iterator { auto pathParser = parser::PathParser::CreateBegin(m_path, m_preferred_separator); - PathIterator it; + const_iterator it; it.m_path_ref = this; it.m_state = static_cast(pathParser.m_parser_state); it.m_path_entry_view = pathParser.m_path_raw_entry; @@ -409,7 +409,7 @@ namespace AZ::IO constexpr auto PathView::end() const -> const_iterator { - PathIterator it; + const_iterator it; it.m_state = const_iterator::AtEnd; it.m_path_ref = this; return it; @@ -1262,7 +1262,7 @@ namespace AZ::IO constexpr auto BasicPath::begin() const -> const_iterator { auto pathParser = parser::PathParser::CreateBegin(m_path, m_preferred_separator); - PathIterator it; + const_iterator it; it.m_path_ref = this; it.m_state = static_cast(pathParser.m_parser_state); it.m_path_entry_view = pathParser.m_path_raw_entry; @@ -1273,7 +1273,7 @@ namespace AZ::IO template constexpr auto BasicPath::end() const -> const_iterator { - PathIterator it; + const_iterator it; it.m_state = const_iterator::AtEnd; it.m_path_ref = this; return it; @@ -1529,16 +1529,16 @@ namespace AZ::IO const typename BasicPath::value_type* rhs); // Iterator compare explicit declarations - extern template bool operator==(const PathIterator& lhs, - const PathIterator& rhs); - extern template bool operator==(const PathIterator& lhs, - const PathIterator& rhs); - extern template bool operator==(const PathIterator& lhs, - const PathIterator& rhs); - extern template bool operator!=(const PathIterator& lhs, - const PathIterator& rhs); - extern template bool operator!=(const PathIterator& lhs, - const PathIterator& rhs); - extern template bool operator!=(const PathIterator& lhs, - const PathIterator& rhs); + extern template bool operator==(const PathIterator& lhs, + const PathIterator& rhs); + extern template bool operator==(const PathIterator& lhs, + const PathIterator& rhs); + extern template bool operator==(const PathIterator& lhs, + const PathIterator& rhs); + extern template bool operator!=(const PathIterator& lhs, + const PathIterator& rhs); + extern template bool operator!=(const PathIterator& lhs, + const PathIterator& rhs); + extern template bool operator!=(const PathIterator& lhs, + const PathIterator& rhs); } diff --git a/Code/Framework/AzCore/AzCore/IO/Path/PathParser.inl b/Code/Framework/AzCore/AzCore/IO/Path/PathParser.inl index b19c518ff9..f8712551b0 100644 --- a/Code/Framework/AzCore/AzCore/IO/Path/PathParser.inl +++ b/Code/Framework/AzCore/AzCore/IO/Path/PathParser.inl @@ -10,6 +10,7 @@ #include #include +#include namespace AZ::IO::Internal { @@ -17,7 +18,7 @@ namespace AZ::IO::Internal { return elem == '/' || elem == '\\'; } - template >> + template >> static constexpr bool HasDrivePrefix(InputIt first, EndIt last) { size_t prefixSize = AZStd::distance(first, last); @@ -46,7 +47,7 @@ namespace AZ::IO::Internal //! Windows root names can have include drive letter within them template constexpr auto ConsumeRootName(InputIt entryBeginIter, InputIt entryEndIter, const char preferredSeparator) - -> AZStd::enable_if_t, InputIt> + -> AZStd::enable_if_t, InputIt> { if (preferredSeparator == PosixPathSeparator) { @@ -147,7 +148,7 @@ namespace AZ::IO::Internal //! If the preferred separator is '/' just checks if the path starts with a '/ //! Otherwise a check for a Windows absolute path occurs //! Windows absolute paths can include a RootName - template >> + template >> static constexpr bool IsAbsolute(InputIt first, EndIt last, const char preferredSeparator) { size_t pathSize = AZStd::distance(first, last); @@ -208,11 +209,11 @@ namespace AZ::IO::parser enum ParserState : uint8_t { // Zero is a special sentinel value used by default constructed iterators. - PS_BeforeBegin = PathIterator::BeforeBegin, - PS_InRootName = PathIterator::InRootName, - PS_InRootDir = PathIterator::InRootDir, - PS_InFilenames = PathIterator::InFilenames, - PS_AtEnd = PathIterator::AtEnd + PS_BeforeBegin = PathView::const_iterator::BeforeBegin, + PS_InRootName = PathView::const_iterator::InRootName, + PS_InRootDir = PathView::const_iterator::InRootDir, + PS_InFilenames = PathView::const_iterator::InFilenames, + PS_AtEnd = PathView::const_iterator::AtEnd }; struct PathParser diff --git a/Code/Framework/AzCore/AzCore/PlatformDef.h b/Code/Framework/AzCore/AzCore/PlatformDef.h index 8609ad5756..8416099f15 100644 --- a/Code/Framework/AzCore/AzCore/PlatformDef.h +++ b/Code/Framework/AzCore/AzCore/PlatformDef.h @@ -248,14 +248,14 @@ #if defined(__has_builtin) #if __has_builtin(__builtin_is_constant_evaluated) #define az_builtin_is_constant_evaluated() __builtin_is_constant_evaluated() - #define az_has_builtin_is_constant_evaluated() true + #define az_has_builtin_is_constant_evaluated true #endif #elif AZ_COMPILER_MSVC >= 1928 #define az_builtin_is_constant_evaluated() __builtin_is_constant_evaluated() - #define az_has_builtin_is_constant_evaluated() true + #define az_has_builtin_is_constant_evaluated true #elif AZ_COMPILER_GCC #define az_builtin_is_constant_evaluated() __builtin_is_constant_evaluated() - #define az_has_builtin_is_constant_evaluated() true + #define az_has_builtin_is_constant_evaluated true #endif #endif @@ -271,7 +271,7 @@ } } #define az_builtin_is_constant_evaluated() AZ::Internal::builtin_is_constant_evaluated() - #define az_has_builtin_is_constant_evaluated() false + #define az_has_builtin_is_constant_evaluated false #endif // define builtin functions used by char_traits class for efficient compile time and runtime diff --git a/Code/Framework/AzCore/AzCore/std/azstd_files.cmake b/Code/Framework/AzCore/AzCore/std/azstd_files.cmake index d516a56295..fe169c4964 100644 --- a/Code/Framework/AzCore/AzCore/std/azstd_files.cmake +++ b/Code/Framework/AzCore/AzCore/std/azstd_files.cmake @@ -19,6 +19,7 @@ set(FILES any.h base.h config.h + concepts/concepts.h createdestroy.h docs.h exceptions.h @@ -27,11 +28,14 @@ set(FILES hash.cpp hash.h hash_table.h + iterator/iterator_primitives.h iterator.h limits.h numeric.h math.h optional.h + ranges/iter_move.h + ranges/ranges.h ratio.h reference_wrapper.h sort.h @@ -151,6 +155,7 @@ set(FILES typetraits/alignment_of.h typetraits/config.h typetraits/common_type.h + typetraits/common_reference.h typetraits/conjunction.h typetraits/disjunction.h typetraits/extent.h @@ -217,4 +222,6 @@ set(FILES typetraits/void_t.h typetraits/internal/type_sequence_traits.h typetraits/internal/is_template_copy_constructible.h + utility/declval.h + utility/move.h ) diff --git a/Code/Framework/AzCore/AzCore/std/base.h b/Code/Framework/AzCore/AzCore/std/base.h index 46d1821328..44b11c61ef 100644 --- a/Code/Framework/AzCore/AzCore/std/base.h +++ b/Code/Framework/AzCore/AzCore/std/base.h @@ -30,4 +30,6 @@ namespace AZStd using std::nullptr_t; using sys_time_t = AZ::s64; + + using std::byte; } diff --git a/Code/Framework/AzCore/AzCore/std/concepts/concepts.h b/Code/Framework/AzCore/AzCore/std/concepts/concepts.h new file mode 100644 index 0000000000..420b671f31 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/std/concepts/concepts.h @@ -0,0 +1,840 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZStd +{ + // alias std::pointer_traits into the AZStd::namespace + using std::pointer_traits; + + // Alias re-declarations from iterator.h + /// Identifying tag for input iterators. + using input_iterator_tag = std::input_iterator_tag; + /// Identifying tag for output iterators. + using output_iterator_tag = std::output_iterator_tag; + /// Identifying tag for forward iterators. + using forward_iterator_tag = std::forward_iterator_tag; + /// Identifying tag for bidirectional iterators. + using bidirectional_iterator_tag = std::bidirectional_iterator_tag; + /// Identifying tag for random-access iterators. + using random_access_iterator_tag = std::random_access_iterator_tag; + /// Identifying tag for contagious iterators + struct contiguous_iterator_tag; +} + +namespace AZStd::Internal +{ + template + constexpr bool pointer_traits_has_to_address_v = false; + + template + constexpr bool pointer_traits_has_to_address_v::to_address(declval()))>>> > = true; + + + // pointer_traits isn't SFINAE friendly https://cplusplus.github.io/LWG/lwg-active.html#3545 + // So working around that by checking if type T has an element_type alias + template + constexpr bool pointer_traits_valid_and_has_to_address_v = false; + template + constexpr bool pointer_traits_valid_and_has_to_address_v> > + = pointer_traits_has_to_address_v; +} + +namespace AZStd +{ + //! Implements the C++20 to_address function + //! This obtains the address represented by ptr without forming a reference + //! to the pointee type + template + constexpr T* to_address(T* ptr) noexcept + { + static_assert(!AZStd::is_function_v, "Invoking to address on a function pointer is not allowed"); + return ptr; + } + //! Fancy pointer overload which delegates to using a specialization of pointer_traits::to_address + //! if that is a well-formed expression, otherwise it returns ptr->operator->() + //! For example invoking `to_address(AZStd::reverse_iterator(char_ptr))` + //! Returns an element of type const char* + template + constexpr auto to_address(const T& ptr) noexcept + { + if constexpr (AZStd::Internal::pointer_traits_valid_and_has_to_address_v) + { + return pointer_traits::to_address(ptr); + } + else + { + return to_address(ptr.operator->()); + } + } +} + +namespace AZStd::Internal +{ + // Variadic template which maps types to true For SFINAE + template + constexpr bool sfinae_trigger_v = true; + + template + constexpr bool is_class_or_enum = false; + template + constexpr bool is_class_or_enum> || is_enum_v>)>> = true; + + template + constexpr bool assignable_from_impl = false; + template + constexpr bool assignable_from_impl + && common_reference_with&, const remove_reference_t&> + && same_as() = declval()), LHS> >> = true; + + + template + constexpr bool common_with_impl = false; + template + constexpr bool common_with_impl, common_type_t> + && sfinae_trigger_v>(declval()))> + && sfinae_trigger_v>(declval()))> + && common_reference_with, add_lvalue_reference_t> + && common_reference_with>, common_reference_t, add_lvalue_reference_t>> + >> = true; +} + +namespace AZStd +{ + template + /*concept*/ constexpr bool common_with = Internal::common_with_impl; + + template + /*concept*/ constexpr bool assignable_from = Internal::assignable_from_impl; + + template + /*concept*/ constexpr bool constructible_from = destructible && is_constructible_v; + + template + /*concept*/ constexpr bool move_constructible = constructible_from && convertible_to; + + template + /*concept*/ constexpr bool derived_from = is_base_of_v && is_convertible_v; +} + +namespace AZStd::ranges::Internal +{ + template + constexpr bool is_class_or_enum_with_swap_adl = false; + template + constexpr bool is_class_or_enum_with_swap_adl> || is_enum_v> + || is_class_v> || is_enum_v>) + && is_void_v(), declval()))>> + >> = true; + + template + void swap(T&, T&) = delete; + + struct swap_fn + { + template + constexpr auto operator()(T&& t, U&& u) const noexcept(noexcept(swap(AZStd::forward(t), AZStd::forward(u)))) + ->enable_if_t> + { + swap(AZStd::forward(t), AZStd::forward(u)); + } + + // ranges::swap customization point https://eel.is/c++draft/concepts#concept.swappable-2.2 + // Implemented in ranges.h as to prevent circular dependency. + // ranges::swap_ranges depends on the range concepts that can't be defined here + template + constexpr auto operator()(T&& t, U&& u) const noexcept(noexcept((*this)(*t, *u))) + ->enable_if_t + && is_array_v && is_array_v && (extent_v == extent_v) + >; + + template + constexpr auto operator()(T& t1, T& t2) const noexcept(noexcept(is_nothrow_move_constructible_v&& is_nothrow_move_assignable_v)) + ->enable_if_t&& assignable_from> + { + auto temp(AZStd::move(t1)); + t1 = AZStd::move(t2); + t2 = AZStd::move(temp); + } + }; +} + +namespace AZStd::ranges +{ + inline namespace customization_point_object + { + inline constexpr auto swap = Internal::swap_fn{}; + } +} + +namespace AZStd::Internal +{ + template + constexpr bool swappable_impl = false; + template + constexpr bool swappable_impl(), declval()))>> = true; + + template + constexpr bool swappable_with_impl = false; + template + constexpr bool swappable_with_impl + && sfinae_trigger_v< + decltype(AZStd::ranges::swap(declval(), declval())), + decltype(AZStd::ranges::swap(declval(), declval())), + decltype(AZStd::ranges::swap(declval(), declval())), + decltype(AZStd::ranges::swap(declval(), declval()))>>> = true; +} +namespace AZStd +{ + template + /*concept*/ constexpr bool signed_integral = integral && is_signed_v; + template + /*concept*/ constexpr bool unsigned_integral = integral && !signed_integral; + + template + /*concept*/ constexpr bool swappable = Internal::swappable_impl; + + template + /*concept*/ constexpr bool swappable_with = Internal::swappable_with_impl; +} + + +namespace AZStd::Internal +{ + // boolean-testable concept (exposition only in the C++standard) + template + constexpr bool boolean_testable_impl = convertible_to; + + template + constexpr bool boolean_testable = false; + template + constexpr bool boolean_testable && boolean_testable_impl())>>> = true; + + // weakly comparable ==, != + template + constexpr bool weakly_equality_comparable_with = false; + template + constexpr bool weakly_equality_comparable_with&>() == declval&>())> + && boolean_testable&>() != declval&>())> + && boolean_testable&>() == declval&>())> + && boolean_testable&>() != declval&>())> + >> = true; + + // partially ordered <, >, <=, >= + template + constexpr bool partially_ordered_with_impl = false; + template + constexpr bool partially_ordered_with_impl&>() < declval&>())> + && boolean_testable&>() > declval&>())> + && boolean_testable&>() <= declval&>())> + && boolean_testable&>() >= declval&>())> + && boolean_testable&>() < declval&>())> + && boolean_testable&>() > declval&>())> + && boolean_testable&>() <= declval&>())> + && boolean_testable&>() >= declval&>())> + >> = true; +} + +namespace AZStd +{ + template + /*concept*/ constexpr bool equality_comparable = Internal::weakly_equality_comparable_with; +} + +namespace AZStd::Internal +{ + // equally_comparable + partially ordered + template + constexpr bool equally_comparable_with_impl = false; + template + constexpr bool equally_comparable_with_impl + && equality_comparable + && common_reference_with&, const remove_reference_t&> + && equality_comparable&, const remove_reference_t&>> + && Internal::weakly_equality_comparable_with + >> = true; +} + +namespace AZStd +{ + template + /*concept*/ constexpr bool equality_comparable_with = Internal::equally_comparable_with_impl; + + template + /*concept*/ constexpr bool partially_ordered_with = Internal::partially_ordered_with_impl; + + template + /*concept*/ constexpr bool totally_ordered = equality_comparable && partially_ordered_with; +} + +namespace AZStd::Internal +{ + // equally_comparable + partially ordered + template + constexpr bool totally_ordered_with_impl = false; + template + constexpr bool totally_ordered_with_impl&& totally_ordered + && equality_comparable_with + && totally_ordered&, const remove_reference_t&>> + && partially_ordered_with + >> = true; +} + +namespace AZStd +{ + template + /*concept*/ constexpr bool totally_ordered_with = Internal::totally_ordered_with_impl; +} + +namespace AZStd::Internal +{ + template + inline constexpr bool is_default_initializable = false; + template + inline constexpr bool is_default_initializable> = true; + + template + constexpr bool default_initializable_impl = false; + template + constexpr bool default_initializable_impl < T, enable_if_t < constructible_from + && sfinae_trigger_v && Internal::is_default_initializable >> = true; + + template + constexpr bool movable_impl = false; + template + constexpr bool movable_impl && move_constructible && + assignable_from && swappable> > = true; + + template + constexpr bool copy_constructible_impl = false; + template + constexpr bool copy_constructible_impl && + constructible_from && convertible_to && + constructible_from && convertible_to && + constructible_from && convertible_to> > = true; +} + +namespace AZStd +{ + // movable + template + /*concept*/ constexpr bool movable = Internal::movable_impl; + + // default_initializable + template + /*concept*/ constexpr bool default_initializable = Internal::default_initializable_impl; + + // copy constructible + template + /*concept*/ constexpr bool copy_constructible = Internal::copy_constructible_impl; +} + +namespace AZStd::Internal +{ + template + constexpr bool copyable_impl = false; + template + constexpr bool copyable_impl && movable && assignable_from && + assignable_from && assignable_from> > = true; +} + +namespace AZStd +{ + // copyable + template + /*concept*/ constexpr bool copyable = Internal::copyable_impl; + + // semiregular + template + /*concept*/ constexpr bool semiregular = copyable && default_initializable; + + // regular + template + /*concept*/ constexpr bool regular = semiregular && equality_comparable; +} + +// Iterator Concepts +namespace AZStd::Internal +{ + template + constexpr bool is_integer_like = integral && !same_as; + + template + constexpr bool is_signed_integer_like = signed_integral; + + template + constexpr bool weakly_incrementable_impl = false; + template + constexpr bool weakly_incrementable_impl + && is_signed_integer_like> + && same_as()), T&> + && sfinae_trigger_v()++)> >> = true; +} + +namespace AZStd +{ + // models weakly_incrementable concept + template + /*concept*/ constexpr bool weakly_incrementable = Internal::weakly_incrementable_impl; + + // models input_or_output_iterator concept + template + /*concept*/ constexpr bool input_or_output_iterator = !is_void_v + && weakly_incrementable; +} + +namespace AZStd::Internal +{ + template + constexpr bool incrementable_impl = false; + template + constexpr bool incrementable_impl + && weakly_incrementable + && same_as()++), T> >> = true; +} + +namespace AZStd +{ + template + /*concept*/ constexpr bool incrementable = Internal::incrementable_impl; +} + +namespace AZStd +{ + template + /*concept*/ constexpr bool sentinel_for = semiregular && + input_or_output_iterator && + Internal::weakly_equality_comparable_with; + template + inline constexpr bool disable_sized_sentinel_for = false; +} + +namespace AZStd::Internal +{ + template + /*concept*/ constexpr bool sized_sentinel_for_impl = false; + template + /*concept*/ constexpr bool sized_sentinel_for_impl + && !disable_sized_sentinel_for, remove_cv_t> + && same_as() - declval()), iter_difference_t> + && same_as() - declval()), iter_difference_t> >> = true; +} + +namespace AZStd +{ + template + /*concept*/ constexpr bool sized_sentinel_for = Internal::sized_sentinel_for_impl; + + template + struct iterator_traits; +} + +namespace AZStd::Internal +{ + // ITER_CONCEPT(I) general concept + template + constexpr bool use_traits_iterator_concept_for_concept = false; + template + constexpr bool use_traits_iterator_concept_for_concept::iterator_concept>> = true; + + template + constexpr bool use_traits_iterator_category_for_concept = false; + template + constexpr bool use_traits_iterator_category_for_concept::iterator_category>> = !use_traits_iterator_concept_for_concept; + + template + constexpr bool use_random_access_iterator_tag_for_concept = false; + template + constexpr bool use_random_access_iterator_tag_for_concept>> = !use_traits_iterator_concept_for_concept + && !use_traits_iterator_category_for_concept; + + template + struct iter_concept; + + template + struct iter_concept>> + { + using type = typename iterator_traits::iterator_concept; + }; + template + struct iter_concept>> + { + using type = typename iterator_traits::iterator_category; + }; + + template + struct iter_concept>> + { + using type = random_access_iterator_tag; + }; + template + using iter_concept_t = typename iter_concept::type; +} + +namespace AZStd +{ + // indirectly readable + template + /*concept*/ constexpr bool indirectly_readable = Internal::indirectly_readable_impl>; +} + +namespace AZStd::Internal +{ + // model the indirectly writable concept + template + constexpr bool indirectly_writable_impl = false; + + template + constexpr bool indirectly_writable_impl() = declval()), + decltype(*declval() = declval()), + decltype(const_cast&&>(*declval()) = declval()), + decltype(const_cast&&>(*declval()) = declval())> + > = true; +} +namespace AZStd +{ + // indirectly writable + template + /*concept*/ constexpr bool indirectly_writable = Internal::indirectly_writable_impl; + + // indirectly movable + template + /*concept*/ constexpr bool indirectly_movable = indirectly_readable && indirectly_writable>; +} + +namespace AZStd::Internal +{ + template + constexpr bool indirectly_movable_storage_impl = false; + + template + constexpr bool indirectly_movable_storage_impl && + indirectly_writable> && + movable> && + constructible_from, iter_rvalue_reference_t> && + assignable_from&, iter_rvalue_reference_t>> > = true; +} + +namespace AZStd +{ + template + /*concept*/ constexpr bool indirectly_movable_storable = Internal::indirectly_movable_storage_impl; +} + +namespace AZStd::Internal +{ + template + constexpr bool indirectly_copyable_impl = false; + + template + constexpr bool indirectly_copyable_impl && + indirectly_writable>> > = true; +} + +namespace AZStd +{ + // indirectly copyable + template + /*concept*/ constexpr bool indirectly_copyable = Internal::indirectly_copyable_impl; +} +namespace AZStd::Internal +{ + template + constexpr bool indirectly_copyable_storable_impl = false; + + template + constexpr bool indirectly_copyable_storable_impl && + indirectly_writable&> && + indirectly_writable&> && + indirectly_writable&&> && + indirectly_writable&&> && + copyable> && + constructible_from, iter_reference_t> && + assignable_from&, iter_reference_t>> > = true; +} + +namespace AZStd +{ + template + /*concept*/ constexpr bool indirectly_copyable_storable = Internal::indirectly_copyable_storable_impl; +} + +namespace AZStd::ranges::Internal +{ + template + void iter_swap(I1, I2) = delete; + + template + constexpr bool iter_swap_adl = false; + + template + constexpr bool iter_swap_adl(), declval()))>> = true; + + template + constexpr bool is_class_or_enum_with_iter_swap_adl = false; + + template + constexpr bool is_class_or_enum_with_iter_swap_adl + && (is_class_v> || is_enum_v>) + && (is_class_v> || is_enum_v>)>> = true; + + struct iter_swap_fn + { + template + constexpr auto operator()(I1&& i1, I2&& i2) const + ->enable_if_t + > + { + iter_swap(AZStd::forward(i1), AZStd::forward(i2)); + } + template + constexpr auto operator()(I1&& i1, I2&& i2) const + ->enable_if_t + && indirectly_readable + && indirectly_readable + && swappable_with, iter_reference_t> + > + { + ranges::swap(*i1, *i2); + } + + template + constexpr auto operator()(I1&& i1, I2&& i2) const + ->enable_if_t + && indirectly_movable_storable + && indirectly_movable_storable + > + { + *AZStd::forward(i1) = iter_exchange_move(AZStd::forward(i2), AZStd::forward(i1)); + } + + private: + template + static constexpr iter_value_t iter_exchange_move(X&& x, Y&& y) + noexcept(noexcept(iter_value_t(iter_move(x))) && noexcept(*x = iter_move(y))) + { + iter_value_t old_value(iter_move(x)); + *x = iter_move(y); + return old_value; + } + }; +} + +namespace AZStd::ranges +{ + inline namespace customization_point_object + { + inline constexpr Internal::iter_swap_fn iter_swap{}; + } +} + + +namespace AZStd::Internal +{ + template + constexpr bool indirectly_swappable_impl = false; + template + constexpr bool indirectly_swappable_impl&& indirectly_readable + && sfinae_trigger_v< + decltype(AZStd::ranges::iter_swap(declval(), declval())), + decltype(AZStd::ranges::iter_swap(declval(), declval())), + decltype(AZStd::ranges::iter_swap(declval(), declval())), + decltype(AZStd::ranges::iter_swap(declval(), declval()))>>> = true; +} + +namespace AZStd +{ + template + /*concept*/ constexpr bool indirectly_swappable = Internal::indirectly_swappable_impl; +} + +namespace AZStd::Internal +{ + template + constexpr bool input_iterator_impl = false; + template + constexpr bool input_iterator_impl + && derived_from, input_iterator_tag> + && indirectly_readable + >> = true; +} + +namespace AZStd +{ + // input iterator + template + /*concept*/ constexpr bool input_iterator = Internal::input_iterator_impl; +} + +namespace AZStd::Internal +{ + template + constexpr bool output_iterator_impl = false; + template + constexpr bool output_iterator_impl + && indirectly_writable + && sfinae_trigger_v()++ = AZStd::declval())> + >> = true; +} + +namespace AZStd +{ + // output iterator + template + /*concept*/ constexpr bool output_iterator = Internal::output_iterator_impl; +} + +namespace AZStd::Internal +{ + template + constexpr bool forward_iterator_impl = false; + template + constexpr bool forward_iterator_impl + && derived_from, forward_iterator_tag> + && incrementable + && sentinel_for> > = true; +} + +namespace AZStd +{ + // forward_iterator + template + /*concept*/ constexpr bool forward_iterator = Internal::forward_iterator_impl; +} + +namespace AZStd::Internal +{ + template + constexpr bool bidirectional_iterator_impl = false; + template + constexpr bool bidirectional_iterator_impl + && derived_from, bidirectional_iterator_tag> + && same_as()), I&> + && same_as()--), I> >> = true; +} + +namespace AZStd +{ + // bidirectional iterator + template + /*concept*/ constexpr bool bidirectional_iterator = Internal::bidirectional_iterator_impl; +} + +namespace AZStd::Internal +{ + template + constexpr bool random_access_iterator_impl = false; + template + constexpr bool random_access_iterator_impl + && derived_from, random_access_iterator_tag> + && totally_ordered + && sized_sentinel_for + && same_as() += declval>()), I&> + && same_as() + declval>()), I> + && same_as>() + declval()), I> + && same_as() -= declval>()), I&> + && same_as() - declval>()), I> + && same_as()[declval>()]), iter_reference_t>>> + = true; +} + +namespace AZStd +{ + template + /*concept*/ constexpr bool random_access_iterator = Internal::random_access_iterator_impl; +} + +namespace AZStd::Internal +{ + template + constexpr bool contiguous_iterator_impl = false; + template + constexpr bool contiguous_iterator_impl + && derived_from, contiguous_iterator_tag> + && is_lvalue_reference_v> + && indirectly_readable + && same_as, remove_cvref_t>> + > > + = same_as())), add_pointer_t>>; +} + +namespace AZStd +{ + // contiguous iterator + template + /*concept*/ constexpr bool contiguous_iterator = Internal::contiguous_iterator_impl; +} + +namespace AZStd::Internal +{ + // models the predicate concept + template + constexpr bool predicate_impl = false; + template + constexpr bool predicate_impl = Internal::boolean_testable>; +} + +namespace AZStd +{ + // models the predicate concept + template + /*concept*/ constexpr bool predicate = Internal::predicate_impl, F, Args...>; + + // models the relation concept + template + /*concept*/ constexpr bool relation = predicate && predicate + && predicate && predicate; + + // models the equivalence_relation concept + template + /*concept*/ constexpr bool equivalence_relation = relation; + + // models the strict_weak_order concept + // Note: semantically this is different than equivalence_relation + template + /*concept*/ constexpr bool strict_weak_order = relation; +} diff --git a/Code/Framework/AzCore/AzCore/std/containers/deque.h b/Code/Framework/AzCore/AzCore/std/containers/deque.h index 9eed66aeb3..d34bdb6b5a 100644 --- a/Code/Framework/AzCore/AzCore/std/containers/deque.h +++ b/Code/Framework/AzCore/AzCore/std/containers/deque.h @@ -135,9 +135,10 @@ namespace AZStd AZ_FORCE_INLINE this_type& operator--() { --m_offset; return *this; } AZ_FORCE_INLINE this_type operator--(int) { this_type tmp = *this; --m_offset; return tmp; } AZ_FORCE_INLINE this_type& operator+=(difference_type offset) { m_offset += offset; return *this; } - AZ_FORCE_INLINE this_type operator+(difference_type offset) { this_type tmp = *this; tmp += offset; return tmp; } + AZ_FORCE_INLINE this_type operator+(difference_type offset) const { this_type tmp = *this; tmp += offset; return tmp; } + friend AZ_FORCE_INLINE this_type operator+(difference_type offset, const this_type& rhs) { this_type tmp = rhs; tmp += offset; return tmp; } AZ_FORCE_INLINE this_type& operator-=(difference_type offset) { m_offset -= offset; return *this; } - AZ_FORCE_INLINE this_type operator-(difference_type offset) { this_type tmp = *this; tmp -= offset; return tmp; } + AZ_FORCE_INLINE this_type operator-(difference_type offset) const { this_type tmp = *this; tmp -= offset; return tmp; } /// ??? AZ_FORCE_INLINE difference_type operator-(const this_type& rhs) const { @@ -197,9 +198,10 @@ namespace AZStd AZ_FORCE_INLINE this_type& operator--() { --base_type::m_offset; return *this; } AZ_FORCE_INLINE this_type operator--(int) { this_type tmp = *this; --base_type::m_offset; return tmp; } AZ_FORCE_INLINE this_type& operator+=(difference_type offset) { base_type::m_offset += offset; return *this; } - AZ_FORCE_INLINE this_type operator+(difference_type offset) { this_type tmp = *this; tmp += offset; return tmp; } + AZ_FORCE_INLINE this_type operator+(difference_type offset) const { this_type tmp = *this; tmp += offset; return tmp; } + friend AZ_FORCE_INLINE this_type operator+(difference_type offset, const this_type& rhs) { this_type tmp = rhs; tmp += offset; return tmp; } AZ_FORCE_INLINE this_type& operator-=(difference_type offset) { base_type::m_offset -= offset; return *this; } - AZ_FORCE_INLINE this_type operator-(difference_type offset) { this_type tmp = *this; tmp -= offset; return tmp; } + AZ_FORCE_INLINE this_type operator-(difference_type offset) const { this_type tmp = *this; tmp -= offset; return tmp; } AZ_FORCE_INLINE difference_type operator-(const this_type& rhs) const { return rhs.m_offset <= base_type::m_offset ? base_type::m_offset - rhs.m_offset : -(difference_type)(rhs.m_offset - base_type::m_offset); diff --git a/Code/Framework/AzCore/AzCore/std/containers/fixed_vector.h b/Code/Framework/AzCore/AzCore/std/containers/fixed_vector.h index 13f3ef2d7a..22edfbd927 100644 --- a/Code/Framework/AzCore/AzCore/std/containers/fixed_vector.h +++ b/Code/Framework/AzCore/AzCore/std/containers/fixed_vector.h @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -101,7 +102,7 @@ namespace AZStd::Internal //! Invokes destructor on all elements in range //! No-op on empty container //! Nothing to destroy since the storage is empty. - template >> + template >> static constexpr void unsafe_destroy(InputIt, InputIt) noexcept { } @@ -214,7 +215,7 @@ namespace AZStd::Internal //! Destructs elements in the range [begin, end). //! This does not modify the size of the storage //! This is a no-op for trivial types - template >> + template >> void unsafe_destroy(InputIt, InputIt) noexcept { } @@ -334,7 +335,7 @@ namespace AZStd::Internal //! Destructs elements in the range [begin, end). //! This does not modify the size of the storage //! Invokes the destuctor via the AZStd::destroy method - template >> + template >> void unsafe_destroy(InputIt first, InputIt last) noexcept(is_nothrow_destructible_v) { AZSTD_CONTAINER_ASSERT(first >= data() && first <= data() + size(), "begin iterator is not in range of storage"); @@ -410,7 +411,7 @@ namespace AZStd AZStd::uninitialized_fill_n(data(), numElements, value); } - template >> + template >> fixed_vector(InputIt first, InputIt last) { resize_no_construct(AZStd::distance(first, last)); @@ -615,7 +616,7 @@ namespace AZStd insert(end(), numElements, value); } - template >> + template >> void assign(InputIt first, InputIt last) { clear(); @@ -641,8 +642,18 @@ namespace AZStd return &newElement; } - AZStd::uninitialized_move(insertPosPtr, dataEnd, insertPosPtr + 1); + // We need to move data with care, it is overlapping. + + // first move the last element into the uninitialized position as that will not overlap. + pointer nonOverlap = dataEnd - 1; + AZStd::uninitialized_move(nonOverlap, dataEnd, dataEnd); + + // copy the memory backwards while performing AZStd::move on the existing elements the area with overlapping memory + // to move the elments to the right by 1 + AZStd::move_backward(insertPosPtr, nonOverlap, dataEnd); + // add new elements AZStd::construct_at(insertPosPtr, AZStd::forward(args)...); + resize_no_construct(size() + 1); return iterator(insertPosPtr); } iterator insert(const_iterator insertPos, const_reference value) @@ -707,7 +718,7 @@ namespace AZStd } } - template>> + template>> void insert(const_iterator insertPos, InputIt first, InputIt last) { // specialize for iterator categories. diff --git a/Code/Framework/AzCore/AzCore/std/containers/span.h b/Code/Framework/AzCore/AzCore/std/containers/span.h index fbf5f56870..d0ac704fc3 100644 --- a/Code/Framework/AzCore/AzCore/std/containers/span.h +++ b/Code/Framework/AzCore/AzCore/std/containers/span.h @@ -7,9 +7,37 @@ */ #pragma once -#include -#include #include +#include +#include +#include + +namespace AZStd +{ + inline constexpr size_t dynamic_extent = numeric_limits::max(); + + template + class span; +} + +namespace AZStd::Internal +{ + template + inline constexpr bool is_std_array = false; + + template + inline constexpr bool is_std_array<::AZStd::array> = true; + + template + inline constexpr bool is_std_span = false; + + template + inline constexpr bool is_std_span<::AZStd::span> = true; + + template + inline constexpr bool is_array_convertible = is_convertible_v; + +} namespace AZStd { @@ -33,97 +61,149 @@ namespace AZStd * * Since the span does not copy and store any data, it is only valid as long as the data used to create it is valid. */ - template - class span final + template + class span { public: using element_type = T; using value_type = AZStd::remove_cv_t; - - using pointer = T*; - using const_pointer = const T*; - - using reference = T&; - using const_reference = const T&; - using size_type = AZStd::size_t; using difference_type = AZStd::ptrdiff_t; - using iterator = T*; - using const_iterator = const T*; + using pointer = element_type*; + using const_pointer = const element_type*; + + using reference = element_type&; + using const_reference = const element_type&; + + + using iterator = element_type*; + using const_iterator = const element_type*; using reverse_iterator = AZStd::reverse_iterator; using const_reverse_iterator = AZStd::reverse_iterator; - constexpr span(); + inline static constexpr size_t extent = Extent; + + constexpr span() noexcept = default;; ~span() = default; - constexpr span(pointer s, size_type length); + template && + Internal::is_array_convertible>, T> && + Extent == dynamic_extent>* = nullptr> + constexpr span(It first, size_type length); - constexpr span(pointer first, pointer last); + template && + Internal::is_array_convertible>, T> && + Extent != dynamic_extent, int> = 0> + constexpr explicit span(It first, size_type length); - // We explicitly delete this constructor because it's too easy to accidentally - // create a span to just the first element instead of an entire array. - constexpr span(const_pointer s) = delete; + template && + Internal::is_array_convertible>, T> && + sized_sentinel_for && + Extent == dynamic_extent>* = nullptr> + constexpr span(It first, End last); - template - constexpr span(Container& data); + template && + Internal::is_array_convertible>, T> && + sized_sentinel_for && + Extent != dynamic_extent, int> = 0> + constexpr explicit span(It first, End last); - template - constexpr span(const Container& data); + template> + constexpr span(type_identity_t (&arr)[N]) noexcept; - constexpr span(const span&) = default; + template > + constexpr span(array& data) noexcept; + template > + constexpr span(const array& data) noexcept; - constexpr span(span&& other); + template && + ranges::sized_range && + (ranges::borrowed_range || is_const_v) && + !Internal::is_std_span> && + !Internal::is_std_array> && + !is_array_v> && + Internal::is_array_convertible>, element_type> >> + constexpr span(R&& r); + + template >> + constexpr span(const span& other); + + constexpr span(const span&) noexcept = default; constexpr span& operator=(const span& other) = default; - constexpr span& operator=(span&& other); + // subviews -> https://eel.is/c++draft/views#span.sub + template + constexpr span first() const; + template + constexpr span last() const; + template + constexpr auto subspan() const; - constexpr size_type size() const; + constexpr span first(size_type count) const; + constexpr span last(size_type count) const; + constexpr span subspan(size_type offset, size_type count = dynamic_extent) const; - constexpr bool empty() const; + // observers - https://eel.is/c++draft/views#span.obs + constexpr size_type size() const noexcept; + constexpr size_type size_bytes() const noexcept; - constexpr pointer data(); - constexpr const_pointer data() const; + [[nodiscard]] constexpr bool empty() const noexcept; - constexpr const_reference operator[](size_type index) const; - constexpr reference operator[](size_type index); + // element access - https://eel.is/c++draft/views#span.elem + constexpr reference operator[](size_type index) const; + constexpr reference front() const; + constexpr reference back() const; + constexpr pointer data() const noexcept; - constexpr void erase(); + // iterator support - https://eel.is/c++draft/views#span.iterators + constexpr iterator begin() const noexcept; + constexpr iterator end() const noexcept; - constexpr iterator begin(); - constexpr iterator end(); - constexpr const_iterator begin() const; - constexpr const_iterator end() const; - - constexpr const_iterator cbegin() const; - constexpr const_iterator cend() const; - - constexpr reverse_iterator rbegin(); - constexpr reverse_iterator rend(); - constexpr const_reverse_iterator rbegin() const; - constexpr const_reverse_iterator rend() const; - - constexpr const_reverse_iterator crbegin() const; - constexpr const_reverse_iterator crend() const; - - friend bool operator==(span lhs, span rhs) - { - return lhs.m_begin == rhs.m_begin && lhs.m_end == rhs.m_end; - } - - friend bool operator!=(span lhs, span rhs) { return !(lhs == rhs); } - friend bool operator< (span lhs, span rhs) { return lhs.m_begin < rhs.m_begin || lhs.m_begin == rhs.m_begin && lhs.m_end < rhs.m_end; } - friend bool operator> (span lhs, span rhs) { return lhs.m_begin > rhs.m_begin || lhs.m_begin == rhs.m_begin && lhs.m_end > rhs.m_end; } - friend bool operator<=(span lhs, span rhs) { return lhs == rhs || lhs < rhs; } - friend bool operator>=(span lhs, span rhs) { return lhs == rhs || lhs > rhs; } + constexpr reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() const noexcept; private: - pointer m_begin; - pointer m_end; + pointer m_data{}; + size_type m_size{}; }; + // deduction guides https://eel.is/c++draft/views#span.deduct + template >> + span(It, EndOrSize) -> span>>; + + // array deductions + template + span(T(&)[N]) -> span; + template + span(array&) -> span; + template + span(const array&) -> span; + + template >> + span(R&&) -> span>>; + + // [span.objectrep], views of object representation + template + auto as_bytes(span s) noexcept + -> span; + + template + auto as_writable_bytes(span s) noexcept + -> enable_if_t, span>; + } // namespace AZStd +namespace AZStd::ranges +{ + template + inline constexpr bool enable_view> = true; + template + inline constexpr bool enable_borrowed_range> = true; +} + #include diff --git a/Code/Framework/AzCore/AzCore/std/containers/span.inl b/Code/Framework/AzCore/AzCore/std/containers/span.inl index 2b24a11fc3..765056cb67 100644 --- a/Code/Framework/AzCore/AzCore/std/containers/span.inl +++ b/Code/Framework/AzCore/AzCore/std/containers/span.inl @@ -9,116 +9,206 @@ namespace AZStd { - template - inline constexpr span::span() - : m_begin(nullptr) - , m_end(nullptr) - { } + template + template && + Internal::is_array_convertible>, T> && + Extent == dynamic_extent>*> + inline constexpr span::span(It first, size_type length) + : m_data{ to_address(first) } + , m_size{ length } + {} - template - inline constexpr span::span(pointer s, size_type length) - : m_begin(s) - , m_end(m_begin + length) + template + template && + Internal::is_array_convertible>, T> && + Extent != dynamic_extent, int>> + inline constexpr span::span(It first, size_type length) + : m_data{ to_address(first) } + , m_size{ length } + {} + + template + template && + Internal::is_array_convertible>, T> && + sized_sentinel_for && + Extent == dynamic_extent>*> + inline constexpr span::span(It first, End last) + : m_data{to_address(first)} + , m_size(last - first) + {} + + template + template && + Internal::is_array_convertible>, T> && + sized_sentinel_for && + Extent != dynamic_extent, int>> + inline constexpr span::span(It first, End last) + : m_data{to_address(first)} + , m_size(last - first) + {} + + template + template + inline constexpr span::span(type_identity_t(&arr)[N]) noexcept + : m_data{ arr } + , m_size{ N } + {} + + template + template + inline constexpr span::span(array& arr) noexcept + : m_data{ arr.data() } + , m_size{ arr.size() } + {} + template + template + inline constexpr span::span(const array& arr) noexcept + : m_data{ arr.data() } + , m_size{ arr.size() } + {} + + template + template + inline constexpr span::span(R&& r) + : m_data{ ranges::data(r) } + , m_size{ ranges::size(r) } { - if (length == 0) erase(); + AZ_Assert(Extent == dynamic_extent || Extent == m_size, "The extent of the span is non dynamic," + " therefore the range size must match the extent. Extent=%zu, Range size=%zu", + Extent, ranges::size(r)); } - template - inline constexpr span::span(pointer first, pointer last) - : m_begin(first) - , m_end(last) - { } - - template - template - inline constexpr span::span(Container& data) - : m_begin(data.data()) - , m_end(m_begin + data.size()) - { } - - template - template - inline constexpr span::span(const Container& data) - : m_begin(data.data()) - , m_end(m_begin + data.size()) - { } - - template - inline constexpr span::span(span&& other) - : span(other.m_begin, other.m_end) + template + template + inline constexpr span::span(const span& other) + : m_data{ other.data() } + , m_size{ other.size() } { -#if AZ_DEBUG_BUILD // Clearing the original pointers isn't necessary, but is good for debugging - other.m_begin = nullptr; - other.m_end = nullptr; -#endif + AZ_Assert(Extent == dynamic_extent || Extent == m_size, "The extent of the span is non dynamic," + " therefore the current size of the other span must match the extent. Extent=%zu, Other span size=%zu", + Extent, other.size()); } - template - inline constexpr AZStd::size_t span::size() const { return m_end - m_begin; } - - template - inline constexpr bool span::empty() const { return m_end == m_begin; } - - template - inline constexpr Element* span::data() { return m_begin; } - - template - inline constexpr const Element* span::data() const { return m_begin; } - - template - inline constexpr span& span::operator=(span&& other) + // subviews + template + template + inline constexpr auto span::first() const -> span { - m_begin = other.m_begin; - m_end = other.m_end; -#if AZ_DEBUG_BUILD // Clearing the original pointers isn't necessary, but is good for debugging - other.m_begin = nullptr; - other.m_end = nullptr; -#endif - return *this; + static_assert(Count <= Extent, "Count is larger than the Extent of the span, a subview of the first" + " Count elemnts of the span cannot be returned"); + AZ_Assert(Count <= size(), "Count %zu is larger than span size %zu", Count, size()); + return span{data(), Count}; } - - template - inline constexpr const Element& span::operator[](AZStd::size_t index) const + template + inline constexpr auto span::first(size_type count) const -> span + { + AZ_Assert(count <= size(), "Count %zu is larger than current size of span size %zu", count, size()); + return { data(), count }; + } + + template + template + inline constexpr auto span::last() const -> span + { + static_assert(Count <= Extent, "Count is larger than the Extent of the span, a subview of the last" + " Count elements of the span cannot be returned"); + AZ_Assert(Count <= size(), "Count %zu is larger than span size %zu", Count, size()); + return span{data() + (size() - Count), Count}; + } + template + inline constexpr auto span::last(size_type count) const -> span + { + AZ_Assert(count <= size(), "Count %zu is larger than span size %zu", count, size()); + return { data() + (size() - count), count }; + } + + template + template + inline constexpr auto span::subspan() const + { + static_assert(Offset <= Extent && (Count == dynamic_extent || Count <= Extent - Offset), + "Subspan Offset must <= span Extent and the Count must be either dynamic_extent" + " or <= (span Extent - Offset)"); + AZ_Assert(Offset <= size() && (Count == dynamic_extent || Count <= size() - Offset), + "Either the Subspan Offset %zu is larger than the span size %zu or the Count != dynamic_extent and" + " its value %zu is greater than \"span size - Offset\" %zu", + Offset, size(), Count, size() - Offset); + using return_type = span; + return return_type{ data() + Offset, Count != dynamic_extent ? Count : size() - Offset }; + } + + template + inline constexpr auto span::subspan(size_type offset, size_type count) const -> span + { + AZ_Assert(offset <= size() && (count == dynamic_extent || count <= size() - offset), + "Either the Subspan offset %zu is larger than the span size %zu or the count != dynamic_extent and" + " its value %zu is greater than \"span size - offset\" %zu", + offset, size(), count, size() - offset); + return { data() + offset, count != dynamic_extent ? count : size() - offset }; + } + + + // observers + template + inline constexpr auto span::size() const noexcept -> size_type { return m_size; } + + template + inline constexpr auto span::size_bytes() const noexcept -> size_type { return m_size * sizeof(element_type); } + + template + [[nodiscard]] inline constexpr bool span::empty() const noexcept{ return size() == 0; } + + // element access + template + inline constexpr auto span::operator[](size_type index) const -> reference { AZ_Assert(index < size(), "index value is out of range"); - return m_begin[index]; + return data()[index]; } - template - inline constexpr Element& span::operator[](AZStd::size_t index) + template + inline constexpr auto span::front() const -> reference { - AZ_Assert(index < size(), "index value is out of range"); - return m_begin[index]; + AZ_Assert(!empty(), "span cannot be empty when invoking front"); + return *data(); } - template - inline constexpr void span::erase() { m_begin = m_end = nullptr; } - - template - inline constexpr Element* span::begin() { return m_begin; } - template - inline constexpr Element* span::end() { return m_end; } - template - inline constexpr const Element* span::begin() const { return m_begin; } - template - inline constexpr const Element* span::end() const { return m_end; } + template + inline constexpr auto span::back() const -> reference + { + AZ_Assert(!empty(), "span cannot be empty when invoking back"); + return *(data() + (size() - 1)); + } - template - inline constexpr const Element* span::cbegin() const { return m_begin; } - template - inline constexpr const Element* span::cend() const { return m_end; } + // iterator support + template + inline constexpr auto span::data() const noexcept -> pointer { return m_data; } - template - inline constexpr AZStd::reverse_iterator span::rbegin() { return AZStd::reverse_iterator(m_end); } - template - inline constexpr AZStd::reverse_iterator span::rend() { return AZStd::reverse_iterator(m_begin); } - template - inline constexpr AZStd::reverse_iterator span::rbegin() const { return AZStd::reverse_iterator(m_end); } - template - inline constexpr AZStd::reverse_iterator span::rend() const { return AZStd::reverse_iterator(m_begin); } + template + inline constexpr auto span::begin() const noexcept -> iterator{ return m_data; } + template + inline constexpr auto span::end() const noexcept -> iterator { return m_data + m_size; } - template - inline constexpr AZStd::reverse_iterator span::crbegin() const { return AZStd::reverse_iterator(cend()); } - template - inline constexpr AZStd::reverse_iterator span::crend() const { return AZStd::reverse_iterator(cbegin()); } + template + inline constexpr auto span::rbegin() const noexcept -> reverse_iterator { return AZStd::make_reverse_iterator(end()); } + template + inline constexpr auto span::rend() const noexcept -> reverse_iterator { return AZStd::make_reverse_iterator(begin()); } + + + template + inline auto as_bytes(span s) noexcept + -> span + { + return span( + reinterpret_cast(s.data()), s.size_bytes()); + } + + + template + inline auto as_writable_bytes(span s) noexcept + -> enable_if_t, span> + { + return span( + reinterpret_cast(s.data()), s.size_bytes()); + } } // namespace AZStd diff --git a/Code/Framework/AzCore/AzCore/std/createdestroy.h b/Code/Framework/AzCore/AzCore/std/createdestroy.h index 355374a13a..2f5c7fde92 100644 --- a/Code/Framework/AzCore/AzCore/std/createdestroy.h +++ b/Code/Framework/AzCore/AzCore/std/createdestroy.h @@ -7,22 +7,19 @@ */ #pragma once +#include #include #include #include #include #include #include -#include #include #include #include // AZStd::addressof namespace AZStd { - // alias std::pointer_traits into the AZStd::namespace - using std::pointer_traits; - //! Bring the names of uninitialized_default_construct and //! uninitialized_default_construct_n into the AZStd namespace using std::uninitialized_default_construct; @@ -34,42 +31,6 @@ namespace AZStd using std::uninitialized_value_construct_n; } -namespace AZStd::Internal -{ - template - constexpr bool pointer_traits_has_to_address_v = false; - template - constexpr bool pointer_traits_has_to_address_v::to_address(declval()))>> = true; -} - -namespace AZStd -{ - //! Implements the C++20 to_address function - //! This obtains the address represented by ptr without forming a reference - //! to the pointee type - template - constexpr T* to_address(T* ptr) noexcept - { - static_assert(!AZStd::is_function_v, "Invoking to address on a function pointer is not allowed"); - return ptr; - } - //! Fancy pointer overload which delegates to using a specialization of pointer_traits::to_address - //! if that is a well-formed expression, otherwise it returns ptr->operator->() - //! For example invoking `to_address(AZStd::reverse_iterator(char_ptr))` - //! Returns an element of type const char* - template - constexpr auto to_address(const T& ptr) noexcept - { - if constexpr (AZStd::Internal::pointer_traits_has_to_address_v) - { - return pointer_traits::to_address(ptr); - } - else - { - return AZStd::to_address(ptr.operator->()); - } - } -} namespace AZStd::Internal { /** @@ -81,7 +42,7 @@ namespace AZStd::Internal /** * Type has trivial destructor. We don't call it. */ - template ::value_type, bool = is_trivially_destructible_v> + template , bool = is_trivially_destructible_v> struct destroy { static constexpr void range(InputIterator first, InputIterator last) { (void)first; (void)last; } @@ -163,7 +124,7 @@ namespace AZStd::Internal * Default object construction. */ // placement new isn't a core constant expression therefore it cannot be used in a constexpr function - template::value_type, + template, bool = is_trivially_constructible_v> struct construct { @@ -242,93 +203,125 @@ namespace AZStd::Internal ////////////////////////////////////////////////////////////////////////// // Sequence copy. If we use optimized version we use memcpy. /** - * Helper class to determine if we have apply fast copy. There are 2 conditions + * Class to determine if we have apply fast copy. There are 2 conditions * - trivial copy ctor. - * - all iterators satisfy the C++20 are contiguous iterator concept: pointers or iterator classes with - * the iterator_concept typedef set to contiguous_iterator_tag + * - all iterators satisfy the C++20 are contiguous iterator concept */ + template + constexpr bool indirectly_trivially_copyable = false; + template + constexpr bool indirectly_trivially_copyable>> = is_trivially_copyable_v>; + template - struct is_fast_copy_helper - { - using value_type = typename iterator_traits::value_type; - static constexpr bool value = AZStd::is_trivially_copyable_v - && Internal::satisfies_contiguous_iterator_concept_v - && Internal::satisfies_contiguous_iterator_concept_v; - }; + using is_fast_copy = bool_constant + && contiguous_iterator + && contiguous_iterator + >; - // Use this trait to to determine copy mode, based on the iterator category and object copy properties, - // Use it when when you call uninitialized_copy, Internal::copy, Internal::move, etc. - template< typename InputIterator, typename ResultIterator > - struct is_fast_copy - : public ::AZStd::integral_constant::value> {}; + template + constexpr bool is_fast_copy_v = is_fast_copy::value; + + // is_fast_copy argument is no longer used. template - constexpr ForwardIterator copy(const InputIterator& first, const InputIterator& last, ForwardIterator result, const false_type& /* is_fast_copy() */) + constexpr ForwardIterator copy(InputIterator first, InputIterator last, ForwardIterator result, bool) { - InputIterator iter(first); - for (; iter != last; ++result, ++iter) + if constexpr (is_fast_copy_v) { - *result = *iter; - } + // Specialized copy for contiguous iterators which are trivially copyable + size_t numElements = last - first; + if (numElements > 0) + { +#if az_has_builtin_memcpy + static_assert(sizeof(iter_value_t) == sizeof(iter_value_t), "Size of value types must match for a trivial copy"); + __builtin_memcpy(to_address(result), to_address(first), numElements * sizeof(iter_value_t)); +#else + if (az_builtin_is_constant_evaluated()) + { + for (; first != last; ++result, ++first) + { + *result = *first; + } - return result; + return result; + } + else + { + static_assert(sizeof(iter_value_t) == sizeof(iter_value_t), "Size of value types must match for a trivial copy"); + AZ_Assert((static_cast(&*result) < static_cast(&*first)) + || (static_cast(&*result) >= static_cast(&*first + numElements)), + "AZStd::copy memory overlaps use AZStd::copy_backward!"); + ::memcpy(to_address(result), to_address(first), numElements * sizeof(iter_value_t)); + } +#endif + } + return result + numElements; + } + else + { + for (; first != last; ++result, ++first) + { + *result = *first; + } + + return result; + } } - // Specialized copy for contiguous iterators (pointers) and trivial copy type. - // This overload cannot be constexpr until builtin_memcpy is added to MSVC compilers - template - inline ForwardIterator copy(const InputIterator& first, const InputIterator& last, ForwardIterator result, const true_type& /* is_fast_copy() */) - { - // \todo Make sure memory ranges don't overlap, otherwise people should use move and move_backward. - static_assert(sizeof(typename iterator_traits::value_type) == sizeof(typename iterator_traits::value_type), "Size of value types must match for a trivial copy"); - AZStd::size_t numElements = last - first; - if (numElements > 0) - { - AZ_Assert((static_cast(&*result) < static_cast(&*first)) || (static_cast(&*result) >= static_cast(&*first + numElements)), "AZStd::copy memory overlaps use AZStd::copy_backward!"); - AZ_Assert((static_cast(&*result + numElements) <= static_cast(&*first)) || (static_cast(&*result + numElements) > static_cast(&*first + numElements)), "AZStd::copy memory overlaps use AZStd::copy_backward!"); - /*AZSTD_STL::*/ memcpy(&*result, &*first, numElements * sizeof(typename iterator_traits::value_type)); - } - return result + numElements; - } // Copy backward. template - constexpr BidirectionalIterator2 copy_backward(const BidirectionalIterator1& first, const BidirectionalIterator1& last, BidirectionalIterator2 result, const false_type& /* is_fast_copy() */) + constexpr BidirectionalIterator2 copy_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 result, bool) { - BidirectionalIterator1 iter(last); - while (first != iter) + if constexpr (is_fast_copy_v) { - *--result = *--iter; + // Specialized copy for contiguous iterators which are trivially copyable + size_t numElements = last - first; + if (numElements > 0) + { +#if az_has_builtin_memmove + static_assert(sizeof(iter_value_t) == sizeof(iter_value_t), "Size of value types must match for a trivial copy"); + result -= numElements; + __builtin_memmove(to_address(result), to_address(first), numElements * sizeof(iter_value_t)); +#else + if (az_builtin_is_constant_evaluated()) + { + while (first != last) + { + *--result = *--last; + } + + return result; + } + else + { + static_assert(sizeof(iter_value_t) == sizeof(iter_value_t), "Size of value types must match for a trivial copy"); + result -= numElements; + AZ_Assert(((&*result + numElements) <= &*first) || ((&*result + numElements) > (&*first + numElements)), "AZStd::copy_backward memory overlaps use AZStd::copy!"); + ::memmove(&*result, &*first, numElements * sizeof(iter_value_t)); + } +#endif + } + return result; } - - return result; - } - - // Specialized copy for contiguous iterators (pointers) and trivial copy type. - // This overload cannot be constexpr until builtin_memcpy is added to MSVC compilers - template - inline BidirectionalIterator2 copy_backward(const BidirectionalIterator1& first, const BidirectionalIterator1& last, BidirectionalIterator2 result, const true_type& /* is_fast_copy() */) - { - // \todo Make sure memory ranges don't overlap, otherwise people should use move and move_backward. - static_assert(sizeof(typename iterator_traits::value_type) == sizeof(typename iterator_traits::value_type), "Size of value types must match for a trivial copy"); - AZStd::size_t numElements = last - first; - if (numElements > 0) + else { - result -= numElements; - AZ_Assert((&*result < &*first) || (&*result >= (&*first + numElements)), "AZStd::copy_backward memory overlaps use AZStd::copy!"); - AZ_Assert(((&*result + numElements) <= &*first) || ((&*result + numElements) > (&*first + numElements)), "AZStd::copy_backward memory overlaps use AZStd::copy!"); - /*AZSTD_STL::*/ memcpy(&*result, &*first, numElements * sizeof(typename iterator_traits::value_type)); + while (first != last) + { + *--result = *--last; + } + + return result; } - return result; } template - constexpr ForwardIterator reverse_copy(const BidirectionalIterator1& first, const BidirectionalIterator1& last, ForwardIterator dest) + constexpr ForwardIterator reverse_copy(BidirectionalIterator1 first, BidirectionalIterator1 last, ForwardIterator dest) { - BidirectionalIterator1 iter(last); - while (iter != first) + while (last != first) { - *(dest++) = *(--iter); + *(dest++) = *(--last); } return dest; @@ -342,143 +335,209 @@ namespace AZStd * Specialized algorithms 20.4.4. We extend that by adding faster specialized versions when we have trivial assign type. */ template - constexpr ForwardIterator uninitialized_copy(const InputIterator& first, const InputIterator& last, ForwardIterator result, const false_type& /* is_fast_copy() */) + constexpr ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result, bool) { - InputIterator iter(first); - for (; iter != last; ++result, ++iter) + // Specialized copy for contiguous iterators which are trivially copyable + if constexpr (Internal::is_fast_copy_v) { - ::new (static_cast(&*result)) typename iterator_traits::value_type(*iter); - } + size_t numElements = last - first; + if (numElements > 0) + { +#if az_has_builtin_memcpy + static_assert(sizeof(iter_value_t) == sizeof(iter_value_t), "Value type sizes must match for a trivial copy"); + __builtin_memcpy(to_address(result), to_address(first), numElements * sizeof(iter_value_t)); +#else + if (az_builtin_is_constant_evaluated()) + { + for (; first != last; ++result, ++first) + { + construct_at(static_cast*>(to_address(result)), *first); + } - return result; + return result; + } + else + { + static_assert(sizeof(iter_value_t) == sizeof(iter_value_t), "Value type sizes must match for a trivial copy"); + ::memcpy(to_address(result), to_address(first), numElements * sizeof(iter_value_t)); + } +#endif + } + return result + numElements; + } + else + { + for (; first != last; ++result, ++first) + { + construct_at(static_cast*>(to_address(result)), *first); + } + + return result; + } } - // Specialized copy for contiguous iterators and trivial copy type. - // This overload cannot be constexpr until builtin_memcpy is added to MSVC compilers - template - inline ForwardIterator uninitialized_copy(const InputIterator& first, const InputIterator& last, ForwardIterator result, const true_type& /* is_fast_copy() */) - { - static_assert(sizeof(typename iterator_traits::value_type) == sizeof(typename iterator_traits::value_type), "Value type sizes must match for a trivial copy"); - AZStd::size_t numElements = last - first; - if (numElements > 0) - { - /*AZSTD_STL::*/ - memcpy(&*result, &*first, numElements * sizeof(typename iterator_traits::value_type)); - } - return result + numElements; - } template - constexpr ForwardIterator uninitialized_copy(const InputIterator& first, const InputIterator& last, ForwardIterator result) + constexpr ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result) { - return uninitialized_copy(first, last, result, Internal::is_fast_copy()); + return uninitialized_copy(first, last, result, {}); } // 25.3.1 Copy template constexpr OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result) { - return AZStd::Internal::copy(first, last, result, AZStd::Internal::is_fast_copy()); + return Internal::copy(first, last, result, {}); } template constexpr OutputIterator reverse_copy(BidirectionalIterator first, BidirectionalIterator last, OutputIterator dest) { - return AZStd::Internal::reverse_copy(first, last, dest); + return Internal::reverse_copy(first, last, dest); } template BidirectionalIterator2 copy_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 result) { - return AZStd::Internal::copy_backward(first, last, result, AZStd::Internal::is_fast_copy()); + return Internal::copy_backward(first, last, result, {}); } } namespace AZStd::Internal { ////////////////////////////////////////////////////////////////////////// - // Sequence move. If we use optimized version we use memmove. + // Sequence move template - constexpr ForwardIterator move(const InputIterator& first, const InputIterator& last, ForwardIterator result, const false_type& /* is_fast_copy() */) + constexpr ForwardIterator move(InputIterator first, InputIterator last, ForwardIterator result, bool) { - InputIterator iter(first); - for (; iter != last; ++result, ++iter) + // Specialized copy for contiguous iterators which are trivially copyable + if constexpr (is_fast_copy_v) { - *result = AZStd::move(*iter); + size_t numElements = last - first; + if (numElements > 0) + { +#if az_has_builtin_memcpy + static_assert(sizeof(iter_value_t) == sizeof(iter_value_t), "Size of value types must match for a trivial copy"); + __builtin_memcpy(to_address(result), to_address(first), numElements * sizeof(iter_value_t)); +#else + if (az_builtin_is_constant_evaluated()) + { + for (; first != last; ++result, ++first) + { + *result = ::AZStd::move(*first); + } + return result; + } + else + { + static_assert(sizeof(iter_value_t) == sizeof(iter_value_t), "Size of value types must match for a trivial copy"); + AZ_Assert((static_cast(&*result) < static_cast(&*first)) + || (static_cast(&*result) >= static_cast(&*first + numElements)), + "AZStd::move memory overlaps use AZStd::move_backward!"); + ::memcpy(to_address(result), to_address(first), numElements * sizeof(iter_value_t)); + } +#endif + } + return result + numElements; + } + else + { + for (; first != last; ++result, ++first) + { + *result = ::AZStd::move(*first); + } + return result; } - return result; } - // Specialized copy for contiguous iterators (pointers) and trivial copy type. - // This overload cannot be constexpr until builtin_memmove is added to MSVC compilers - template - inline ForwardIterator move(const InputIterator& first, const InputIterator& last, ForwardIterator result, const true_type& /* is_fast_copy() */) - { - static_assert(sizeof(typename iterator_traits::value_type) == sizeof(typename iterator_traits::value_type), "Size of value types must match for a trivial copy"); - AZStd::size_t numElements = last - first; - if (numElements > 0) - { - /*AZSTD_STL::*/ - memmove(&*result, &*first, numElements * sizeof(typename iterator_traits::value_type)); - } - return result + numElements; - } // For generic iterators, move is the same as copy. template - constexpr BidirectionalIterator2 move_backward(const BidirectionalIterator1& first, const BidirectionalIterator1& last, BidirectionalIterator2 result, const false_type& /* is_fast_copy() */) + constexpr BidirectionalIterator2 move_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 result, bool) { - BidirectionalIterator1 iter(last); - while (first != iter) + // Specialized copy for contiguous iterators which are trivially copyable + if constexpr (is_fast_copy_v) { - *--result = AZStd::move(*--iter); + size_t numElements = last - first; + if (numElements > 0) + { +#if az_has_builtin_memmove + static_assert(sizeof(iter_value_t) == sizeof(iter_value_t), "Size of value types must match for a trivial copy"); + result -= numElements; + __builtin_memmove(to_address(result), to_address(first), numElements * sizeof(iter_value_t)); +#else + if (az_builtin_is_constant_evaluated()) + { + while (first != last) + { + *--result = ::AZStd::move(*--last); + } + return result; + } + else + { + static_assert(sizeof(iter_value_t) == sizeof(iter_value_t), "Size of value types must match for a trivial copy"); + result -= numElements; + AZ_Assert((static_cast(&*result + numElements) <= static_cast(&*first)) + || (static_cast(&*result + numElements) > static_cast(&*first + numElements)), + "AZStd::move_backward memory overlaps use AZStd::move!"); + ::memmove(to_address(result), to_address(first), numElements * sizeof(iter_value_t)); + } +#endif + } + return result; } - return result; - } - - // Specialized copy for contiguous iterators (pointers) and trivial copy type. - // This overload cannot be constexpr until builtin_memmove is added to MSVC compilers - template - inline BidirectionalIterator2 move_backward(const BidirectionalIterator1& first, const BidirectionalIterator1& last, BidirectionalIterator2 result, const true_type& /* is_fast_copy() */) - { - // \todo Make sure memory ranges don't overlap, otherwise people should use move and move_backward. - static_assert(sizeof(typename iterator_traits::value_type) == sizeof(typename iterator_traits::value_type), "Size of value types must match for a trivial copy"); - AZStd::size_t numElements = last - first; - result -= numElements; - if (numElements > 0) + else { - /*AZSTD_STL::*/ - memmove(&*result, &*first, numElements * sizeof(typename iterator_traits::value_type)); + while (first != last) + { + *--result = ::AZStd::move(*--last); + } + return result; } - return result; } template - constexpr ForwardIterator uninitialized_move(const InputIterator& first, const InputIterator& last, ForwardIterator result, const false_type& /* is_fast_copy() */) + constexpr ForwardIterator uninitialized_move(InputIterator first, InputIterator last, ForwardIterator result, bool) { - InputIterator iter(first); - - for (; iter != last; ++result, ++iter) + // Specialized copy for contiguous iterators which are trivially copyable + if constexpr (is_fast_copy_v) { - ::new (static_cast(&*result)) typename iterator_traits::value_type(AZStd::move(*iter)); - } - return result; - } - // Specialized copy for contiguous iterators and trivial move type. (since the object is POD we will just perform a copy) - // This overload cannot be constexpr until builtin_memcpy is added to MSVC compilers - template - inline ForwardIterator uninitialized_move(const InputIterator& first, const InputIterator& last, ForwardIterator result, const true_type& /* is_fast_copy() */) - { - static_assert(sizeof(typename iterator_traits::value_type) == sizeof(typename iterator_traits::value_type), "Value type sizes must match for a trivial copy"); - AZStd::size_t numElements = last - first; - if (numElements > 0) - { - /*AZSTD_STL::*/ - memcpy(&*result, &*first, numElements * sizeof(typename iterator_traits::value_type)); - } - return result + numElements; - } + size_t numElements = last - first; + if (numElements > 0) + { +#if az_has_builtin_memcpy + static_assert(sizeof(iter_value_t) == sizeof(iter_value_t), "Value type sizes must match for a trivial copy"); + __builtin_memcpy(to_address(result), to_address(first), numElements * sizeof(iter_value_t)); +#else + if (az_builtin_is_constant_evaluated()) + { + for (; first != last; ++result, ++first) + { + construct_at(static_cast*>(to_address(result)), ::AZStd::move(*first)); + } + return result; + } + else + { + static_assert(sizeof(iter_value_t) == sizeof(iter_value_t), "Value type sizes must match for a trivial copy"); + ::memcpy(to_address(result), to_address(first), numElements * sizeof(iter_value_t)); + } +#endif + } + return result + numElements; + } + else + { + for (; first != last; ++result, ++first) + { + construct_at(static_cast*>(to_address(result)), ::AZStd::move(*first)); + } + + return result; + } + } // end of sequence move. ////////////////////////////////////////////////////////////////////////// } @@ -492,19 +551,19 @@ namespace AZStd template ForwardIt uninitialized_move(InputIt first, InputIt last, ForwardIt result) { - return AZStd::Internal::uninitialized_move(first, last, result, AZStd::Internal::is_fast_copy{}); + return AZStd::Internal::uninitialized_move(first, last, result, {}); } // 25.3.2 Move template OutputIterator move(InputIterator first, InputIterator last, OutputIterator result) { - return AZStd::Internal::move(first, last, result, AZStd::Internal::is_fast_copy()); + return AZStd::Internal::move(first, last, result, {}); } template BidirectionalIterator2 move_backward(BidirectionalIterator1 first, BidirectionalIterator1 last, BidirectionalIterator2 result) { - return AZStd::Internal::move_backward(first, last, result, AZStd::Internal::is_fast_copy()); + return AZStd::Internal::move_backward(first, last, result, {}); } } @@ -516,63 +575,77 @@ namespace AZStd::Internal * Helper class to determine if we have apply fast fill. There are 3 conditions * - trivial assign * - size of type == 1 (chars) to use memset - * - contiguous iterators (pointers) + * - contiguous iterators */ + template + constexpr bool indirectly_copy_assignable = false; + template + constexpr bool indirectly_copy_assignable>> = + is_trivially_copy_assignable_v> && sizeof(iter_value_t) == 1; + template - struct is_fast_fill_helper - { - using value_type = typename iterator_traits::value_type; - constexpr static bool value = is_trivially_copy_assignable_v && sizeof(value_type) == 1 - && Internal::satisfies_contiguous_iterator_concept_v; - }; - - // Use this trait to to determine fill mode, based on the iterator, value size, etc. - // Use it when you call uninitialized_fill, uninitialized_fill_n, fill and fill_n. - template< typename Iterator > - struct is_fast_fill - : public ::AZStd::integral_constant::value> - {}; + using is_fast_fill = bool_constant && contiguous_iterator>; + template + constexpr bool is_fast_fill_v = is_fast_fill::value; + // The fast fill trait is no longer used + // It is detected using C++20 concepts now template - constexpr void fill(const ForwardIterator& first, const ForwardIterator& last, const T& value, const false_type& /* is_fast_fill() */) + constexpr void fill(ForwardIterator first, ForwardIterator last, const T& value, bool) { - ForwardIterator iter(first); - for (; iter != last; ++iter) + if constexpr (is_fast_fill_v) { - *iter = value; + size_t numElements = last - first; + if (numElements > 0) + { + if (az_builtin_is_constant_evaluated()) + { + for (; first != last; ++first) + { + *first = value; + } + } + else + { + ::memset(to_address(first), reinterpret_cast(value), numElements); + } + } } - } - // Specialized version for character types where memset can be used - // This overload cannot be constexpr until builtin_memset is added to MSVC compilers - template - inline void fill(const ForwardIterator& first, const ForwardIterator& last, const T& value, const true_type& /* is_fast_fill() */) - { - AZStd::size_t numElements = last - first; - if (numElements > 0) + else { - /*AZSTD_STL::*/ - memset((void*)&*first, *reinterpret_cast(&value), numElements); + for (; first != last; ++first) + { + *first = value; + } } } template - constexpr void fill_n(ForwardIterator first, Size numElements, const T& value, const false_type& /* is_fast_fill() */) + constexpr void fill_n(ForwardIterator first, Size numElements, const T& value, bool) { - for (; numElements--; ++first) + if constexpr (is_fast_fill_v) { - *first = value; + if (numElements) + { + if (az_builtin_is_constant_evaluated()) + { + for (; numElements--; ++first) + { + *first = value; + } + } + else + { + ::memset(to_address(first), reinterpret_cast(value), numElements); + } + } } - } - - // Specialized version for character types where memset can be used to perform the fill - // This overload cannot be constexpr until builtin_memset is added to MSVC compilers - template - inline void fill_n(ForwardIterator first, Size numElements, const T& value, const true_type& /* is_fast_fill() */) - { - if (numElements > 0) + else { - /*AZSTD_STL::*/ - memset(&*first, *reinterpret_cast(&value), numElements); + for (; numElements--; ++first) + { + *first = value; + } } } } @@ -580,78 +653,85 @@ namespace AZStd::Internal namespace AZStd { template - constexpr void fill(const ForwardIterator& first, const ForwardIterator& last, const T& value) + constexpr void fill(ForwardIterator first, ForwardIterator last, const T& value) { - Internal::fill(first, last, value, Internal::is_fast_fill()); + Internal::fill(first, last, value, {}); } - template constexpr void fill_n(ForwardIterator first, Size numElements, const T& value) { - Internal::fill_n(first, numElements, value, Internal::is_fast_fill()); + Internal::fill_n(first, numElements, value, {}); } template - constexpr void uninitialized_fill(const ForwardIterator& first, const ForwardIterator& last, const T& value, const false_type& /* is_fast_fill() */) + constexpr void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& value, bool) { - ForwardIterator iter(first); - for (; iter != last; ++iter) + if constexpr (Internal::is_fast_fill_v) { - ::new (static_cast(&*iter)) typename iterator_traits::value_type(value); + size_t numElements = last - first; + if (numElements > 0) + { + if (az_builtin_is_constant_evaluated()) + { + for (; first != last; ++first) + { + construct_at(static_cast*>(to_address(first)), value); + } + } + else + { + ::memset(to_address(first), reinterpret_cast(value), numElements); + } + } } - } - - // Specialized overload for types which meet the following criteria. - // 1. Has it's iterator_traits::iterator_concept type set to to contiguous_iterator_tag - // 2. Is trivially assignable - // 3. Has a sizeof(T) == 1 - // In such a case memset can be used to fill in the data - // This overload cannot be constexpr until builtin_memset is added to MSVC compilers - template - inline void uninitialized_fill(const ForwardIterator& first, const ForwardIterator& last, const T& value, const true_type& /* is_fast_fill() */) - { - AZStd::size_t numElements = last - first; - if (numElements > 0) + else { - /*AZSTD_STL::*/ - memset(&*first, *reinterpret_cast(&value), numElements); + for (; first != last; ++first) + { + construct_at(static_cast*>(to_address(first)), value); + } } } template constexpr void uninitialized_fill(ForwardIterator first, Size numElements, const T& value) { - return uninitialized_fill(first, numElements, value, Internal::is_fast_fill()); + return uninitialized_fill(first, numElements, value, {}); } template - constexpr void uninitialized_fill_n(ForwardIterator first, Size numElements, const T& value, const false_type& /* is_fast_fill() */) + constexpr void uninitialized_fill_n(ForwardIterator first, Size numElements, const T& value, bool) { - for (; numElements--; ++first) + if constexpr (Internal::is_fast_fill_v) { - ::new (static_cast(&*first)) typename iterator_traits::value_type(value); + if (numElements > 0) + { + if (az_builtin_is_constant_evaluated()) + { + for (; numElements--; ++first) + { + construct_at(static_cast*>(to_address(first)), value); + } + } + else + { + ::memset(to_address(first), reinterpret_cast(value), numElements); + } + } } - } - - // Specialized overload for types which meet the following criteria. - // 1. Has it's iterator_traits::iterator_concept type set to to contiguous_iterator_tag - // 2. Is trivially assignable - // 3. Has a sizeof(T) == 1 - // In such a case memset can be used to fill in the data - template - inline void uninitialized_fill_n(ForwardIterator first, Size numElements, const T& value, const true_type& /* is_fast_fill() */) - { - if (numElements) + else { - /*AZSTD_STL::*/ - memset(&*first, *reinterpret_cast(&value), numElements); + for (; numElements--; ++first) + { + construct_at(static_cast*>(to_address(first)), value); + } } } template constexpr void uninitialized_fill_n(ForwardIterator first, Size numElements, const T& value) { - return uninitialized_fill_n(first, numElements, value, Internal::is_fast_fill()); + return uninitialized_fill_n(first, numElements, value, {}); } } diff --git a/Code/Framework/AzCore/AzCore/std/function/invoke.h b/Code/Framework/AzCore/AzCore/std/function/invoke.h index 88dbbea218..6dccb43e36 100644 --- a/Code/Framework/AzCore/AzCore/std/function/invoke.h +++ b/Code/Framework/AzCore/AzCore/std/function/invoke.h @@ -38,4 +38,12 @@ namespace AZStd { return Internal::INVOKE(Internal::InvokeTraits::forward(f), Internal::InvokeTraits::forward(args)...); } + + // models the invocable concept + template + /*concept*/ constexpr bool invocable = is_invocable_v; + + // models the regular_invocable concept + template + /*concept*/ constexpr bool regular_invocable = invocable; } diff --git a/Code/Framework/AzCore/AzCore/std/iterator.h b/Code/Framework/AzCore/AzCore/std/iterator.h index 8d0d49b649..5bc653e3b6 100644 --- a/Code/Framework/AzCore/AzCore/std/iterator.h +++ b/Code/Framework/AzCore/AzCore/std/iterator.h @@ -8,19 +8,19 @@ #pragma once #include -#include -#include -#include -#include // use by ConstIteratorCast +#include +#include +#include #include -#include +#include +#include #include namespace AZStd { - // Everything unless specified is based on C++ standard 24 (lib.iterators). + // Everything unless specified is based on C++ standard 20 (lib.iterators). /// Identifying tag for input iterators. using input_iterator_tag = std::input_iterator_tag; @@ -51,16 +51,6 @@ namespace AZStd::Internal typename Iterator::reference> > = true; - - template - inline constexpr bool has_iterator_category_v = false; - template - inline constexpr bool has_iterator_category_v> = true; - template - inline constexpr bool has_iterator_concept_v = false; - template - inline constexpr bool has_iterator_concept_v> = true; - // Iterator iterator_category alias must be one of the iterator category tags template struct iterator_traits_category_tags @@ -98,6 +88,8 @@ namespace AZStd struct iterator_traits : Internal::iterator_traits_type_aliases> { + // Internal type alias meant to indicate that this is the primary template + using _is_primary_template = iterator_traits; }; /** @@ -114,45 +106,6 @@ namespace AZStd using iterator_category = random_access_iterator_tag; using iterator_concept = contiguous_iterator_tag; }; - -} - -namespace AZStd::Internal -{ - // iterator_category tag testers - template >> - inline constexpr bool has_iterator_category_convertible_to_v = false; - template - inline constexpr bool has_iterator_category_convertible_to_v = is_convertible_v::iterator_category, Category>; - - template - inline constexpr bool is_input_iterator_v = has_iterator_category_convertible_to_v; - - template - inline constexpr bool is_forward_iterator_v = has_iterator_category_convertible_to_v; - - template - inline constexpr bool is_bidirectional_iterator_v = has_iterator_category_convertible_to_v; - - template - inline constexpr bool is_random_access_iterator_v = has_iterator_category_convertible_to_v; - - template - inline constexpr bool is_contiguous_iterator_v = has_iterator_category_convertible_to_v; - - template - inline constexpr bool is_exactly_input_iterator_v = has_iterator_category_convertible_to_v && !has_iterator_category_convertible_to_v; - - // iterator concept testers - template - inline constexpr bool derived_from = is_base_of_v && is_convertible_v; - - template >> - inline constexpr bool satisfies_iterator_concept = false; - template - inline constexpr bool satisfies_iterator_concept = derived_from::iterator_concept, Concept>; - template - inline constexpr bool satisfies_contiguous_iterator_concept_v = satisfies_iterator_concept; } namespace AZStd diff --git a/Code/Framework/AzCore/AzCore/std/iterator/iterator_primitives.h b/Code/Framework/AzCore/AzCore/std/iterator/iterator_primitives.h new file mode 100644 index 0000000000..39d89e1f2f --- /dev/null +++ b/Code/Framework/AzCore/AzCore/std/iterator/iterator_primitives.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace AZStd +{ + // Bring in std utility functions into AZStd namespace + using std::forward; + + // forward declare iterator_traits to avoid iterator.h include + template + struct iterator_traits; +} + +// C++20 range traits for iteratable types +namespace AZStd::Internal +{ + // Models the can-reference concept which isn't available until C++20 + // template + template + constexpr bool can_reference = true; + template <> + inline constexpr bool can_reference = false; + + // Models the dereferencable concept which isn't available until C++20 + template + /*concept*/ constexpr bool dereferenceable = false; + template + constexpr bool dereferenceable())>>> = true; + + template + constexpr bool is_primary_template_v = false; + template + constexpr bool is_primary_template_v>> = true; + + // indirectly readable traits + template + constexpr bool has_value_type_v = false; + template + constexpr bool has_value_type_v> = true; + template + constexpr bool has_element_type_v = false; + template + constexpr bool has_element_type_v> = true; + + template + struct object_type_value_requires {}; + template + struct object_type_value_requires>> + { + using value_type = remove_cv_t; + }; + template + struct indirectly_readable_requires {}; + template + struct indirectly_readable_requires> + && is_void_v::value_type>> >> + { + // iterator_traits has been been specialized + using value_type = typename iterator_traits::value_type; + }; + + template + struct indirectly_readable_requires> + && is_array_v>> + { + using value_type = remove_cv_t>; + }; + + template + struct indirectly_readable_requires> + && has_value_type_v && !has_element_type_v>> + : object_type_value_requires {}; + + template + struct indirectly_readable_requires> + && has_element_type_v && !has_value_type_v>> + : object_type_value_requires {}; + + template + struct indirectly_readable_requires> + && has_value_type_v&& has_element_type_v + && same_as, remove_cv_t> >> + : object_type_value_requires {}; + + // incrementable traits + template + constexpr bool has_difference_type_v = false; + template + constexpr bool has_difference_type_v> = true; + + template + struct object_type_difference_requires {}; + template + struct object_type_difference_requires>> + { + using difference_type = ptrdiff_t; + }; + + template + struct incrementable_requires {}; + // iterator_traits has been specialized + template + struct incrementable_requires> + && is_void_v::difference_type>> >> + { + using difference_type = typename iterator_traits::difference_type; + }; + template + struct incrementable_requires> + && has_difference_type_v>> + { + using difference_type = typename T::difference_type; + }; + template + struct incrementable_requires> + && !has_difference_type_v + && integral() - declval())> >> + { + using difference_type = make_signed_t() - declval())>; + }; +} + +namespace AZStd +{ + // indirectly_readable_traits for iter_value_t + template + struct indirectly_readable_traits + : Internal::indirectly_readable_requires {}; + template + struct indirectly_readable_traits + : Internal::object_type_value_requires {}; + template + struct indirectly_readable_traits + : indirectly_readable_traits {}; + + template + using iter_value_t = typename indirectly_readable_traits>::value_type; + + template + using iter_reference_t = enable_if_t, decltype(*declval())>; + + // incrementable_traits for iter_difference_t + template + struct incrementable_traits + : Internal::incrementable_requires {}; + template + struct incrementable_traits + : Internal::object_type_difference_requires {}; + template + struct incrementable_traits + : incrementable_traits {}; + + template + using iter_difference_t = typename incrementable_traits>::difference_type; + + template + using iter_rvalue_reference_t = decltype(ranges::iter_move(declval())); + + namespace Internal + { + // model the indirectly readable concept + template + constexpr bool indirectly_readable_impl = false; + + template + constexpr bool indirectly_readable_impl()), iter_reference_t> + && same_as())), iter_rvalue_reference_t> + && common_reference_with&&, iter_value_t&> + && common_reference_with&&, iter_rvalue_reference_t&> + && common_reference_with&&, const iter_value_t&>>> = true; + } + + template + using iter_common_reference_t = enable_if_t, + common_reference_t, iter_value_t&>>; +} diff --git a/Code/Framework/AzCore/AzCore/std/ranges/iter_move.h b/Code/Framework/AzCore/AzCore/std/ranges/iter_move.h new file mode 100644 index 0000000000..a9519f03c5 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/std/ranges/iter_move.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace AZStd +{ + // Bring in std utility functions into AZStd namespace + using std::forward; +} + +// C++20 range traits for iteratable types +namespace AZStd::ranges::Internal +{ + void iter_move(); + + template + constexpr bool iter_move_adl = false; + + template + constexpr bool iter_move_adl()))>> = true; + + template + constexpr bool is_class_or_enum_with_iter_move_adl = false; + + template + constexpr bool is_class_or_enum_with_iter_move_adl + && (is_class_v> || is_enum_v>)>> + = true; + + struct iter_move_fn + { + template + constexpr auto operator()(It&& it) const + ->enable_if_t, + decltype(iter_move(AZStd::forward(it)))> + { + return iter_move(AZStd::forward(it)); + } + template + constexpr auto operator()(It&& it) const + ->enable_if_t&& is_lvalue_reference_v(it))>, + decltype(AZStd::move(*AZStd::forward(it)))> + { + return AZStd::move(*AZStd::forward(it)); + } + template + constexpr auto operator()(It&& it) const + ->enable_if_t && !is_lvalue_reference_v(it))>, + decltype(*AZStd::forward(it))> + { + return *AZStd::forward(it); + } + }; +} + +namespace AZStd::ranges +{ + inline namespace customization_point_object + { + inline constexpr auto iter_move = Internal::iter_move_fn{}; + } +} diff --git a/Code/Framework/AzCore/AzCore/std/ranges/ranges.h b/Code/Framework/AzCore/AzCore/std/ranges/ranges.h new file mode 100644 index 0000000000..a3ead81456 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/std/ranges/ranges.h @@ -0,0 +1,1157 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZStd +{ + // alias std:: reverse_iterator names into AZStd:: + using std::make_reverse_iterator; +} + +namespace AZStd::ranges +{ + // Range variable templates + template + inline constexpr bool enable_borrowed_range = false; + + template + inline constexpr bool disable_sized_range = false; + + namespace Internal + { + // Variadic template which maps types to true For SFINAE + template + constexpr bool sfinae_trigger_v = true; + + template + constexpr bool is_lvalue_or_borrowable = is_lvalue_reference_v || enable_borrowed_range>; + + //! begin + template + constexpr bool has_member_begin = false; + template + constexpr bool has_member_begin().begin())>> = true; + + template + constexpr bool has_unqualified_begin = false; + template + constexpr bool has_unqualified_begin()))>> + = !has_member_begin && AZStd::Internal::is_class_or_enum; + + template + void begin(T&) = delete; + template + void begin(const T&) = delete; + + struct begin_fn + { + template + constexpr auto operator()(T& t) const noexcept -> + enable_if_t && sfinae_trigger_v>, + decltype(t + 0)> + { + return t + 0; + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::forward(t).begin())) -> + enable_if_t&& is_lvalue_or_borrowable + && !is_array_v&& has_member_begin, + decltype(AZStd::forward(t).begin())> + { + return AZStd::forward(t).begin(); + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(begin(AZStd::forward(t)))) -> + enable_if_t&& is_lvalue_or_borrowable + && !is_array_v && has_unqualified_begin, + decltype(begin(AZStd::forward(t)))> + { + return begin(AZStd::forward(t)); + } + }; + } + inline namespace customization_point_object + { + inline constexpr Internal::begin_fn begin{}; + } + + template + using iterator_t = decltype(ranges::begin(declval())); + + namespace Internal + { + template + constexpr bool has_iterator_t = has_member_begin; + + //! end + template + constexpr bool has_member_end = false; + template + constexpr bool has_member_end().end())>> = true; + + template + constexpr bool has_unqualified_end = false; + template + constexpr bool has_unqualified_end()))>> + = !has_member_end && AZStd::Internal::is_class_or_enum; + + template + void end(T&) = delete; + template + void end(const T&) = delete; + + struct end_fn + { + template + constexpr auto operator()(T& t) const noexcept -> + enable_if_t && extent_v != 0, + decltype(t + extent_v)> + { + return t + extent_v; + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::forward(t).end())) -> + enable_if_t>&& is_lvalue_or_borrowable + && !is_array_v && has_member_end, + decltype(AZStd::forward(t).end())> + { + return AZStd::forward(t).end(); + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(end(AZStd::forward(t)))) -> + enable_if_t>&& is_lvalue_or_borrowable + && !is_array_v && has_unqualified_end, + decltype(end(AZStd::forward(t)))> + { + return end(AZStd::forward(t)); + } + }; + } + inline namespace customization_point_object + { + inline constexpr Internal::end_fn end{}; + } + + namespace Internal + { + //! cbegin + struct cbegin_fn + { + template + constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::begin(static_cast(t)))) + ->enable_if_t, decltype(ranges::begin(static_cast(t)))> + { + return ranges::begin(static_cast(t)); + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::begin(static_cast(t)))) -> + enable_if_t, decltype(ranges::begin(static_cast(t)))> + { + return ranges::begin(static_cast(t)); + } + }; + } + inline namespace customization_point_object + { + inline constexpr Internal::cbegin_fn cbegin{}; + } + + namespace Internal + { + //! cend + struct cend_fn + { + template + constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::end(static_cast(t)))) + ->enable_if_t, decltype(ranges::end(static_cast(t)))> + { + return ranges::end(static_cast(t)); + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::end(static_cast(t)))) -> + enable_if_t, decltype(ranges::end(static_cast(t)))> + { + return ranges::end(static_cast(t)); + } + }; + } + inline namespace customization_point_object + { + inline constexpr Internal::cend_fn cend{}; + } + + namespace Internal + { + //! rbegin + template + constexpr bool has_member_rbegin = false; + template + constexpr bool has_member_rbegin().rbegin())>> = true; + + template + constexpr bool has_unqualified_rbegin = false; + template + constexpr bool has_unqualified_rbegin()))>> + = !has_member_rbegin && AZStd::Internal::is_class_or_enum; + + template + constexpr bool has_bidirectional_rbegin = false; + template + constexpr bool has_bidirectional_rbegin())), decltype(ranges::end(declval()))> + && bidirectional_iterator()))> + && bidirectional_iterator()))> + >> = !has_member_rbegin && !has_unqualified_rbegin; + + + template + void rbegin(T&) = delete; + template + void rbegin(const T&) = delete; + + struct rbegin_fn + { + template + constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::forward(t).rbegin())) -> + enable_if_t && is_lvalue_or_borrowable + && has_member_rbegin, + decltype(AZStd::forward(t).rbegin())> + { + return AZStd::forward(t).rbegin(); + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(rbegin(AZStd::forward(t)))) -> + enable_if_t && is_lvalue_or_borrowable + && has_unqualified_rbegin, + decltype(rbegin(AZStd::forward(t)))> + { + return rbegin(AZStd::forward(t)); + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::make_reverse_iterator(ranges::end(AZStd::forward(t))))) -> + enable_if_t, + decltype(AZStd::make_reverse_iterator(ranges::end(AZStd::forward(t))))> + { + return AZStd::make_reverse_iterator(ranges::end(AZStd::forward(t))); + } + }; + } + + inline namespace customization_point_object + { + inline constexpr Internal::rbegin_fn rbegin{}; + } + + namespace Internal + { + //! rend + template + constexpr bool has_member_rend = false; + template + constexpr bool has_member_rend().rend())>> = true; + + template + constexpr bool has_unqualified_rend = false; + template + constexpr bool has_unqualified_rend()))>> + = !has_member_rend && AZStd::Internal::is_class_or_enum; + + template + constexpr bool has_bidirectional_rend = false; + template + constexpr bool has_bidirectional_rend())), decltype(ranges::end(declval()))> + && bidirectional_iterator()))> + && bidirectional_iterator()))> + >> = !has_member_rend && !has_unqualified_rend; + + template + void rend(T&) = delete; + template + void rend(const T&) = delete; + + struct rend_fn + { + template + constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::forward(t).rend())) -> + enable_if_t && is_lvalue_or_borrowable + && has_member_rend, + decltype(AZStd::forward(t).rend())> + { + return AZStd::forward(t).rend(); + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(rend(AZStd::forward(t)))) -> + enable_if_t && is_lvalue_or_borrowable + && has_unqualified_rend, + decltype(rend(AZStd::forward(t)))> + { + return rend(AZStd::forward(t)); + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::make_reverse_iterator(ranges::begin(AZStd::forward(t))))) -> + enable_if_t, + decltype(AZStd::make_reverse_iterator(ranges::begin(AZStd::forward(t))))> + { + return AZStd::make_reverse_iterator(ranges::begin(AZStd::forward(t))); + } + }; + } + + inline namespace customization_point_object + { + inline constexpr Internal::rend_fn rend{}; + } + + namespace Internal + { + //! crbegin + struct crbegin_fn + { + template + constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::rbegin(static_cast(t)))) + ->enable_if_t, decltype(ranges::rbegin(static_cast(t)))> + { + return ranges::rbegin(static_cast(t)); + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::rbegin(static_cast(t)))) -> + enable_if_t, decltype(ranges::rbegin(static_cast(t)))> + { + return ranges::rbegin(static_cast(t)); + } + }; + } + inline namespace customization_point_object + { + inline constexpr Internal::crbegin_fn crbegin{}; + } + + namespace Internal + { + //! crend + struct crend_fn + { + template + constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::rend(static_cast(t)))) + ->enable_if_t, decltype(ranges::rend(static_cast(t)))> + { + return ranges::rend(static_cast(t)); + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::rend(static_cast(t)))) -> + enable_if_t, decltype(ranges::rend(static_cast(t)))> + { + return ranges::rend(static_cast(t)); + } + }; + } + inline namespace customization_point_object + { + inline constexpr Internal::crend_fn crend{}; + } + + namespace Internal + { + //! size + template + constexpr bool has_member_size = false; + template + constexpr bool has_member_size().size())>> = true; + + template + constexpr bool has_unqualified_size = false; + template + constexpr bool has_unqualified_size()))>> + = !has_member_size && AZStd::Internal::is_class_or_enum; + + template + constexpr bool has_end_subtract_begin = false; + template + constexpr bool has_end_subtract_begin()) - ranges::begin(declval()))>> + = !has_member_size && !has_unqualified_size; + + template + void size(T&) = delete; + template + void size(const T&) = delete; + + struct size_fn + { + template + constexpr auto operator()(T&) const noexcept -> + enable_if_t && extent_v != 0, + decltype(extent_v)> + { + return extent_v; + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::forward(t).size())) -> + enable_if_t> && has_member_size + && AZStd::Internal::is_integer_like(t).size())>, + decltype(AZStd::forward(t).size())> + { + return AZStd::forward(t).size(); + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(size(AZStd::forward(t)))) -> + enable_if_t> + && has_unqualified_size + && AZStd::Internal::is_integer_like(t)))>, + decltype(size(AZStd::forward(t)))> + { + return size(AZStd::forward(t)); + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::end(AZStd::forward(t)) - ranges::begin(AZStd::forward(t)))) -> + enable_if_t< + has_end_subtract_begin + && sized_sentinel_for(t))), decltype(ranges::begin(AZStd::forward(t)))> + && forward_iterator(t)))>, + AZStd::make_unsigned_t(t)) - ranges::begin(AZStd::forward(t)))>> + { + using size_type = AZStd::make_unsigned_t(t)) - ranges::begin(AZStd::forward(t)))>; + return static_cast(ranges::end(AZStd::forward(t)) - ranges::begin(AZStd::forward(t))); + } + }; + } + inline namespace customization_point_object + { + inline constexpr Internal::size_fn size{}; + } + + namespace Internal + { + //! ssize + struct ssize_fn + { + template + constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::size(t))) -> + enable_if_t<(sizeof(ptrdiff_t) > sizeof(make_signed_t)), ptrdiff_t> + { + return static_cast(ranges::size(t)); + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::size(t))) -> + enable_if_t), make_signed_t> + { + using ssize_type = make_signed_t; + return static_cast(ranges::size(t)); + } + }; + } + inline namespace customization_point_object + { + inline constexpr Internal::ssize_fn ssize{}; + } + + namespace Internal + { + //! empty + template + constexpr bool has_member_empty = false; + template + constexpr bool has_member_empty().empty()), bool>>> = true; + + template + constexpr bool has_size_compare_to_0 = false; + template + constexpr bool has_size_compare_to_0()) == 0), bool> >> + = !has_member_empty; + + template + constexpr bool has_begin_compare_to_end = false; + + template + constexpr bool has_begin_compare_to_end()) == ranges::end(declval())), bool> >> + = !has_member_empty && !has_size_compare_to_0; + + struct empty_fn + { + template + [[nodiscard]] constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::forward(t).empty())) -> + enable_if_t && has_member_empty, bool> + { + return AZStd::forward(t).empty(); + } + + template + [[nodiscard]] constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::size(AZStd::forward(t)) == 0)) -> + enable_if_t && has_size_compare_to_0, bool> + { + return ranges::size(AZStd::forward(t)) == 0; + } + + template + [[nodiscard]] constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::begin(AZStd::forward(t)) == ranges::end(AZStd::forward(t)))) -> + enable_if_t && has_begin_compare_to_end, bool> + { + return ranges::begin(AZStd::forward(t)) == ranges::end(AZStd::forward(t)); + } + }; + } + inline namespace customization_point_object + { + inline constexpr Internal::empty_fn empty{}; + } + + namespace Internal + { + //! data + template + constexpr bool has_member_data = false; + template + constexpr bool has_member_data().data())>> = true; + + template + constexpr bool has_qualified_ranges_begin = false; + template + constexpr bool has_qualified_ranges_begin()))>> > + = !has_member_data; + + struct data_fn + { + template + constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::forward(t).data())) -> + enable_if_t && has_member_data, + decltype(AZStd::forward(t).data())> + { + return AZStd::forward(t).data(); + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(AZStd::to_address(ranges::begin(AZStd::forward(t))))) -> + enable_if_t && has_qualified_ranges_begin, + decltype(AZStd::to_address(ranges::begin(AZStd::forward(t))))> + { + return AZStd::to_address(ranges::begin(AZStd::forward(t))); + } + }; + } + inline namespace customization_point_object + { + inline constexpr Internal::data_fn data{}; + } + + namespace Internal + { + //! cdata + struct cdata_fn + { + template + constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::data(static_cast(t)))) -> + enable_if_t, decltype(ranges::data(static_cast(t)))> + { + return ranges::data(static_cast(t)); + } + + template + constexpr auto operator()(T&& t) const noexcept(noexcept(ranges::data(static_cast(t)))) -> + enable_if_t, decltype(ranges::data(static_cast(t)))> + { + return ranges::data(static_cast(t)); + } + }; + } + inline namespace customization_point_object + { + inline constexpr Internal::cdata_fn cdata{}; + } +} + +namespace AZStd::ranges +{ + namespace Internal + { + template + constexpr bool range_impl = false; + template + constexpr bool range_impl())), decltype(ranges::end(declval()))>> = true; + } + + // Models range concept + template + /*concept*/ constexpr bool range = Internal::range_impl; + + // sentinal type can now be defined after the range concept has been modeled + template + using sentinel_t = enable_if_t, decltype(ranges::end(declval()))>; + + // Models borrowed range concept + template + /*concept*/ constexpr bool borrowed_range = range + && (is_lvalue_reference_v || enable_borrowed_range>); + + struct dangling + { + constexpr dangling() = default; + template + constexpr dangling(T&&...) noexcept {} + }; + + template + using borrowed_iterator_t = conditional_t, iterator_t, dangling>; + + // Models sized range concept + namespace Internal + { + template + constexpr bool sized_range_impl = false; + template + constexpr bool sized_range_impl + && sfinae_trigger_v()))> >> = true; + } + + template + /*concept*/ constexpr bool sized_range = Internal::sized_range_impl; + + namespace Internal + { + template + constexpr bool output_range_impl = false; + template + constexpr bool output_range_impl>> = range && output_iterator, T>; + } + + template + /*concept*/ constexpr bool output_range = Internal::output_range_impl; + + namespace Internal + { + template + constexpr bool input_range_impl = false; + template + constexpr bool input_range_impl>> = range && input_iterator>; + } + + template + /*concept*/ constexpr bool input_range = Internal::input_range_impl; + + namespace Internal + { + template + constexpr bool forward_range_impl = false; + template + constexpr bool forward_range_impl>> = input_range && forward_iterator>; + } + + template + /*concept*/ constexpr bool forward_range = Internal::forward_range_impl; + + namespace Internal + { + template + constexpr bool bidirectional_range_impl = false; + template + constexpr bool bidirectional_range_impl>> = forward_range && bidirectional_iterator>; + } + + template + /*concept*/ constexpr bool bidirectional_range = Internal::bidirectional_range_impl; + + namespace Internal + { + template + constexpr bool random_access_range_impl = false; + template + constexpr bool random_access_range_impl>> = bidirectional_range && random_access_iterator>; + } + + template + /*concept*/ constexpr bool random_access_range = Internal::random_access_range_impl; + + template + using range_size_t = enable_if_t, decltype(ranges::size(declval()))>; + template + using range_difference_t = enable_if_t, iter_difference_t>>; + template + using range_value_t = enable_if_t, iter_value_t>>; + template + using range_reference_t = enable_if_t, iter_reference_t>>; + template + using range_rvalue_reference_t = enable_if_t, iter_rvalue_reference_t>>; + + + namespace Internal + { + template + constexpr bool contiguous_range_impl = false; + template + constexpr bool contiguous_range_impl + && contiguous_iterator> + && same_as())), add_pointer_t>> >> = true; + } + + template + /*concept*/ constexpr bool contiguous_range = Internal::contiguous_range_impl; + + template + /*concept*/ constexpr bool common_range = range && same_as, sentinel_t>; +} + +namespace AZStd::ranges +{ + // iterator operations + // ranges::advance + namespace Internal + { + struct advance_fn + { + template + constexpr auto operator()(I& i, iter_difference_t n) const -> + enable_if_t> + { + if constexpr (random_access_iterator) + { + i += n; + } + else + { + for (; n > 0; ++i, --n) {} + + // The Precondition is that if I is not a bidirectional iterator, n must be positive + if constexpr (bidirectional_iterator) + { + for (; n < 0; --i, ++n) {} + } + } + } + + template + constexpr auto operator()(I& i, S bound) const -> + enable_if_t&& sentinel_for> + { + if constexpr (assignable_from) + { + i = AZStd::move(bound); + } + else if constexpr (sized_sentinel_for) + { + operator()(i, bound - i); + } + else + { + for (; i != bound; ++i) {} + } + } + + template + constexpr auto operator()(I& i, iter_difference_t n, S bound) const -> + enable_if_t&& sentinel_for, iter_difference_t> + { + if constexpr (sized_sentinel_for) + { + if (const auto dist = bound - i; + (n > 0 && n > dist) || (n < 0 && n < dist)) + { + // advance is limited to the i reach bound + operator()(i, bound); + return n - dist; + } + else if (n != 0) + { + // advance is limited by the value of n + operator()(i, n); + return 0; + } + + return 0; + } + else + { + for (; i != bound && n > 0; ++i, --n) {} + if constexpr (bidirectional_iterator && same_as) + { + for (; i != bound && n < 0; --i, ++n) {} + } + + return n; + } + } + }; + } + + inline namespace customization_point_object + { + inline constexpr Internal::advance_fn advance{}; + } + + // ranges::distance + namespace Internal + { + struct distance_fn + { + template + constexpr auto operator()(I first, S last) const -> + enable_if_t && sentinel_for && !sized_sentinel_for, + iter_difference_t> + { + // Since S is not a sized sentinel, can only increment from first to last + iter_difference_t result{}; + for (; first != last; ++first, ++result) {} + + return result; + } + + template + constexpr auto operator()(const I& first, const S& last) const -> + enable_if_t && sentinel_for && sized_sentinel_for, + iter_difference_t> + { + return last - first; + } + + template + constexpr auto operator()(R&& r) const -> + enable_if_t, range_difference_t> + { + if constexpr (sized_range) + { + return ranges::size(r); + } + else + { + operator()(ranges::begin(r), ranges::end(r)); + } + } + }; + } + + inline namespace customization_point_object + { + inline constexpr Internal::distance_fn distance{}; + } + + // ranges::next + namespace Internal + { + struct next_fn + { + template + constexpr auto operator()(I x) const -> + enable_if_t, I> + { + ++x; + return x; + } + + template + constexpr auto operator()(I x, iter_difference_t n) const -> + enable_if_t, I> + { + ranges::advance(x, n); + return x; + } + + template + constexpr auto operator()(I x, S bound) const -> + enable_if_t&& sentinel_for, I> + { + ranges::advance(x, bound); + return x; + } + + template + constexpr auto operator()(I x, iter_difference_t n, S bound) const -> + enable_if_t&& sentinel_for, I> + { + ranges::advance(x, n, bound); + return x; + } + }; + } + + inline namespace customization_point_object + { + inline constexpr Internal::next_fn next{}; + } + + //ranges::prev + namespace Internal + { + struct prev_fn + { + template + constexpr auto operator()(I x) const -> + enable_if_t, I> + { + --x; + return x; + } + + template + constexpr auto operator()(I x, iter_difference_t n) const -> + enable_if_t, I> + { + ranges::advance(x, -n); + return x; + } + + template + constexpr auto operator()(I x, iter_difference_t n, S bound) const -> + enable_if_t&& sentinel_for, I> + { + ranges::advance(x, -n, bound); + return x; + } + }; + } + + inline namespace customization_point_object + { + inline constexpr Internal::prev_fn prev{}; + } +} + +namespace AZStd::ranges +{ + namespace Internal + { + template + constexpr bool is_initializer_list = false; + template + constexpr bool is_initializer_list> = true; + } + + //! views + // view interface can be used with non-constant class types + template + class view_interface; + template + class view_interface< D, enable_if_t && same_as> >> + { + private: + constexpr D& derived() noexcept + { + return static_cast(*this); + } + constexpr const D& derived() const noexcept + { + return static_cast(*this); + } + + public: + template + constexpr auto empty() -> enable_if_t, bool> + { + return ranges::begin(derived()) == ranges::end(derived()); + } + template + constexpr auto empty() const -> enable_if_t, bool> + { + return ranges::begin(derived()) == ranges::end(derived()); + } + + template ()))>> + constexpr explicit operator bool() const noexcept(noexcept(ranges::empty(derived()))) + { + return !ranges::empty(derived()); + } + + template + constexpr auto data() -> + enable_if_t>, decltype(to_address(ranges::begin(derived())))> + { + return to_address(ranges::begin(derived())); + } + template + constexpr auto data() const -> + enable_if_t>, decltype(to_address(ranges::begin(derived())))> + { + return to_address(ranges::begin(derived())); + } + + template + constexpr auto size() -> + enable_if_t && sized_sentinel_for, iterator_t>, + decltype(ranges::end(derived()) - ranges::begin(derived()))> + { + return ranges::end(derived()) - ranges::begin(derived()); + } + template + constexpr auto size() const -> + enable_if_t&& sized_sentinel_for, iterator_t>, + decltype(ranges::end(derived()) - ranges::begin(derived()))> + { + return ranges::end(derived()) - ranges::begin(derived()); + } + + template + constexpr auto front() -> + enable_if_t, decltype(*ranges::begin(derived()))> + { + return *ranges::begin(derived()); + } + template + constexpr auto front() const -> + enable_if_t, decltype(*ranges::begin(derived()))> + { + return *ranges::begin(derived()); + } + + template + constexpr auto back() -> + enable_if_t && common_range, decltype(*ranges::prev(ranges::end(derived())))> + { + return *ranges::prev(ranges::end(derived())); + } + + template + constexpr auto back() const -> + enable_if_t&& common_range, decltype(*ranges::prev(ranges::end(derived())))> + { + return *ranges::prev(ranges::end(derived())); + } + + template + constexpr auto operator[](range_difference_t n) -> + enable_if_t, decltype(ranges::begin(derived())[n])> + { + return ranges::begin(derived())[n]; + } + template + constexpr auto operator[](range_difference_t n) const -> + enable_if_t, decltype(ranges::begin(derived())[n])> + { + return ranges::begin(derived())[n]; + } + }; + + struct view_base {}; + namespace Internal + { + template + void derived_from_view_interface_template(view_interface&); + template + inline constexpr bool is_derived_from_view_interface = false; + template + inline constexpr bool is_derived_from_view_interface()))> = true; + } + template + inline constexpr bool enable_view = derived_from || Internal::is_derived_from_view_interface; + + template + /*concept*/ constexpr bool view = range && movable && enable_view; + + template + /*concept*/ constexpr bool viewable_range = range && + ((view> && constructible_from, T>) || + (!view> && + (is_lvalue_reference_v || (movable> && !Internal::is_initializer_list)))); +} + + +namespace AZStd::ranges +{ +#if __has_cpp_attribute(no_unique_address) +#define az_no_unique_address [[no_unique_address]] +#else +#define az_no_unique_address +#endif + template + struct in_in_result + { + az_no_unique_address I1 in1; + az_no_unique_address I2 in2; + + template&& convertible_to> > + constexpr operator in_in_result() const& + { + return { in1, in2 }; + } + + template&& convertible_to> > + constexpr operator in_in_result()&& + { + return { AZStd::move(in1), AZStd::move(in2) }; + } + }; + +#undef az_no_unique_address + + template + using swap_ranges_result = in_in_result; + + namespace Internal + { + struct swap_ranges_fn + { + template + constexpr auto operator()(I1 first1, S1 last1, I2 first2, S2 last2) const -> + enable_if_t&& sentinel_for + && input_iterator&& sentinel_for + && indirectly_swappable, + swap_ranges_result> + { + for (; !(first1 == last1 or first2 == last2); ++first1, ++first2) + { + ranges::iter_swap(first1, first2); + } + return { AZStd::move(first1), AZStd::move(first2) }; + } + + template + constexpr auto operator()(R1&& r1, R2&& r2) const -> + enable_if_t&& input_range + && indirectly_swappable, iterator_t>, + swap_ranges_result, borrowed_iterator_t>> + { + return operator()(ranges::begin(r1), ranges::end(r1), + ranges::begin(r2), ranges::end(r2)); + } + }; + } + inline namespace customization_point_object + { + constexpr Internal::swap_ranges_fn swap_ranges{}; + } +} + +namespace AZStd::ranges::Internal +{ + // Implementation of ranges::swap customization point overload which calls ranges::swap_ranges + // Must be done after the ranges::swap_ranges function has been declared + // ranges::swap customization point https://eel.is/c++draft/concepts#concept.swappable-2.2 + template + constexpr auto swap_fn::operator()(T&& t, U&& u) const noexcept(noexcept((*this)(*t, *u))) + ->enable_if_t + && is_array_v && is_array_v && (extent_v == extent_v) + > + { + ranges::swap_ranges(t, u); + } +} diff --git a/Code/Framework/AzCore/AzCore/std/string/fixed_string.h b/Code/Framework/AzCore/AzCore/std/string/fixed_string.h index ea841bc4ca..bbaab391b4 100644 --- a/Code/Framework/AzCore/AzCore/std/string/fixed_string.h +++ b/Code/Framework/AzCore/AzCore/std/string/fixed_string.h @@ -74,7 +74,7 @@ namespace AZStd constexpr basic_fixed_string(const_pointer ptr); // #6 - template && !is_convertible_v>> + template && !is_convertible_v>> constexpr basic_fixed_string(InputIt first, InputIt last); // #7 @@ -146,7 +146,7 @@ namespace AZStd constexpr auto append(size_type count, Element ch) -> basic_fixed_string&; template constexpr auto append(InputIt first, InputIt last) - -> enable_if_t && !is_convertible_v, basic_fixed_string&>; + -> enable_if_t && !is_convertible_v, basic_fixed_string&>; constexpr auto append(AZStd::initializer_list ilist) -> basic_fixed_string&; constexpr auto assign(const basic_fixed_string& rhs) -> basic_fixed_string&; @@ -161,7 +161,7 @@ namespace AZStd constexpr auto assign(size_type count, Element ch) -> basic_fixed_string&; template constexpr auto assign(InputIt first, InputIt last) - ->enable_if_t && !is_convertible_v, basic_fixed_string&>; + ->enable_if_t && !is_convertible_v, basic_fixed_string&>; constexpr auto assign(AZStd::initializer_list ilist) -> basic_fixed_string&; @@ -179,7 +179,7 @@ namespace AZStd constexpr auto insert(const_iterator insertPos, size_type count, Element ch) -> iterator; template constexpr auto insert(const_iterator insertPos, InputIt first, InputIt last) - -> enable_if_t && !is_convertible_v, iterator>; + -> enable_if_t && !is_convertible_v, iterator>; constexpr auto insert(const_iterator insertPos, AZStd::initializer_list ilist) -> iterator; @@ -215,7 +215,7 @@ namespace AZStd constexpr auto replace(const_iterator first, const_iterator last, size_type count, Element ch) -> basic_fixed_string&; template constexpr auto replace(const_iterator first, const_iterator last, InputIt first2, InputIt last2) - -> enable_if_t && !is_convertible_v, basic_fixed_string&>; + -> enable_if_t && !is_convertible_v, basic_fixed_string&>; constexpr auto replace(const_iterator first, const_iterator last, AZStd::initializer_list ilist) -> basic_fixed_string&; constexpr auto at(size_type offset) -> reference; diff --git a/Code/Framework/AzCore/AzCore/std/string/fixed_string.inl b/Code/Framework/AzCore/AzCore/std/string/fixed_string.inl index caa047f3c8..65fc1d88be 100644 --- a/Code/Framework/AzCore/AzCore/std/string/fixed_string.inl +++ b/Code/Framework/AzCore/AzCore/std/string/fixed_string.inl @@ -325,14 +325,14 @@ namespace AZStd template template inline constexpr auto basic_fixed_string::append(InputIt first, InputIt last) - -> enable_if_t && !is_convertible_v, basic_fixed_string&> + -> enable_if_t && !is_convertible_v, basic_fixed_string&> { - if constexpr (Internal::satisfies_contiguous_iterator_concept_v + if constexpr (contiguous_iterator && is_same_v::value_type, value_type>) { return append(AZStd::to_address(first), AZStd::distance(first, last)); } - else if constexpr (Internal::is_forward_iterator_v) + else if constexpr (forward_iterator) { // Input Iterator pointer type doesn't match the const_pointer type // So the elements need to be appended one by one into the buffer @@ -461,14 +461,14 @@ namespace AZStd template template inline constexpr auto basic_fixed_string::assign(InputIt first, InputIt last) - -> enable_if_t && !is_convertible_v, basic_fixed_string&> + -> enable_if_t && !is_convertible_v, basic_fixed_string&> { - if constexpr (Internal::satisfies_contiguous_iterator_concept_v + if constexpr (contiguous_iterator && is_same_v::value_type, value_type>) { return assign(AZStd::to_address(first), AZStd::distance(first, last)); } - else if constexpr (Internal::is_forward_iterator_v) + else if constexpr (forward_iterator) { // Input Iterator pointer type doesn't match the const_pointer type // So the elements need to be assigned one by one into the buffer @@ -627,15 +627,15 @@ namespace AZStd template template inline constexpr auto basic_fixed_string::insert(const_iterator insertPos, - InputIt first, InputIt last)-> enable_if_t && !is_convertible_v, iterator> + InputIt first, InputIt last)-> enable_if_t && !is_convertible_v, iterator> { // insert [_First, _Last) at _Where size_type insertOffset = AZStd::distance(cbegin(), insertPos); - if constexpr (Internal::satisfies_contiguous_iterator_concept_v + if constexpr (contiguous_iterator && is_same_v::value_type, value_type>) { insert(insertOffset, AZStd::to_address(first), AZStd::distance(first, last)); } - else if constexpr (Internal::is_forward_iterator_v) + else if constexpr (forward_iterator) { // Input Iterator pointer type doesn't match the const_pointer type // So the elements need to be inserted one by one into the buffer @@ -927,14 +927,14 @@ namespace AZStd template template inline constexpr auto basic_fixed_string::replace(const_iterator first, const_iterator last, - InputIt replaceFirst, InputIt replaceLast) -> enable_if_t && !is_convertible_v, basic_fixed_string&> + InputIt replaceFirst, InputIt replaceLast) -> enable_if_t && !is_convertible_v, basic_fixed_string&> { // replace [first, last) with [replaceFirst,replaceLast) - if constexpr (Internal::satisfies_contiguous_iterator_concept_v + if constexpr (contiguous_iterator && is_same_v::value_type, value_type>) { return replace(first, last, AZStd::to_address(replaceFirst), AZStd::distance(replaceFirst, replaceLast)); } - else if constexpr (Internal::is_forward_iterator_v) + else if constexpr (forward_iterator) { // Input Iterator pointer type doesn't match the const_pointer type // So the elements need to be appended one by one into the buffer diff --git a/Code/Framework/AzCore/AzCore/std/string/string.h b/Code/Framework/AzCore/AzCore/std/string/string.h index c65d699d15..c2f4a6953e 100644 --- a/Code/Framework/AzCore/AzCore/std/string/string.h +++ b/Code/Framework/AzCore/AzCore/std/string/string.h @@ -114,28 +114,23 @@ namespace AZStd assign(count, ch); } - template && !is_convertible_v>> + template && !is_convertible_v>> inline basic_string(InputIt first, InputIt last, const Allocator& alloc = Allocator()) : m_storage{ skip_element_tag{}, alloc } { // construct from [first, last) assign(first, last); } - inline basic_string(const_pointer first, const_pointer last) - { // construct from [first, last), const pointers - assign(first, last - first); - } - inline basic_string(const this_type& rhs) : m_storage{ skip_element_tag{}, rhs.m_storage.second() } { - assign(rhs, 0, npos); + assign(rhs); } inline basic_string(this_type&& rhs) - : m_storage{ skip_element_tag{}, AZStd::move(rhs.m_storage.second()) } + : m_storage{ skip_element_tag{}, rhs.m_storage.second() } { - assign(AZStd::forward(rhs)); + assign(AZStd::move(rhs)); } inline basic_string(const this_type& rhs, size_type rhsOffset, size_type count = npos) @@ -251,14 +246,14 @@ namespace AZStd template inline auto append(InputIt first, InputIt last) - -> enable_if_t && !is_convertible_v, this_type&> + -> enable_if_t && !is_convertible_v, this_type&> { // append [first, last) - if constexpr (Internal::satisfies_contiguous_iterator_concept_v + if constexpr (contiguous_iterator && is_same_v::value_type, value_type>) { return append(AZStd::to_address(first), AZStd::distance(first, last)); } - else if constexpr (Internal::is_forward_iterator_v) + else if constexpr (forward_iterator) { // Input Iterator pointer type doesn't match the const_pointer type // So the elements need to be appended one by one into the buffer @@ -299,7 +294,7 @@ namespace AZStd inline this_type& assign(const this_type& rhs) { - return assign(rhs, 0, npos); + return this != &rhs ? assign(rhs, 0, npos) : *this; } inline this_type& assign(basic_string_view view) @@ -319,7 +314,8 @@ namespace AZStd pointer rhsData = rhs.data(); // Memmove the right hand side string data if it is using the short string optimization // Otherwise set the pointer to the right hand side - if (rhs.m_storage.first().ShortStringOptimizationActive()) + if (rhs.m_storage.first().ShortStringOptimizationActive() || + (get_allocator() != rhs.get_allocator() && !allocator_traits::propagate_on_container_move_assignment::value)) { Traits::move(data, rhsData, rhs.size() + 1); // string + null-terminator } @@ -395,14 +391,14 @@ namespace AZStd template auto assign(InputIt first, InputIt last) - -> enable_if_t && !is_convertible_v, this_type&> + -> enable_if_t && !is_convertible_v, this_type&> { - if constexpr (Internal::satisfies_contiguous_iterator_concept_v + if constexpr (contiguous_iterator && is_same_v::value_type, value_type>) { return assign(AZStd::to_address(first), AZStd::distance(first, last)); } - else if constexpr (Internal::is_forward_iterator_v) + else if constexpr (forward_iterator) { // forward iterator pointer type doesn't match the const_pointer type // So the elements need to be assigned one by one into the buffer @@ -431,7 +427,7 @@ namespace AZStd inputCopy.push_back(static_cast(*first)); } - return assign(inputCopy.c_str(), inputCopy.size()); + return assign(AZStd::move(inputCopy)); } } inline this_type& insert(size_type offset, const this_type& rhs) { return insert(offset, rhs, 0, npos); } @@ -539,15 +535,15 @@ namespace AZStd template auto insert(const_iterator insertPos, InputIt first, InputIt last) - -> enable_if_t && !is_convertible_v, iterator> + -> enable_if_t && !is_convertible_v, iterator> { // insert [_First, _Last) at _Where size_type insertOffset = AZStd::distance(cbegin(), insertPos); - if constexpr (Internal::satisfies_contiguous_iterator_concept_v + if constexpr (contiguous_iterator && is_same_v::value_type, value_type>) { insert(insertOffset, AZStd::to_address(first), AZStd::distance(first, last)); } - else if constexpr (Internal::is_forward_iterator_v) + else if constexpr (forward_iterator) { // Input Iterator pointer type doesn't match the const_pointer type // So the elements need to be inserted one by one into the buffer @@ -834,14 +830,14 @@ namespace AZStd template inline auto replace(const_iterator first, const_iterator last, InputIt replaceFirst, InputIt replaceLast) - -> enable_if_t && !is_convertible_v, this_type&> + -> enable_if_t && !is_convertible_v, this_type&> { - if constexpr (Internal::satisfies_contiguous_iterator_concept_v + if constexpr (contiguous_iterator && is_same_v::value_type, value_type>) { return replace(first, last, AZStd::to_address(replaceFirst), AZStd::distance(replaceFirst, replaceLast)); } - else if constexpr (Internal::is_forward_iterator_v) + else if constexpr (forward_iterator) { // Input Iterator pointer type doesn't match the const_pointer type // So the elements need to be appended one by one into the buffer @@ -1031,12 +1027,19 @@ namespace AZStd // same allocator, swap storage m_storage.first().swap(rhs.m_storage.first()); } + else if (allocator_traits::propagate_on_container_swap::value) + { + // The allocator propagates on swap, so the allocators can be swapped + m_storage.first().swap(rhs.m_storage.first()); + using AZStd::swap; + swap(m_storage.second(), rhs.m_storage.second()); + } else { // different allocator, do multiple assigns - this_type tmp = *this; - *this = rhs; - rhs = tmp; + this_type tmp = AZStd::move(*this); + *this = AZStd::move(rhs); + rhs = AZStd::move(tmp); } } diff --git a/Code/Framework/AzCore/AzCore/std/string/string_view.h b/Code/Framework/AzCore/AzCore/std/string/string_view.h index 1579e43f4d..c333e2cea1 100644 --- a/Code/Framework/AzCore/AzCore/std/string/string_view.h +++ b/Code/Framework/AzCore/AzCore/std/string/string_view.h @@ -7,6 +7,7 @@ */ #pragma once +#include #include #include #include @@ -613,8 +614,9 @@ namespace AZStd {} template - && is_same_v::value_type, value_type> + contiguous_iterator + && sized_sentinel_for + && is_same_v, value_type> && !is_convertible_v> > constexpr basic_string_view(It first, End last) @@ -961,23 +963,6 @@ namespace AZStd using string_view = basic_string_view; using wstring_view = basic_string_view; - template> - using basic_const_string = basic_string_view; - using const_string = string_view; - using const_wstring = wstring_view; - - template > - constexpr typename basic_string_view::const_iterator begin(basic_string_view sv) - { - return sv.begin(); - } - - template > - constexpr typename basic_string_view::const_iterator end(basic_string_view sv) - { - return sv.end(); - } - inline namespace literals { inline namespace string_view_literals @@ -1024,6 +1009,15 @@ namespace AZStd } // namespace AZStd +namespace AZStd::ranges +{ + template + inline constexpr bool enable_borrowed_range> = true; + + template + inline constexpr bool enable_view> = true; +} + //! Use this macro to simplify safe printing of a string_view which may not be null-terminated. //! Example: AZStd::string::format("Safely formatted: %.*s", AZ_STRING_ARG(myString)); #define AZ_STRING_ARG(str) aznumeric_cast(str.size()), str.data() diff --git a/Code/Framework/AzCore/AzCore/std/typetraits/common_reference.h b/Code/Framework/AzCore/AzCore/std/typetraits/common_reference.h new file mode 100644 index 0000000000..51fd9c1dda --- /dev/null +++ b/Code/Framework/AzCore/AzCore/std/typetraits/common_reference.h @@ -0,0 +1,230 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace AZStd +{ + template class TQual, template class UQual> + struct basic_common_reference + {}; +} + +namespace AZStd::Internal +{ + // const volatile and reference qualifier copy templates + template + struct copy_cv_qual + { + using type = conditional_t, conditional_t, const volatile QualType, const QualType>, + conditional_t, volatile QualType, QualType>>; + }; + + template + using copy_cv_qual_t = typename copy_cv_qual::type; + + static_assert(is_same_v, float>); + static_assert(is_same_v, const float>); + static_assert(is_same_v, volatile float>); + static_assert(is_same_v, const volatile float>); + static_assert(is_same_v, const float>); + static_assert(is_same_v, const float>); + static_assert(is_same_v, const volatile float>); + static_assert(is_same_v, const volatile float>); + static_assert(is_same_v, volatile float>); + static_assert(is_same_v, const volatile float>); + static_assert(is_same_v, volatile float>); + static_assert(is_same_v, const volatile float>); + static_assert(is_same_v, const volatile float>); + static_assert(is_same_v, const volatile float>); + static_assert(is_same_v, const volatile float>); + static_assert(is_same_v, const volatile float>); + + template + struct copy_reference_qual + { + using type = conditional_t, QualType&, + conditional_t, QualType&&, QualType>>; + }; + + template + using copy_reference_qual_t = typename copy_reference_qual::type; + + static_assert(is_same_v, float>); + static_assert(is_same_v, float&>); + static_assert(is_same_v, float&&>); + static_assert(is_same_v, float&>); + static_assert(is_same_v, float&>); + static_assert(is_same_v, float&>); + static_assert(is_same_v, float&&>); + static_assert(is_same_v, float&>); + static_assert(is_same_v, float&&>); + + template + using copy_cvref_qual_t = copy_cv_qual_t, QualType>; + + template + struct copy_qualifiers_from_t + { + template + using templ = copy_cvref_qual_t; + }; + + template + using cond_res = decltype(false ? declval, remove_reference_t>&>() + : declval, remove_reference_t>&>()); + + // common reference helper templates begin + template + struct common_reference_base_reference_test; + + // COMMON_REF is defined within the C++ standard at https://eel.is/c++draft/meta.trans.other#3.5 + template + struct common_reference_base_reference_test&& is_lvalue_reference_v, + void_t> >> + { + // Uses the ternary operator for determining the common type + using type = cond_res; + }; + + template + struct common_reference_base_reference_test&& is_rvalue_reference_v>> + { + using C = remove_reference_t&, remove_reference_t&>::type>; + using type = AZStd::enable_if_t&& is_convertible_v, C>; + }; + + template + struct common_reference_base_reference_test&& is_lvalue_reference_v>> + { + // Turn rvalue references to const lvalue references + using D = typename common_reference_base_reference_test&, remove_reference_t&>::type; + using type = AZStd::enable_if_t, D>; + }; + + template + struct common_reference_base_reference_test&& is_rvalue_reference_v>> + { + // Swap the parameters to call the 3rd specialization for common_reference_base_reference_test + using type = typename common_reference_base_reference_test::type; + }; + + template + constexpr bool has_reference_test = false; + + template + constexpr bool has_reference_test::type>> = true; + + template + struct basic_common_reference_test; + + template + struct basic_common_reference_test, remove_cvref_t, + copy_qualifiers_from_t::template templ, copy_qualifiers_from_t::template templ>::type>> + { + using type = typename basic_common_reference, remove_cvref_t, + copy_qualifiers_from_t::template templ, copy_qualifiers_from_t::template templ>::type; + }; + + template + constexpr bool has_basic_common_reference_test = false; + + template + constexpr bool has_basic_common_reference_test::type>> = true; + + template + constexpr bool has_condition_result_test = false; + + template + constexpr bool has_condition_result_test() : declval())>> = true; + + template + struct common_reference_base_test + {}; + + template + struct common_reference_base_test>> + : common_reference_base_reference_test + {}; + template + struct common_reference_base_test + && has_basic_common_reference_test>> + : basic_common_reference_test + {}; + template + struct common_reference_base_test + && !has_basic_common_reference_test && has_condition_result_test>> + { + using type = decltype(false ? declval() : declval()); + }; + template + struct common_reference_base_test + && !has_basic_common_reference_test && !has_condition_result_test>> + : common_type + {}; + + template + struct common_reference_base + {}; + + template + struct common_reference_base + { + using type = T; + }; + template + struct common_reference_base + : common_reference_base_test + {}; + + template + struct common_reference_base + : common_reference_base::type, V, Rs...> + {}; +} +namespace AZStd +{ + template + struct common_reference + : Internal::common_reference_base + {}; + + template + using common_reference_t = typename common_reference::type; + + // models the common reference concept + namespace Internal + { + template + constexpr bool common_reference_with_impl = false; + template + constexpr bool common_reference_with_impl, common_reference_t> + && convertible_to> + && convertible_to> + >> = true; + } + + template + /*concept*/ constexpr bool common_reference_with = Internal::common_reference_with_impl; +} diff --git a/Code/Framework/AzCore/AzCore/std/typetraits/is_convertible.h b/Code/Framework/AzCore/AzCore/std/typetraits/is_convertible.h index 65f3b9908c..1f2933cecf 100644 --- a/Code/Framework/AzCore/AzCore/std/typetraits/is_convertible.h +++ b/Code/Framework/AzCore/AzCore/std/typetraits/is_convertible.h @@ -8,12 +8,26 @@ #pragma once +#include #include +#include +#include namespace AZStd { using std::is_convertible; + using std::is_convertible_v; + + // models the C++20 convertible_to concept + namespace Internal + { + template + constexpr bool convertible_to_impl = false; + template + constexpr bool convertible_to_impl, void_t(declval()))>>> = true; + } template - constexpr bool is_convertible_v = std::is_convertible_v; + /*concept*/ constexpr bool convertible_to = Internal::convertible_to_impl; } diff --git a/Code/Framework/AzCore/AzCore/std/typetraits/is_destructible.h b/Code/Framework/AzCore/AzCore/std/typetraits/is_destructible.h index ac03f01d3b..39d79781f4 100644 --- a/Code/Framework/AzCore/AzCore/std/typetraits/is_destructible.h +++ b/Code/Framework/AzCore/AzCore/std/typetraits/is_destructible.h @@ -21,4 +21,7 @@ namespace AZStd constexpr bool is_trivially_destructible_v = std::is_trivially_destructible::value; template constexpr bool is_nothrow_destructible_v = std::is_nothrow_destructible::value; + + template + /*concept*/ constexpr bool destructible = is_nothrow_destructible_v; } diff --git a/Code/Framework/AzCore/AzCore/std/typetraits/is_floating_point.h b/Code/Framework/AzCore/AzCore/std/typetraits/is_floating_point.h index 7408866ed7..b973ac714c 100644 --- a/Code/Framework/AzCore/AzCore/std/typetraits/is_floating_point.h +++ b/Code/Framework/AzCore/AzCore/std/typetraits/is_floating_point.h @@ -13,4 +13,7 @@ namespace AZStd { using std::is_floating_point; using std::is_floating_point_v; + + template + /*concept*/ constexpr bool floating_point = is_floating_point_v; } diff --git a/Code/Framework/AzCore/AzCore/std/typetraits/is_integral.h b/Code/Framework/AzCore/AzCore/std/typetraits/is_integral.h index a51e06dc06..eb699aa6d1 100644 --- a/Code/Framework/AzCore/AzCore/std/typetraits/is_integral.h +++ b/Code/Framework/AzCore/AzCore/std/typetraits/is_integral.h @@ -13,4 +13,7 @@ namespace AZStd { using std::is_integral; using std::is_integral_v; + + template + /*concept*/ constexpr bool integral = is_integral_v; } diff --git a/Code/Framework/AzCore/AzCore/std/typetraits/is_same.h b/Code/Framework/AzCore/AzCore/std/typetraits/is_same.h index 858e9b1f52..61037d7549 100644 --- a/Code/Framework/AzCore/AzCore/std/typetraits/is_same.h +++ b/Code/Framework/AzCore/AzCore/std/typetraits/is_same.h @@ -13,4 +13,8 @@ namespace AZStd { using std::is_same; using std::is_same_v; + + // models the same_as concept + template + /*concept*/ constexpr bool same_as = is_same_v; } diff --git a/Code/Framework/AzCore/AzCore/std/typetraits/typetraits.h b/Code/Framework/AzCore/AzCore/std/typetraits/typetraits.h index d29b0c28ee..bf45d15836 100644 --- a/Code/Framework/AzCore/AzCore/std/typetraits/typetraits.h +++ b/Code/Framework/AzCore/AzCore/std/typetraits/typetraits.h @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/Code/Framework/AzCore/AzCore/std/utility/declval.h b/Code/Framework/AzCore/AzCore/std/utility/declval.h new file mode 100644 index 0000000000..c017bb142a --- /dev/null +++ b/Code/Framework/AzCore/AzCore/std/utility/declval.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +#include + +namespace AZStd +{ + using std::declval; +} diff --git a/Code/Framework/AzCore/AzCore/std/utility/move.h b/Code/Framework/AzCore/AzCore/std/utility/move.h new file mode 100644 index 0000000000..71f2a49b18 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/std/utility/move.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ +#pragma once + +namespace AZStd +{ + // rvalue + // rvalue move + template + constexpr AZStd::remove_reference_t&& move(T&& t) + { + return static_cast&&>(t); + } +} diff --git a/Code/Framework/AzCore/AzCore/std/utils.h b/Code/Framework/AzCore/AzCore/std/utils.h index 4c918250de..d3ead8022b 100644 --- a/Code/Framework/AzCore/AzCore/std/utils.h +++ b/Code/Framework/AzCore/AzCore/std/utils.h @@ -22,22 +22,15 @@ #include #include #include +#include +#include #include namespace AZStd { ////////////////////////////////////////////////////////////////////////// - // rvalue - // rvalue move - template - constexpr AZStd::remove_reference_t&& move(T && t) - { - return static_cast&&>(t); - } - using std::forward; - using std::declval; using std::exchange; template diff --git a/Code/Framework/AzCore/Tests/AZStd/ConceptsTests.cpp b/Code/Framework/AzCore/Tests/AZStd/ConceptsTests.cpp new file mode 100644 index 0000000000..718edfcde4 --- /dev/null +++ b/Code/Framework/AzCore/Tests/AZStd/ConceptsTests.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +namespace UnitTest +{ + class ConceptsTestFixture + : public ScopedAllocatorSetupFixture + {}; + + TEST_F(ConceptsTestFixture, GeneralConcepts) + { + + // concept same_as + static_assert(AZStd::same_as); + static_assert(!AZStd::same_as); + + // concept derived_from + static_assert(AZStd::derived_from); + static_assert(!AZStd::derived_from); + + // concept convertible_to + static_assert(AZStd::convertible_to); + static_assert(!AZStd::convertible_to); + + + // Test structs to validate common_reference_with and common_with concepts + struct Base {}; + struct TestBase : Base {}; + struct NoMove + { + NoMove(NoMove&&) = delete; + NoMove& operator=(NoMove&&) = delete; + }; + struct NoDestructible + { + ~NoDestructible() = delete; + }; + struct NoDefaultInitializable + { + NoDefaultInitializable(bool); + }; + + struct CopyOnly + { + CopyOnly(const CopyOnly&) = default; + }; + struct MoveOnly + { + MoveOnly(MoveOnly&&) = default; + }; + + struct MoveableButNotCopyable + { + MoveableButNotCopyable(MoveableButNotCopyable&&) = default; + MoveableButNotCopyable& operator=(MoveableButNotCopyable&&) = default; + }; + + // concept common_reference_with + static_assert(AZStd::common_reference_with); + static_assert(AZStd::same_as, const Base&>); + static_assert(!AZStd::common_reference_with); + + // concept common_with + static_assert(AZStd::common_with); + static_assert(!AZStd::common_with); + + // arithmetic concepts + // concept integral + static_assert(AZStd::integral); + static_assert(!AZStd::integral); + + // concept signed_integral + static_assert(AZStd::signed_integral); + static_assert(!AZStd::signed_integral); + static_assert(!AZStd::signed_integral); + + // concept signed_integral + static_assert(AZStd::unsigned_integral); + static_assert(!AZStd::unsigned_integral); + static_assert(!AZStd::unsigned_integral); + + // concept floating_point + static_assert(AZStd::floating_point); + static_assert(!AZStd::floating_point); + + // concept assignable_from + static_assert(AZStd::assignable_from); + static_assert(!AZStd::assignable_from); + + // concept swappable + static_assert(AZStd::swappable); + static_assert(!AZStd::swappable); + static_assert(AZStd::swappable_with); + static_assert(!AZStd::swappable_with); + + // concept destructible + static_assert(AZStd::destructible); + static_assert(!AZStd::destructible); + + // concept constructible_from + static_assert(AZStd::constructible_from); + static_assert(!AZStd::constructible_from); + + // concept default_initializable + static_assert(AZStd::default_initializable); + static_assert(!AZStd::default_initializable); + + // concept move_constructible + static_assert(AZStd::move_constructible); + static_assert(!AZStd::move_constructible); + + // concept copy_constructible + static_assert(AZStd::copy_constructible); + static_assert(!AZStd::copy_constructible); + + // concept equality_comparable + static_assert(AZStd::equality_comparable); + static_assert(!AZStd::equality_comparable); + static_assert(AZStd::equality_comparable_with); + static_assert(!AZStd::equality_comparable_with); + static_assert(!AZStd::equality_comparable_with); + + // concept totally_ordered + static_assert(AZStd::totally_ordered); + static_assert(!AZStd::totally_ordered); + static_assert(AZStd::totally_ordered_with); + static_assert(!AZStd::totally_ordered_with); + static_assert(!AZStd::totally_ordered_with); + + // concept movable + static_assert(AZStd::movable); + static_assert(!AZStd::movable); + + // concept copyable + static_assert(AZStd::copyable); + static_assert(!AZStd::copyable); + + // concept semiregular + static_assert(AZStd::semiregular); + static_assert(!AZStd::semiregular); + + // concept regular + static_assert(AZStd::regular); + static_assert(!AZStd::regular); + + // concept invocable + static_assert(AZStd::invocable); + static_assert(!AZStd::invocable); + + // concept predicate + auto BooleanPredicate = [](double) -> int + { + return 0; + }; + auto BasePredicate = [](int) -> Base + { + return Base{}; + }; + + static_assert(AZStd::predicate); + static_assert(!AZStd::predicate); + static_assert(!AZStd::predicate); + + // concept relation + struct RelationPredicate + { + bool operator()(AZStd::string_view, Base) const; + bool operator()(Base, AZStd::string_view) const; + bool operator()(AZStd::string_view, AZStd::string_view) const; + bool operator()(Base, Base) const; + + // non-complete relation + bool operator()(Base, int) const; + bool operator()(int, Base) const; + }; + + static_assert(AZStd::relation); + static_assert(AZStd::relation); + static_assert(!AZStd::relation); + static_assert(!AZStd::relation); + + //concept equivalence_relation + static_assert(AZStd::equivalence_relation); + static_assert(AZStd::equivalence_relation); + static_assert(!AZStd::equivalence_relation); + static_assert(!AZStd::equivalence_relation); + + //concept strict_weak_order + static_assert(AZStd::strict_weak_order); + static_assert(AZStd::strict_weak_order); + static_assert(!AZStd::strict_weak_order); + static_assert(!AZStd::strict_weak_order); + } +} diff --git a/Code/Framework/AzCore/Tests/AZStd/Iterators.cpp b/Code/Framework/AzCore/Tests/AZStd/Iterators.cpp index 720aa0c7a8..28b596398e 100644 --- a/Code/Framework/AzCore/Tests/AZStd/Iterators.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/Iterators.cpp @@ -6,6 +6,7 @@ * */ #include "UserTypes.h" +#include #include #include #include @@ -13,13 +14,11 @@ #include #include -using namespace AZStd; -using namespace UnitTestInternal; namespace UnitTest { class Iterators - : public AllocatorsFixture + : public ScopedAllocatorSetupFixture { }; @@ -28,30 +27,30 @@ namespace UnitTest { Container int_container = {{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }}; - typename Container::iterator iter_begin = begin(int_container); + typename Container::iterator iter_begin = AZStd::begin(int_container); EXPECT_EQ(*iter_begin, 0); - EXPECT_EQ(*next(iter_begin), 1); - EXPECT_EQ(*next(iter_begin, 2), 2); + EXPECT_EQ(*AZStd::next(iter_begin), 1); + EXPECT_EQ(*AZStd::next(iter_begin, 2), 2); ++iter_begin; EXPECT_EQ(*iter_begin, 1); typename Container::iterator iter_end = end(int_container); EXPECT_EQ(iter_end, int_container.end()); - EXPECT_EQ(*prev(iter_end), 9); - EXPECT_EQ(*prev(iter_end, 2), 8); + EXPECT_EQ(*AZStd::prev(iter_end), 9); + EXPECT_EQ(*AZStd::prev(iter_end, 2), 8); --iter_end; EXPECT_EQ(*iter_end, 9); - typename Container::reverse_iterator iter_rbegin = rbegin(int_container); + typename Container::reverse_iterator iter_rbegin = AZStd::rbegin(int_container); EXPECT_EQ(*iter_rbegin, 9); - EXPECT_EQ(*next(iter_rbegin), 8); - EXPECT_EQ(*next(iter_rbegin, 2), 7); + EXPECT_EQ(*AZStd::next(iter_rbegin), 8); + EXPECT_EQ(*AZStd::next(iter_rbegin, 2), 7); ++iter_rbegin; EXPECT_EQ(*iter_rbegin, 8); - typename Container::reverse_iterator iter_rend = rend(int_container); - EXPECT_EQ(*prev(iter_rend), 0); - EXPECT_EQ(*prev(iter_rend, 2), 1); + typename Container::reverse_iterator iter_rend = AZStd::rend(int_container); + EXPECT_EQ(*AZStd::prev(iter_rend), 0); + EXPECT_EQ(*AZStd::prev(iter_rend, 2), 1); --iter_rend; EXPECT_EQ(*iter_rend, 0); @@ -65,30 +64,30 @@ namespace UnitTest { Container int_container = {{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }}; - typename Container::const_iterator iter_cbegin = cbegin(int_container); + typename Container::const_iterator iter_cbegin = AZStd::cbegin(int_container); EXPECT_EQ(*iter_cbegin, 0); - EXPECT_EQ(*next(iter_cbegin), 1); - EXPECT_EQ(*next(iter_cbegin, 2), 2); + EXPECT_EQ(*AZStd::next(iter_cbegin), 1); + EXPECT_EQ(*AZStd::next(iter_cbegin, 2), 2); ++iter_cbegin; EXPECT_EQ(*iter_cbegin, 1); - typename Container::const_iterator iter_cend = cend(int_container); + typename Container::const_iterator iter_cend = AZStd::cend(int_container); EXPECT_EQ(iter_cend, int_container.cend()); - EXPECT_EQ(*prev(iter_cend), 9); - EXPECT_EQ(*prev(iter_cend, 2), 8); + EXPECT_EQ(*AZStd::prev(iter_cend), 9); + EXPECT_EQ(*AZStd::prev(iter_cend, 2), 8); --iter_cend; EXPECT_EQ(*iter_cend, 9); - typename Container::const_reverse_iterator iter_crbegin = crbegin(int_container); + typename Container::const_reverse_iterator iter_crbegin = AZStd::crbegin(int_container); EXPECT_EQ(*iter_crbegin, 9); - EXPECT_EQ(*next(iter_crbegin), 8); - EXPECT_EQ(*next(iter_crbegin, 2), 7); + EXPECT_EQ(*AZStd::next(iter_crbegin), 8); + EXPECT_EQ(*AZStd::next(iter_crbegin, 2), 7); ++iter_crbegin; EXPECT_EQ(*iter_crbegin, 8); - typename Container::const_reverse_iterator iter_crend = crend(int_container); - EXPECT_EQ(*prev(iter_crend), 0); - EXPECT_EQ(*prev(iter_crend, 2), 1); + typename Container::const_reverse_iterator iter_crend = AZStd::crend(int_container); + EXPECT_EQ(*AZStd::prev(iter_crend), 0); + EXPECT_EQ(*AZStd::prev(iter_crend, 2), 1); --iter_crend; EXPECT_EQ(*iter_crend, 0); } @@ -98,15 +97,15 @@ namespace UnitTest { const ConstContainer const_int_container = {{ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }}; - typename ConstContainer::const_iterator const_iter_begin = begin(const_int_container); + typename ConstContainer::const_iterator const_iter_begin = AZStd::begin(const_int_container); EXPECT_EQ(*const_iter_begin, 10); - EXPECT_EQ(*next(const_iter_begin), 11); - EXPECT_EQ(*next(const_iter_begin, 2), 12); + EXPECT_EQ(*AZStd::next(const_iter_begin), 11); + EXPECT_EQ(*AZStd::next(const_iter_begin, 2), 12); - typename ConstContainer::const_iterator const_iter_end = end(const_int_container); + typename ConstContainer::const_iterator const_iter_end = AZStd::end(const_int_container); EXPECT_EQ(const_iter_end, const_int_container.end()); - EXPECT_EQ(*prev(const_iter_end), 19); - EXPECT_EQ(*prev(const_iter_end, 2), 18); + EXPECT_EQ(*AZStd::prev(const_iter_end), 19); + EXPECT_EQ(*AZStd::prev(const_iter_end, 2), 18); } TEST_F(Iterators, FunctionWrappers_MutableContainers) @@ -136,87 +135,78 @@ namespace UnitTest { int int_array[10] = { 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 }; - EXPECT_EQ(*begin(int_array), 20); - EXPECT_EQ(*next(begin(int_array)), 21); - EXPECT_EQ(*next(begin(int_array), 2), 22); + EXPECT_EQ(*AZStd::begin(int_array), 20); + EXPECT_EQ(*AZStd::next(AZStd::begin(int_array)), 21); + EXPECT_EQ(*AZStd::next(AZStd::begin(int_array), 2), 22); - EXPECT_EQ(end(int_array) - AZ_ARRAY_SIZE(int_array), begin(int_array)); - EXPECT_EQ(*prev(end(int_array)), 29); - EXPECT_EQ(*prev(end(int_array), 2), 28); + EXPECT_EQ(AZStd::end(int_array) - AZ_ARRAY_SIZE(int_array), AZStd::begin(int_array)); + EXPECT_EQ(*AZStd::prev(AZStd::end(int_array)), 29); + EXPECT_EQ(*AZStd::prev(AZStd::end(int_array), 2), 28); - EXPECT_EQ(*rbegin(int_array), 29); - EXPECT_EQ(*next(rbegin(int_array)), 28); - EXPECT_EQ(*next(rbegin(int_array), 2), 27); + EXPECT_EQ(*AZStd::rbegin(int_array), 29); + EXPECT_EQ(*AZStd::next(AZStd::rbegin(int_array)), 28); + EXPECT_EQ(*AZStd::next(AZStd::rbegin(int_array), 2), 27); - EXPECT_EQ(*prev(rend(int_array)), 20); - EXPECT_EQ(*prev(rend(int_array), 2), 21); + EXPECT_EQ(*AZStd::prev(AZStd::rend(int_array)), 20); + EXPECT_EQ(*AZStd::prev(AZStd::rend(int_array), 2), 21); - EXPECT_EQ(*crbegin(int_array), 29); - EXPECT_EQ(*next(crbegin(int_array)), 28); - EXPECT_EQ(*next(crbegin(int_array), 2), 27); + EXPECT_EQ(*AZStd::crbegin(int_array), 29); + EXPECT_EQ(*AZStd::next(AZStd::crbegin(int_array)), 28); + EXPECT_EQ(*AZStd::next(AZStd::crbegin(int_array), 2), 27); - EXPECT_EQ(*prev(crend(int_array)), 20); - EXPECT_EQ(*prev(crend(int_array), 2), 21); + EXPECT_EQ(*AZStd::prev(AZStd::crend(int_array)), 20); + EXPECT_EQ(*AZStd::prev(AZStd::crend(int_array), 2), 21); //verify we can successfully modify the value in a non-const iterator - *begin(int_array) = -42; - EXPECT_EQ(*begin(int_array), -42); + *AZStd::begin(int_array) = -42; + EXPECT_EQ(*AZStd::begin(int_array), -42); } TEST_F(Iterators, FunctionWrappers_ConstRawArray) { const int const_int_array[10] = { 30, 31, 32, 33, 34, 35, 36, 37, 38, 39 }; - EXPECT_EQ(*cbegin(const_int_array), 30); - EXPECT_EQ(*next(cbegin(const_int_array)), 31); - EXPECT_EQ(*next(cbegin(const_int_array), 2), 32); + EXPECT_EQ(*AZStd::cbegin(const_int_array), 30); + EXPECT_EQ(*AZStd::next(AZStd::cbegin(const_int_array)), 31); + EXPECT_EQ(*AZStd::next(AZStd::cbegin(const_int_array), 2), 32); - EXPECT_EQ(cend(const_int_array) - AZ_ARRAY_SIZE(const_int_array), cbegin(const_int_array)); - EXPECT_EQ(*prev(cend(const_int_array)), 39); - EXPECT_EQ(*prev(cend(const_int_array), 2), 38); + EXPECT_EQ(AZStd::cend(const_int_array) - AZ_ARRAY_SIZE(const_int_array), AZStd::cbegin(const_int_array)); + EXPECT_EQ(*AZStd::prev(AZStd::cend(const_int_array)), 39); + EXPECT_EQ(*AZStd::prev(AZStd::cend(const_int_array), 2), 38); } TEST_F(Iterators, IteratorTraits_ResolveAtCompileTime) { using list_type = AZStd::list; - static_assert(AZStd::Internal::has_iterator_category_v); - static_assert(AZStd::Internal::has_iterator_type_aliases_v); constexpr bool list_type_iterator_type_aliases = AZStd::Internal::has_iterator_type_aliases_v; static_assert(AZStd::is_convertible_v::iterator_category, AZStd::input_iterator_tag>); - static_assert(is_same_v::iterator_category, bidirectional_iterator_tag>); - static_assert(is_same_v::value_type, int>); - static_assert(is_same_v::difference_type, AZStd::ptrdiff_t>); - static_assert(is_same_v::pointer, int*>); - static_assert(is_same_v::reference, int&>); - static_assert(AZStd::Internal::is_input_iterator_v); - static_assert(!AZStd::Internal::has_iterator_concept_v>); - static_assert(!AZStd::Internal::satisfies_contiguous_iterator_concept_v); + static_assert(AZStd::is_same_v::iterator_category, AZStd::bidirectional_iterator_tag>); + static_assert(AZStd::is_same_v::value_type, int>); + static_assert(AZStd::is_same_v::difference_type, AZStd::ptrdiff_t>); + static_assert(AZStd::is_same_v::pointer, int*>); + static_assert(AZStd::is_same_v::reference, int&>); + static_assert(AZStd::input_iterator); + static_assert(!AZStd::contiguous_iterator); - static_assert(AZStd::Internal::has_iterator_category_v); - static_assert(AZStd::Internal::has_iterator_type_aliases_v); constexpr bool list_type_const_iterator_type_aliases = AZStd::Internal::has_iterator_type_aliases_v; static_assert(AZStd::is_convertible_v::iterator_category, AZStd::input_iterator_tag>); - static_assert(is_same_v::iterator_category, bidirectional_iterator_tag>); - static_assert(is_same_v::value_type, int>); - static_assert(is_same_v::difference_type, AZStd::ptrdiff_t>); - static_assert(is_same_v::pointer, const int*>); - static_assert(is_same_v::reference, const int&>); - static_assert(AZStd::Internal::is_input_iterator_v); - static_assert(!AZStd::Internal::has_iterator_concept_v>); - static_assert(!AZStd::Internal::satisfies_contiguous_iterator_concept_v); + static_assert(AZStd::is_same_v::iterator_category, AZStd::bidirectional_iterator_tag>); + static_assert(AZStd::is_same_v::value_type, int>); + static_assert(AZStd::is_same_v::difference_type, AZStd::ptrdiff_t>); + static_assert(AZStd::is_same_v::pointer, const int*>); + static_assert(AZStd::is_same_v::reference, const int&>); + static_assert(AZStd::input_iterator); + static_assert(!AZStd::contiguous_iterator); using pointer_type = const char*; - static_assert(AZStd::Internal::has_iterator_category_v>); - static_assert(AZStd::Internal::has_iterator_type_aliases_v>); - static_assert(is_same_v::iterator_concept, contiguous_iterator_tag>); - static_assert(is_same_v::iterator_category, random_access_iterator_tag>); - static_assert(is_same_v::value_type, char>); - static_assert(is_same_v::difference_type, AZStd::ptrdiff_t>); - static_assert(is_same_v::pointer, const char*>); - static_assert(is_same_v::reference, const char&>); - static_assert(AZStd::Internal::has_iterator_concept_v>); - static_assert(AZStd::Internal::satisfies_contiguous_iterator_concept_v); + static_assert(AZStd::is_same_v::iterator_concept, AZStd::contiguous_iterator_tag>); + static_assert(AZStd::is_same_v::iterator_category, AZStd::random_access_iterator_tag>); + static_assert(AZStd::is_same_v::value_type, char>); + static_assert(AZStd::is_same_v::difference_type, AZStd::ptrdiff_t>); + static_assert(AZStd::is_same_v::pointer, const char*>); + static_assert(AZStd::is_same_v::reference, const char&>); + static_assert(AZStd::contiguous_iterator); } } diff --git a/Code/Framework/AzCore/Tests/AZStd/RangesTests.cpp b/Code/Framework/AzCore/Tests/AZStd/RangesTests.cpp new file mode 100644 index 0000000000..7d0751a519 --- /dev/null +++ b/Code/Framework/AzCore/Tests/AZStd/RangesTests.cpp @@ -0,0 +1,583 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include + +namespace UnitTest +{ + class RangesTestFixture + : public ScopedAllocatorSetupFixture + {}; + + struct RangeLikeCustomizationPoint {}; + + RangeLikeCustomizationPoint* begin(RangeLikeCustomizationPoint& rangeLike) + { + return &rangeLike; + } + RangeLikeCustomizationPoint* end(RangeLikeCustomizationPoint& rangeLike) + { + return &rangeLike; + } + const RangeLikeCustomizationPoint* cbegin(const RangeLikeCustomizationPoint& rangeLike) + { + return &rangeLike; + } + const RangeLikeCustomizationPoint* cend(const RangeLikeCustomizationPoint& rangeLike) + { + return &rangeLike; + } + RangeLikeCustomizationPoint* rbegin(RangeLikeCustomizationPoint& rangeLike) + { + return &rangeLike; + } + RangeLikeCustomizationPoint* rend(RangeLikeCustomizationPoint& rangeLike) + { + return &rangeLike; + } + const RangeLikeCustomizationPoint* crbegin(const RangeLikeCustomizationPoint& rangeLike) + { + return &rangeLike; + } + const RangeLikeCustomizationPoint* crend(const RangeLikeCustomizationPoint& rangeLike) + { + return &rangeLike; + } + + constexpr size_t size(const RangeLikeCustomizationPoint&) + { + return 0; + } + constexpr size_t size(RangeLikeCustomizationPoint&) + { + return 0; + } + + + // range access + TEST_F(RangesTestFixture, RangesBegin_Compiles_WithExtentArray) + { + using ArrayExtentType = int[5]; + + ArrayExtentType extentArray{}; + EXPECT_EQ(extentArray + 0, AZStd::ranges::begin(extentArray)); + } + + TEST_F(RangesTestFixture, RangesBegin_DoesNotCompile_WithNoExtentArray) + { + using ArrayNoExtentType = int[]; + static_assert(!AZStd::invocable); + } + + TEST_F(RangesTestFixture, RangesBegin_Compiles_WithMemberOverload) + { + AZStd::string_view strView; + EXPECT_EQ(strView.begin(), AZStd::ranges::begin(strView)); + } + + TEST_F(RangesTestFixture, RangesBegin_Compiles_WithADL) + { + RangeLikeCustomizationPoint rangeLike; + EXPECT_EQ(&rangeLike, AZStd::ranges::begin(rangeLike)); + } + + TEST_F(RangesTestFixture, RangesEnd_Compiles_WithExtentArray) + { + using ArrayExtentType = int[5]; + + ArrayExtentType extentArray{}; + EXPECT_EQ(extentArray + 5, AZStd::ranges::end(extentArray)); + } + + TEST_F(RangesTestFixture, RangesEnd_DoesNotCompile_WithNoExtentArray) + { + using ArrayNoExtentType = int[]; + static_assert(!AZStd::invocable); + } + + TEST_F(RangesTestFixture, RangesEnd_Compiles_WithMemberOverload) + { + AZStd::string_view strView; + EXPECT_EQ(strView.end(), AZStd::ranges::end(strView)); + } + TEST_F(RangesTestFixture, RangesEnd_Compiles_WithADL) + { + RangeLikeCustomizationPoint rangeLike; + EXPECT_EQ(&rangeLike, AZStd::ranges::end(rangeLike)); + } + + TEST_F(RangesTestFixture, RangesCBegin_Compiles_WithExtentArray) + { + using ArrayExtentType = int[5]; + + ArrayExtentType extentArray{}; + EXPECT_EQ(extentArray + 0, AZStd::ranges::cbegin(extentArray)); + } + + TEST_F(RangesTestFixture, RangesCBegin_Compiles_WithMemberOverload) + { + AZStd::string_view strView; + EXPECT_EQ(strView.cbegin(), AZStd::ranges::cbegin(strView)); + } + + TEST_F(RangesTestFixture, RangesCBegin_Compiles_WithADL) + { + RangeLikeCustomizationPoint rangeLike; + EXPECT_EQ(&rangeLike, AZStd::ranges::cbegin(rangeLike)); + } + + TEST_F(RangesTestFixture, RangesCEnd_Compiles_WithExtentArray) + { + using ArrayExtentType = int[5]; + + ArrayExtentType extentArray{}; + EXPECT_EQ(extentArray + 5, AZStd::ranges::cend(extentArray)); + } + + TEST_F(RangesTestFixture, RangesCEnd_Compiles_WithMemberOverload) + { + AZStd::string_view strView; + EXPECT_EQ(strView.cend(), AZStd::ranges::cend(strView)); + } + + TEST_F(RangesTestFixture, RangesCEnd_Compiles_WithADL) + { + RangeLikeCustomizationPoint rangeLike; + EXPECT_EQ(&rangeLike, AZStd::ranges::cend(rangeLike)); + } + + TEST_F(RangesTestFixture, RangesRBegin_Compiles_WithExtentArray) + { + using ArrayExtentType = int[5]; + + ArrayExtentType extentArray{}; + EXPECT_EQ(extentArray + 5, AZStd::ranges::rbegin(extentArray).base()); + } + + TEST_F(RangesTestFixture, RangesRBegin_Compiles_WithMemberOverload) + { + AZStd::string_view strView; + EXPECT_EQ(strView.rbegin(), AZStd::ranges::rbegin(strView)); + } + TEST_F(RangesTestFixture, RangesRBegin_Compiles_WithADL) + { + RangeLikeCustomizationPoint rangeLike; + EXPECT_EQ(&rangeLike, AZStd::ranges::rbegin(rangeLike)); + } + + TEST_F(RangesTestFixture, RangesREnd_Compiles_WithExtentArray) + { + using ArrayExtentType = int[5]; + + ArrayExtentType extentArray{}; + EXPECT_EQ(extentArray, AZStd::ranges::rend(extentArray).base()); + } + + TEST_F(RangesTestFixture, RangesREnd_Compiles_WithMemberOverload) + { + AZStd::string_view strView; + EXPECT_EQ(strView.rend(), AZStd::ranges::rend(strView)); + } + TEST_F(RangesTestFixture, RangesREnd_Compiles_WithADL) + { + RangeLikeCustomizationPoint rangeLike; + EXPECT_EQ(&rangeLike, AZStd::ranges::rend(rangeLike)); + } + + TEST_F(RangesTestFixture, RangesCRBegin_Compiles_WithExtentArray) + { + using ArrayExtentType = int[5]; + + ArrayExtentType extentArray{}; + EXPECT_EQ(extentArray + 5, AZStd::ranges::crbegin(extentArray).base()); + } + + TEST_F(RangesTestFixture, RangesCRBegin_Compiles_WithMemberOverload) + { + AZStd::string_view strView; + EXPECT_EQ(strView.crbegin(), AZStd::ranges::crbegin(strView)); + } + TEST_F(RangesTestFixture, RangesCRBegin_Compiles_WithADL) + { + RangeLikeCustomizationPoint rangeLike; + EXPECT_EQ(&rangeLike, AZStd::ranges::crbegin(rangeLike)); + } + + TEST_F(RangesTestFixture, RangesCREnd_Compiles_WithExtentArray) + { + using ArrayExtentType = int[5]; + + ArrayExtentType extentArray{}; + EXPECT_EQ(extentArray + 0, AZStd::ranges::crend(extentArray).base()); + } + + TEST_F(RangesTestFixture, RangesCREnd_Compiles_WithMemberOverload) + { + AZStd::string_view strView; + EXPECT_EQ(strView.crend(), AZStd::ranges::crend(strView)); + } + + TEST_F(RangesTestFixture, RangesCREnd_Compiles_WithADL) + { + RangeLikeCustomizationPoint rangeLike; + EXPECT_EQ(&rangeLike, AZStd::ranges::crend(rangeLike)); + } + + // range access - size + TEST_F(RangesTestFixture, RangesSize_Compiles_WithExtentArray) + { + using ArrayExtentType = int[5]; + + constexpr ArrayExtentType extentArray{}; + static_assert(5 == AZStd::ranges::size(extentArray)); + } + + TEST_F(RangesTestFixture, RangesSize_DoesNotCompile_WithNoExtentArray) + { + using ArrayNoExtentType = int[]; + static_assert(!AZStd::invocable); + } + + TEST_F(RangesTestFixture, RangesSize_Compiles_WithMemberOverload) + { + AZStd::string_view strView; + EXPECT_EQ(strView.size(), AZStd::ranges::size(strView)); + } + + + TEST_F(RangesTestFixture, RangesSize_Compiles_WithADL) + { + RangeLikeCustomizationPoint rangeLike; + + EXPECT_EQ(0, AZStd::ranges::size(rangeLike)); + } + + TEST_F(RangesTestFixture, RangesSSize_Compiles_WithExtentArray) + { + using ArrayExtentType = int[5]; + + constexpr ArrayExtentType extentArray{}; + static_assert(AZStd::signed_integral); + static_assert(5 == AZStd::ranges::ssize(extentArray)); + } + + TEST_F(RangesTestFixture, RangesSSize_DoesNotCompile_WithNoExtentArray) + { + using ArrayNoExtentType = int[]; + static_assert(!AZStd::invocable); + } + + TEST_F(RangesTestFixture, RangesSSize_Compiles_WithMemberOverload) + { + AZStd::string_view strView; + static_assert(AZStd::signed_integral); + EXPECT_EQ(strView.size(), AZStd::ranges::ssize(strView)); + } + + TEST_F(RangesTestFixture, RangesSSize_Compiles_WithADL) + { + RangeLikeCustomizationPoint rangeLike; + static_assert(AZStd::signed_integral); + EXPECT_EQ(0, AZStd::ranges::ssize(rangeLike)); + } + + // range access - empty + TEST_F(RangesTestFixture, RangesEmpty_Compiles_WithExtentArray) + { + using ArrayExtentType = int[5]; + + constexpr ArrayExtentType extentArray{}; + static_assert(!AZStd::ranges::empty(extentArray)); + } + + TEST_F(RangesTestFixture, RangesEmpty_DoesNotCompile_WithNoExtentArray) + { + using ArrayNoExtentType = int[]; + static_assert(!AZStd::invocable); + } + + TEST_F(RangesTestFixture, RangesEmpty_Compiles_WithMemberOverload) + { + constexpr AZStd::string_view strView; + static_assert(AZStd::ranges::empty(strView)); + } + + TEST_F(RangesTestFixture, RangesEmpty_Compiles_WithADL) + { + constexpr RangeLikeCustomizationPoint rangeLike; + + static_assert(AZStd::ranges::empty(rangeLike)); + } + + // range access - data + TEST_F(RangesTestFixture, RangesData_Compiles_WithExtentArray) + { + using ArrayExtentType = int[5]; + + constexpr ArrayExtentType extentArray{}; + EXPECT_EQ(extentArray, AZStd::ranges::data(extentArray)); + } + + TEST_F(RangesTestFixture, RangesData_DoesNotCompile_WithNoExtentArray) + { + using ArrayNoExtentType = int[]; + static_assert(!AZStd::invocable); + } + + TEST_F(RangesTestFixture, RangesData_Compiles_WithMemberOverload) + { + constexpr AZStd::string_view strView; + EXPECT_EQ(strView.data(), AZStd::ranges::data(strView)); + } + + TEST_F(RangesTestFixture, RangesData_Compiles_WithADL) + { + RangeLikeCustomizationPoint rangeLike; + + EXPECT_EQ(&rangeLike, AZStd::ranges::data(rangeLike)); + } + + // range access - cdata + TEST_F(RangesTestFixture, RangesCData_Compiles_WithExtentArray) + { + using ArrayExtentType = int[5]; + + constexpr ArrayExtentType extentArray{}; + EXPECT_EQ(extentArray, AZStd::ranges::cdata(extentArray)); + } + + TEST_F(RangesTestFixture, RangesCData_DoesNotCompile_WithNoExtentArray) + { + using ArrayNoExtentType = int[]; + static_assert(!AZStd::invocable); + } + + TEST_F(RangesTestFixture, RangesCData_Compiles_WithMemberOverload) + { + constexpr AZStd::string_view strView; + EXPECT_EQ(strView.data(), AZStd::ranges::cdata(strView)); + } + + TEST_F(RangesTestFixture, RangesCData_Compiles_WithADL) + { + RangeLikeCustomizationPoint rangeLike; + + EXPECT_EQ(&rangeLike, AZStd::ranges::cdata(rangeLike)); + } + + // Ranges TypeTraits Test + TEST_F(RangesTestFixture, RangesTypeTraits_Compiles) + { + // string_view + static_assert(AZStd::same_as, const char*>); + static_assert(AZStd::same_as, const char*>); + static_assert(AZStd::same_as, ptrdiff_t>); + static_assert(AZStd::same_as, size_t>); + static_assert(AZStd::same_as, char>); + static_assert(AZStd::same_as, const char&>); + static_assert(AZStd::same_as, const char&&>); + + // string + static_assert(AZStd::same_as, char*>); + static_assert(AZStd::same_as, char*>); + static_assert(AZStd::same_as, ptrdiff_t>); + static_assert(AZStd::same_as, size_t>); + static_assert(AZStd::same_as, char>); + static_assert(AZStd::same_as, char&>); + static_assert(AZStd::same_as, char&&>); + + // int array type + using ArrayExtentType = int[5]; + static_assert(AZStd::same_as, int*>); + static_assert(AZStd::same_as, int*>); + static_assert(AZStd::same_as, ptrdiff_t>); + static_assert(AZStd::same_as, size_t>); + static_assert(AZStd::same_as, int>); + static_assert(AZStd::same_as, int&>); + static_assert(AZStd::same_as, int&&>); + + // RangeLikeCustomizationPoint type which specializes several range functions + static_assert(AZStd::same_as, RangeLikeCustomizationPoint*>); + static_assert(AZStd::same_as, RangeLikeCustomizationPoint*>); + static_assert(AZStd::same_as, ptrdiff_t>); + static_assert(AZStd::same_as, size_t>); + static_assert(AZStd::same_as, RangeLikeCustomizationPoint>); + static_assert(AZStd::same_as, RangeLikeCustomizationPoint&>); + static_assert(AZStd::same_as, RangeLikeCustomizationPoint&&>); + } + + // Ranges Concepts Test + TEST_F(RangesTestFixture, RangesConcepts_Compiles) + { + using ArrayExtentType = int[5]; + // concept - range + static_assert(AZStd::ranges::range); + static_assert(AZStd::ranges::range); + static_assert(AZStd::ranges::range); + static_assert(!AZStd::ranges::range); + + // concept - sized_range + static_assert(AZStd::ranges::sized_range); + static_assert(AZStd::ranges::sized_range); + // Path classes do not have a size() function so they are not a sized_range + static_assert(!AZStd::ranges::sized_range); + + // concept - borrowed_range + static_assert(AZStd::ranges::borrowed_range); + static_assert(AZStd::ranges::borrowed_range); + static_assert(!AZStd::ranges::borrowed_range); + + // concept - output_range + static_assert(AZStd::ranges::output_range); + static_assert(!AZStd::ranges::output_range); + + // concept - input_range + static_assert(AZStd::ranges::input_range>); + static_assert(AZStd::ranges::input_range); + static_assert(AZStd::ranges::input_range); + + // concept - forward_range + static_assert(AZStd::ranges::forward_range>); + static_assert(AZStd::ranges::forward_range); + static_assert(AZStd::ranges::forward_range); + + // concept - bidirectional_range + static_assert(AZStd::ranges::bidirectional_range>); + static_assert(AZStd::ranges::bidirectional_range); + static_assert(AZStd::ranges::bidirectional_range); + + // concept - random_access_range + static_assert(!AZStd::ranges::random_access_range>); + static_assert(AZStd::ranges::random_access_range>); + static_assert(AZStd::ranges::random_access_range); + static_assert(AZStd::ranges::random_access_range); + + // concept - contiguous_range + static_assert(!AZStd::ranges::contiguous_range>); + static_assert(AZStd::ranges::contiguous_range); + static_assert(AZStd::ranges::contiguous_range); + + // concept - common_range + static_assert(AZStd::ranges::common_range); + static_assert(AZStd::ranges::common_range>); + static_assert(AZStd::ranges::common_range>); + static_assert(AZStd::ranges::common_range); + static_assert(AZStd::ranges::common_range); + + // concept - view + static_assert(AZStd::ranges::view); + static_assert(!AZStd::ranges::view); + + // concept - viewable_range + static_assert(AZStd::ranges::viewable_range); + static_assert(AZStd::ranges::viewable_range); + static_assert(!AZStd::ranges::viewable_range); + } + + // Ranges iterator operations + TEST_F(RangesTestFixture, RangesAdvance_PositiveDifference_Succeeds) + { + AZStd::string_view testString{ "Hello World" }; + auto strIter = testString.begin(); + + // difference overload + AZStd::ranges::advance(strIter, 5); + ASSERT_NE(testString.end(), strIter); + EXPECT_EQ(' ', *strIter); + + // bound overload + AZStd::ranges::advance(strIter, testString.end()); + EXPECT_EQ(testString.end(), strIter); + + // difference + bound overload + strIter = testString.begin(); + ptrdiff_t charactersToTraverse = 20; + EXPECT_EQ(charactersToTraverse - testString.size(), AZStd::ranges::advance(strIter, charactersToTraverse, testString.end())); + EXPECT_EQ(testString.end(), strIter); + + strIter = testString.begin(); + charactersToTraverse = 5; + EXPECT_EQ(0, AZStd::ranges::advance(strIter, charactersToTraverse, testString.end())); + ASSERT_NE(testString.end(), strIter); + EXPECT_EQ(' ', *strIter); + } + + TEST_F(RangesTestFixture, RangesAdvance_NegativeDifference_Succeeds) + { + AZStd::string_view testString{ "Hello World" }; + auto strIter = testString.end(); + + // difference overload + AZStd::ranges::advance(strIter, -5); + ASSERT_NE(testString.end(), strIter); + EXPECT_EQ('W', *strIter); + + // difference + bound overload + strIter = testString.end(); + ptrdiff_t charactersToTraverse = -20; + EXPECT_EQ(charactersToTraverse + testString.size(), AZStd::ranges::advance(strIter, charactersToTraverse, testString.begin())); + EXPECT_EQ(testString.begin(), strIter); + + strIter = testString.end(); + charactersToTraverse = -5; + EXPECT_EQ(0, AZStd::ranges::advance(strIter, charactersToTraverse, testString.begin())); + ASSERT_NE(testString.end(), strIter); + ASSERT_NE(testString.begin(), strIter); + EXPECT_EQ('W', *strIter); + } + + TEST_F(RangesTestFixture, RangesDistance_Succeeds) + { + AZStd::string_view testString{ "Hello World" }; + EXPECT_EQ(testString.size(), AZStd::ranges::distance(testString)); + EXPECT_EQ(testString.size(), AZStd::ranges::distance(testString.begin(), testString.end())); + + AZStd::list testList{ 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' }; + EXPECT_EQ(testList.size(), AZStd::ranges::distance(testList)); + EXPECT_EQ(testList.size(), AZStd::ranges::distance(testList.begin(), testList.end())); + } + + TEST_F(RangesTestFixture, RangesNext_Succeeds) + { + AZStd::string_view testString{ "Hello World" }; + auto strIter = testString.begin(); + auto boundIter = testString.begin() + 5; + // single increment + EXPECT_EQ(testString.begin() + 1, AZStd::ranges::next(strIter)); + // increment by value + strIter = testString.begin(); + EXPECT_EQ(testString.begin() + 5, AZStd::ranges::next(strIter, 5)); + // increment until bound + strIter = testString.begin(); + EXPECT_EQ(testString.begin() + 5, AZStd::ranges::next(strIter, boundIter)); + // increment by value up until bound + strIter = testString.begin(); + EXPECT_EQ(testString.begin() + 5, AZStd::ranges::next(strIter, 10, boundIter)); + strIter = testString.begin(); + EXPECT_EQ(testString.begin() + 4, AZStd::ranges::next(strIter, 4, boundIter)); + } + + TEST_F(RangesTestFixture, RangesPrev_Succeeds) + { + AZStd::string_view testString{ "Hello World" }; + auto strIter = testString.end(); + auto boundIter = testString.end() - 5; + // single decrement + EXPECT_EQ(testString.end() - 1, AZStd::ranges::prev(strIter)); + // decrement by value + strIter = testString.end(); + EXPECT_EQ(testString.end() - 5, AZStd::ranges::prev(strIter, 5)); + // decrement by value up until bound + strIter = testString.end(); + EXPECT_EQ(testString.end() - 5, AZStd::ranges::prev(strIter, 10, boundIter)); + strIter = testString.end(); + EXPECT_EQ(testString.end() - 4, AZStd::ranges::prev(strIter, 4, boundIter)); + } +} diff --git a/Code/Framework/AzCore/Tests/AZStd/SpanTests.cpp b/Code/Framework/AzCore/Tests/AZStd/SpanTests.cpp new file mode 100644 index 0000000000..f9861ae1f2 --- /dev/null +++ b/Code/Framework/AzCore/Tests/AZStd/SpanTests.cpp @@ -0,0 +1,249 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include + +namespace UnitTest +{ + class SpanTestFixture + : public ScopedAllocatorSetupFixture + {}; + + // range access + TEST_F(SpanTestFixture, IsConstructibleWithContiguousRangeLikeContainers) + { + constexpr AZStd::string_view testStringView{ "Foo" }; + AZStd::string testString{ "Foo" }; + AZStd::vector testVector{ 'F', 'o', 'o' }; + AZStd::fixed_vector testFixedVector{ 'F', 'o', 'o' }; + AZStd::array testStdArray{ 'F', 'o', 'o' }; + const char testCArray[]{ 'F', 'o', 'o' }; + + constexpr AZStd::span stringViewSpan(testStringView); + static_assert(stringViewSpan.data() == testStringView.data()); + + AZStd::span testStringSpan(testString); + EXPECT_EQ(testStringSpan.data(), testString.data()); + + AZStd::span testVectorSpan(testVector); + EXPECT_EQ(testVectorSpan.data(), testVector.data()); + + AZStd::span testFixedVectorSpan(testFixedVector); + EXPECT_EQ(testFixedVectorSpan.data(), testFixedVector.data()); + + AZStd::span testStdArraySpan(testStdArray); + EXPECT_EQ(testStdArraySpan.data(), testStdArray.data()); + + AZStd::span testCArraySpan(testCArray); + EXPECT_EQ(AZStd::data(testCArray), testCArraySpan.data()); + } + + TEST_F(SpanTestFixture, IsConstructibleWithContiguousIterators) + { + constexpr AZStd::string_view testStringView{ "Foo" }; + AZStd::string testString{ "Foo" }; + AZStd::vector testVector{ 'F', 'o', 'o' }; + AZStd::fixed_vector testFixedVector{ 'F', 'o', 'o' }; + AZStd::array testStdArray{ 'F', 'o', 'o' }; + const char testCArray[]{ 'F', 'o', 'o' }; + + constexpr AZStd::span stringViewSpan(testStringView.begin(), testStringView.end()); + static_assert(stringViewSpan.data() == testStringView.data()); + + AZStd::span testStringSpan(testString.begin(), testString.end()); + EXPECT_EQ(testStringSpan.data(), testString.data()); + + AZStd::span testVectorSpan(testVector.begin(), testVector.end()); + EXPECT_EQ(testVectorSpan.data(), testVector.data()); + + AZStd::span testFixedVectorSpan(testFixedVector.begin(), testFixedVector.end()); + EXPECT_EQ(testFixedVectorSpan.data(), testFixedVector.data()); + + AZStd::span testStdArraySpan(testStdArray.begin(), testStdArray.end()); + EXPECT_EQ(testStdArraySpan.data(), testStdArray.data()); + + AZStd::span testCArraySpan(AZStd::begin(testCArray), AZStd::end(testCArray)); + EXPECT_EQ(AZStd::data(testCArray), testCArraySpan.data()); + } + + TEST_F(SpanTestFixture, ObserverMethods_ReturnsCorrectValues) + { + AZStd::vector intVector{ 4, 5, 6, 1, 7 }; + + AZStd::span intSpan(intVector); + + EXPECT_FALSE(intSpan.empty()); + EXPECT_EQ(intVector.size(), intSpan.size()); + EXPECT_EQ(intSpan.size() * sizeof(int), intSpan.size_bytes()); + + intSpan = {}; + + EXPECT_TRUE(intSpan.empty()); + EXPECT_EQ(0, intSpan.size()); + EXPECT_EQ(0, intSpan.size_bytes()); + } + + TEST_F(SpanTestFixture, ElementAccessorMethods_Succeeds) + { + AZStd::vector intVector{ 4, 5, 6, 1, 7 }; + + AZStd::span intSpan(intVector); + + EXPECT_EQ(intVector.data(), intSpan.data()); + EXPECT_EQ(4, intSpan.front()); + EXPECT_EQ(7, intSpan.back()); + EXPECT_EQ(6, intSpan[2]); + + // Create subspan from elements 1 .. end - 1 + intSpan = intSpan.subspan(1, intSpan.size() - 2); + EXPECT_NE(intVector.data(), intSpan.data()); + EXPECT_EQ(5, intSpan.front()); + EXPECT_EQ(1, intSpan.back()); + EXPECT_EQ(6, intSpan[1]); + } + + TEST_F(SpanTestFixture, Supspan_Returns_Subview_Succeeds) + { + AZStd::vector intVector{ 4, 5, 6, 1, 7 }; + + AZStd::span intSpan(intVector); + + // dynamic_extent subspan with count + auto dynamicIntSubSpan = intSpan.subspan(1, 2); + ASSERT_EQ(2, dynamicIntSubSpan.size()); + EXPECT_EQ(5, dynamicIntSubSpan[0]); + EXPECT_EQ(6, dynamicIntSubSpan[1]); + + // dynamic_extent subspan without count + dynamicIntSubSpan = intSpan.subspan(1); + ASSERT_EQ(4, dynamicIntSubSpan.size()); + EXPECT_EQ(5, dynamicIntSubSpan[0]); + EXPECT_EQ(6, dynamicIntSubSpan[1]); + EXPECT_EQ(1, dynamicIntSubSpan[2]); + EXPECT_EQ(7, dynamicIntSubSpan[3]); + + // template subspan with count + auto templateIntSubSpan1 = intSpan.subspan<1, 3>(); + static_assert(decltype(templateIntSubSpan1)::extent == 3); + ASSERT_EQ(3, templateIntSubSpan1.size()); + EXPECT_EQ(5, templateIntSubSpan1[0]); + EXPECT_EQ(6, templateIntSubSpan1[1]); + EXPECT_EQ(1, templateIntSubSpan1[2]); + + // template subspan without count + auto templateIntSubSpan2 = intSpan.subspan<1>(); + static_assert(decltype(templateIntSubSpan2)::extent == AZStd::dynamic_extent); + ASSERT_EQ(4, templateIntSubSpan2.size()); + EXPECT_EQ(5, templateIntSubSpan2[0]); + EXPECT_EQ(6, templateIntSubSpan2[1]); + EXPECT_EQ(1, templateIntSubSpan2[2]); + EXPECT_EQ(7, templateIntSubSpan2[3]); + + // get subspan of fixed extent span without count + auto subSpanOfSubSpan = templateIntSubSpan1.subspan<1>(); + static_assert(decltype(subSpanOfSubSpan)::extent == 2); + ASSERT_EQ(2, subSpanOfSubSpan.size()); + EXPECT_EQ(6, subSpanOfSubSpan[0]); + EXPECT_EQ(1, subSpanOfSubSpan[1]); + } + + TEST_F(SpanTestFixture, FirstMethod_Returns_FirstCountElementsOfSpan) + { + constexpr size_t vectorElementCount = 5; + AZStd::vector intVector{ 4, 5, 6, 1, 7 }; + + AZStd::span intSpan(intVector); + + { + // No templated first function + auto prefixSpan = intSpan.first(3); + ASSERT_EQ(3, prefixSpan.size()); + EXPECT_EQ(4, prefixSpan[0]); + EXPECT_EQ(5, prefixSpan[1]); + EXPECT_EQ(6, prefixSpan[2]); + + auto prefixSpanRedux = prefixSpan.first(1); + ASSERT_EQ(1, prefixSpanRedux.size()); + EXPECT_EQ(4, prefixSpanRedux[0]); + + // Test failure of preconditions by requesting more + // elements thant stored in the span + AZ_TEST_START_TRACE_SUPPRESSION; + intSpan.first(intSpan.size() + 1); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + } + + { + // templated first function + auto prefixSpan = intSpan.first<3>(); + static_assert(decltype(prefixSpan)::extent == 3); + ASSERT_EQ(3, prefixSpan.size()); + EXPECT_EQ(4, prefixSpan[0]); + EXPECT_EQ(5, prefixSpan[1]); + EXPECT_EQ(6, prefixSpan[2]); + + auto prefixSpanRedux = prefixSpan.first<1>(); + ASSERT_EQ(1, prefixSpanRedux.size()); + EXPECT_EQ(4, prefixSpanRedux[0]); + + // Test failure of preconditions by requesting more + // elements thant stored in the span + AZ_TEST_START_TRACE_SUPPRESSION; + intSpan.first(); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + } + } + + TEST_F(SpanTestFixture, LastCountElementsOfSpan) + { + constexpr size_t vectorElementCount = 5; + AZStd::vector intVector{ 4, 5, 6, 1, 7 }; + + AZStd::span intSpan(intVector); + + { + // No templated last function + auto suffixSpan = intSpan.last(3); + ASSERT_EQ(3, suffixSpan.size()); + EXPECT_EQ(6, suffixSpan[0]); + EXPECT_EQ(1, suffixSpan[1]); + EXPECT_EQ(7, suffixSpan[2]); + + auto suffixSpanRedux = suffixSpan.last(1); + ASSERT_EQ(1, suffixSpanRedux.size()); + EXPECT_EQ(7, suffixSpanRedux[0]); + + // Test failure of preconditions by requesting more + // elements thant stored in the span + AZ_TEST_START_TRACE_SUPPRESSION; + intSpan.last(intSpan.size() + 1); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + } + + { + // templated last function + auto suffixSpan = intSpan.last<3>(); + static_assert(decltype(suffixSpan)::extent == 3); + ASSERT_EQ(3, suffixSpan.size()); + EXPECT_EQ(6, suffixSpan[0]); + EXPECT_EQ(1, suffixSpan[1]); + EXPECT_EQ(7, suffixSpan[2]); + + auto suffixSpanRedux = suffixSpan.last<1>(); + ASSERT_EQ(1, suffixSpanRedux.size()); + EXPECT_EQ(7, suffixSpanRedux[0]); + + // Test failure of preconditions by requesting more + // elements thant stored in the span + AZ_TEST_START_TRACE_SUPPRESSION; + intSpan.last(); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); + } + } +} diff --git a/Code/Framework/AzCore/Tests/AZStd/TypeTraits.cpp b/Code/Framework/AzCore/Tests/AZStd/TypeTraits.cpp index aeba048d69..d0f34d14a0 100644 --- a/Code/Framework/AzCore/Tests/AZStd/TypeTraits.cpp +++ b/Code/Framework/AzCore/Tests/AZStd/TypeTraits.cpp @@ -45,197 +45,197 @@ namespace UnitTest // Primary type categories: // alignment_of and align_to - AZ_TEST_STATIC_ASSERT(alignment_of::value == 4); - AZ_TEST_STATIC_ASSERT(alignment_of::value == 1); + static_assert(alignment_of::value == 4); + static_assert(alignment_of::value == 1); - AZ_TEST_STATIC_ASSERT(alignment_of::value == 16); - aligned_storage::type alignedArray; + static_assert(alignment_of::value == 16); + aligned_storage::type alignedArray; AZ_TEST_ASSERT((((AZStd::size_t)&alignedArray) & 15) == 0); - AZ_TEST_STATIC_ASSERT((alignment_of< aligned_storage::type >::value) == 8); - AZ_TEST_STATIC_ASSERT(sizeof(aligned_storage::type) == 16); + static_assert((alignment_of< aligned_storage::type >::value) == 8); + static_assert(sizeof(aligned_storage::type) == 16); // is_void - AZ_TEST_STATIC_ASSERT(is_void::value == false); - AZ_TEST_STATIC_ASSERT(is_void::value == true); - AZ_TEST_STATIC_ASSERT(is_void::value == true); - AZ_TEST_STATIC_ASSERT(is_void::value == true); - AZ_TEST_STATIC_ASSERT(is_void::value == true); + static_assert(is_void::value == false); + static_assert(is_void::value == true); + static_assert(is_void::value == true); + static_assert(is_void::value == true); + static_assert(is_void::value == true); // is_integral - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - //AZ_TEST_STATIC_ASSERT(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + //static_assert(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); + static_assert(is_integral::value == true); - AZ_TEST_STATIC_ASSERT(is_integral::value == false); - AZ_TEST_STATIC_ASSERT(is_integral::value == false); - AZ_TEST_STATIC_ASSERT(is_integral::value == false); + static_assert(is_integral::value == false); + static_assert(is_integral::value == false); + static_assert(is_integral::value == false); // is_floating_point - AZ_TEST_STATIC_ASSERT(is_floating_point::value == false); - AZ_TEST_STATIC_ASSERT(is_floating_point::value == true); - AZ_TEST_STATIC_ASSERT(is_floating_point::value == true); - AZ_TEST_STATIC_ASSERT(is_floating_point::value == true); - AZ_TEST_STATIC_ASSERT(is_floating_point::value == true); + static_assert(is_floating_point::value == false); + static_assert(is_floating_point::value == true); + static_assert(is_floating_point::value == true); + static_assert(is_floating_point::value == true); + static_assert(is_floating_point::value == true); // is_array - AZ_TEST_STATIC_ASSERT(is_array::value == false); - AZ_TEST_STATIC_ASSERT(is_array::value == true); - AZ_TEST_STATIC_ASSERT(is_array::value == true); - AZ_TEST_STATIC_ASSERT(is_array::value == true); - AZ_TEST_STATIC_ASSERT(is_array::value == true); + static_assert(is_array::value == false); + static_assert(is_array::value == true); + static_assert(is_array::value == true); + static_assert(is_array::value == true); + static_assert(is_array::value == true); - AZ_TEST_STATIC_ASSERT(is_array::value == true); - AZ_TEST_STATIC_ASSERT(is_array::value == true); - AZ_TEST_STATIC_ASSERT(is_array::value == true); - AZ_TEST_STATIC_ASSERT(is_array::value == true); + static_assert(is_array::value == true); + static_assert(is_array::value == true); + static_assert(is_array::value == true); + static_assert(is_array::value == true); // is_pointer - AZ_TEST_STATIC_ASSERT(is_pointer::value == false); - AZ_TEST_STATIC_ASSERT(is_pointer::value == true); - AZ_TEST_STATIC_ASSERT(is_pointer::value == true); - AZ_TEST_STATIC_ASSERT(is_pointer::value == true); - AZ_TEST_STATIC_ASSERT(is_pointer::value == true); + static_assert(is_pointer::value == false); + static_assert(is_pointer::value == true); + static_assert(is_pointer::value == true); + static_assert(is_pointer::value == true); + static_assert(is_pointer::value == true); // is_reference - AZ_TEST_STATIC_ASSERT(is_reference::value == false); - AZ_TEST_STATIC_ASSERT(is_reference::value == true); - AZ_TEST_STATIC_ASSERT(is_reference::value == true); - AZ_TEST_STATIC_ASSERT(is_reference::value == true); - AZ_TEST_STATIC_ASSERT(is_reference::value == true); + static_assert(is_reference::value == false); + static_assert(is_reference::value == true); + static_assert(is_reference::value == true); + static_assert(is_reference::value == true); + static_assert(is_reference::value == true); // is_member_object_pointer - AZ_TEST_STATIC_ASSERT(is_member_object_pointer::value == false); - AZ_TEST_STATIC_ASSERT(is_member_object_pointer::value == false); - AZ_TEST_STATIC_ASSERT(is_member_object_pointer::value == true); + static_assert(is_member_object_pointer::value == false); + static_assert(is_member_object_pointer::value == false); + static_assert(is_member_object_pointer::value == true); // is_member_function_pointer - AZ_TEST_STATIC_ASSERT(is_member_function_pointer::value == false); - AZ_TEST_STATIC_ASSERT(is_member_function_pointer::value == true); - AZ_TEST_STATIC_ASSERT(is_member_function_pointer::value == false); - AZ_TEST_STATIC_ASSERT((is_member_function_pointer::value)); - AZ_TEST_STATIC_ASSERT((is_member_function_pointer::value)); - AZ_TEST_STATIC_ASSERT((is_member_function_pointer::value)); - AZ_TEST_STATIC_ASSERT((is_member_function_pointer::value)); - AZ_TEST_STATIC_ASSERT((is_member_function_pointer::value)); - AZ_TEST_STATIC_ASSERT((is_member_function_pointer::value)); - AZ_TEST_STATIC_ASSERT((is_member_function_pointer::value)); - AZ_TEST_STATIC_ASSERT((is_member_function_pointer::value)); - AZ_TEST_STATIC_ASSERT((is_member_function_pointer::value)); + static_assert(is_member_function_pointer::value == false); + static_assert(is_member_function_pointer::value == true); + static_assert(is_member_function_pointer::value == false); + static_assert((is_member_function_pointer::value)); + static_assert((is_member_function_pointer::value)); + static_assert((is_member_function_pointer::value)); + static_assert((is_member_function_pointer::value)); + static_assert((is_member_function_pointer::value)); + static_assert((is_member_function_pointer::value)); + static_assert((is_member_function_pointer::value)); + static_assert((is_member_function_pointer::value)); + static_assert((is_member_function_pointer::value)); // is_enum - AZ_TEST_STATIC_ASSERT(is_enum::value == false); - AZ_TEST_STATIC_ASSERT(is_enum::value == false); - AZ_TEST_STATIC_ASSERT(is_enum::value == true); + static_assert(is_enum::value == false); + static_assert(is_enum::value == false); + static_assert(is_enum::value == true); // is_union - AZ_TEST_STATIC_ASSERT(is_union::value == false); - AZ_TEST_STATIC_ASSERT(is_union::value == false); - AZ_TEST_STATIC_ASSERT(is_union::value == true); + static_assert(is_union::value == false); + static_assert(is_union::value == false); + static_assert(is_union::value == true); // is_class - AZ_TEST_STATIC_ASSERT(is_class::value == false); - AZ_TEST_STATIC_ASSERT(is_class::value == true); - AZ_TEST_STATIC_ASSERT(is_class::value == true); + static_assert(is_class::value == false); + static_assert(is_class::value == true); + static_assert(is_class::value == true); // is_function - AZ_TEST_STATIC_ASSERT(is_function::value == false); - AZ_TEST_STATIC_ASSERT(is_function::value == false); - AZ_TEST_STATIC_ASSERT(is_function::value == true); + static_assert(is_function::value == false); + static_assert(is_function::value == false); + static_assert(is_function::value == true); ////////////////////////////////////////////////////////////////////////// // composite type categories: // is_arithmetic - AZ_TEST_STATIC_ASSERT(is_arithmetic::value == false); - AZ_TEST_STATIC_ASSERT(is_arithmetic::value == true); - AZ_TEST_STATIC_ASSERT(is_arithmetic::value == true); + static_assert(is_arithmetic::value == false); + static_assert(is_arithmetic::value == true); + static_assert(is_arithmetic::value == true); // is_fundamental - AZ_TEST_STATIC_ASSERT(is_fundamental::value == false); - AZ_TEST_STATIC_ASSERT(is_fundamental::value == true); - AZ_TEST_STATIC_ASSERT(is_fundamental::value == true); - AZ_TEST_STATIC_ASSERT(is_fundamental::value == true); + static_assert(is_fundamental::value == false); + static_assert(is_fundamental::value == true); + static_assert(is_fundamental::value == true); + static_assert(is_fundamental::value == true); // is_object - AZ_TEST_STATIC_ASSERT(is_object::value == true); - AZ_TEST_STATIC_ASSERT(is_object::value == false); - AZ_TEST_STATIC_ASSERT(is_object::value == false); - AZ_TEST_STATIC_ASSERT(is_object::value == false); + static_assert(is_object::value == true); + static_assert(is_object::value == false); + static_assert(is_object::value == false); + static_assert(is_object::value == false); // is_scalar - AZ_TEST_STATIC_ASSERT(is_scalar::value == false); - AZ_TEST_STATIC_ASSERT(is_scalar::value == true); - AZ_TEST_STATIC_ASSERT(is_scalar::value == true); - AZ_TEST_STATIC_ASSERT(is_scalar::value == true); + static_assert(is_scalar::value == false); + static_assert(is_scalar::value == true); + static_assert(is_scalar::value == true); + static_assert(is_scalar::value == true); // is_compound - AZ_TEST_STATIC_ASSERT(is_compound::value == false); - AZ_TEST_STATIC_ASSERT(is_compound::value == true); - AZ_TEST_STATIC_ASSERT(is_compound::value == true); - AZ_TEST_STATIC_ASSERT(is_compound::value == true); - AZ_TEST_STATIC_ASSERT(is_compound::value == true); - AZ_TEST_STATIC_ASSERT(is_compound::value == true); + static_assert(is_compound::value == false); + static_assert(is_compound::value == true); + static_assert(is_compound::value == true); + static_assert(is_compound::value == true); + static_assert(is_compound::value == true); + static_assert(is_compound::value == true); // is_member_pointer - AZ_TEST_STATIC_ASSERT(is_member_pointer::value == false); - AZ_TEST_STATIC_ASSERT(is_member_pointer::value == true); - AZ_TEST_STATIC_ASSERT(is_member_pointer::value == true); + static_assert(is_member_pointer::value == false); + static_assert(is_member_pointer::value == true); + static_assert(is_member_pointer::value == true); ////////////////////////////////////////////////////////////////////////// // type properties: // is_const - AZ_TEST_STATIC_ASSERT(is_const::value == false); - AZ_TEST_STATIC_ASSERT(is_const::value == false); - AZ_TEST_STATIC_ASSERT(is_const::value == true); - AZ_TEST_STATIC_ASSERT(is_const::value == true); + static_assert(is_const::value == false); + static_assert(is_const::value == false); + static_assert(is_const::value == true); + static_assert(is_const::value == true); // is_volatile - AZ_TEST_STATIC_ASSERT(is_volatile::value == false); - AZ_TEST_STATIC_ASSERT(is_volatile::value == false); - AZ_TEST_STATIC_ASSERT(is_volatile::value == true); - AZ_TEST_STATIC_ASSERT(is_volatile::value == true); + static_assert(is_volatile::value == false); + static_assert(is_volatile::value == false); + static_assert(is_volatile::value == true); + static_assert(is_volatile::value == true); // is_pod - AZ_TEST_STATIC_ASSERT(is_pod::value == true); - AZ_TEST_STATIC_ASSERT(is_pod::value == true); - AZ_TEST_STATIC_ASSERT(is_pod::value == false); - AZ_TEST_STATIC_ASSERT((is_pod< aligned_storage<30, 32>::type >::value) == true); + static_assert(is_pod::value == true); + static_assert(is_pod::value == true); + static_assert(is_pod::value == false); + static_assert((is_pod< aligned_storage<30, 32>::type >::value) == true); // is_empty - AZ_TEST_STATIC_ASSERT(is_empty::value == false); - AZ_TEST_STATIC_ASSERT(is_empty::value == true); - AZ_TEST_STATIC_ASSERT(is_empty::value == false); + static_assert(is_empty::value == false); + static_assert(is_empty::value == true); + static_assert(is_empty::value == false); // is_polymorphic - AZ_TEST_STATIC_ASSERT(is_polymorphic::value == false); - AZ_TEST_STATIC_ASSERT(is_polymorphic::value == true); + static_assert(is_polymorphic::value == false); + static_assert(is_polymorphic::value == true); // is_abstract - AZ_TEST_STATIC_ASSERT(is_abstract::value == false); - AZ_TEST_STATIC_ASSERT(is_abstract::value == true); + static_assert(is_abstract::value == false); + static_assert(is_abstract::value == true); // has_trivial_constructor static_assert(is_trivially_constructible_v); @@ -264,20 +264,20 @@ namespace UnitTest // has_nothrow_assign // is_signed - AZ_TEST_STATIC_ASSERT(is_signed::value == true); - AZ_TEST_STATIC_ASSERT(is_signed::value == false); - AZ_TEST_STATIC_ASSERT(is_signed::value == false); + static_assert(is_signed::value == true); + static_assert(is_signed::value == false); + static_assert(is_signed::value == false); static_assert(is_signed::value); // is_unsigned - AZ_TEST_STATIC_ASSERT(is_unsigned::value == false); - AZ_TEST_STATIC_ASSERT(is_unsigned::value == false); - AZ_TEST_STATIC_ASSERT(is_unsigned::value == true); - AZ_TEST_STATIC_ASSERT(is_unsigned::value == false); + static_assert(is_unsigned::value == false); + static_assert(is_unsigned::value == false); + static_assert(is_unsigned::value == true); + static_assert(is_unsigned::value == false); // true and false types - AZ_TEST_STATIC_ASSERT(true_type::value == true); - AZ_TEST_STATIC_ASSERT(false_type::value == false); + static_assert(true_type::value == true); + static_assert(false_type::value == false); //! function traits tests struct NotMyStruct @@ -290,7 +290,7 @@ namespace UnitTest { bool operator()(FunctionTestStruct&) const { return true; }; }; - + using PrimitiveFunctionPtr = int(*)(bool, float, double, AZ::u8, AZ::s8, AZ::u16, AZ::s16, AZ::u32, AZ::s32, AZ::u64, AZ::s64); using NotMyStructMemberPtr = int(NotMyStruct::*)(); using ComplexFunctionPtr = float(*)(MyEmptyStruct&, NotMyStructMemberPtr, MyUnion*); @@ -298,27 +298,27 @@ namespace UnitTest using MemberFunctionPtr = void(MyInterface::*)(int); using ConstMemberFunctionPtr = bool(FunctionTestStruct::*)(FunctionTestStruct&) const; - AZ_TEST_STATIC_ASSERT((AZStd::is_same::result_type, int>::value)); - AZ_TEST_STATIC_ASSERT((AZStd::is_same::get_arg_t<10>, AZ::s64>::value)); - AZ_TEST_STATIC_ASSERT((AZStd::is_same, AZ::u16>::value)); - AZ_TEST_STATIC_ASSERT((AZStd::function_traits::arity == 11)); - - AZ_TEST_STATIC_ASSERT((AZStd::is_same, float>::value)); - AZ_TEST_STATIC_ASSERT((AZStd::is_same, int(NotMyStruct::*)()>::value)); - AZ_TEST_STATIC_ASSERT((AZStd::function_traits::arity == 3)); + static_assert((AZStd::is_same::result_type, int>::value)); + static_assert((AZStd::is_same::get_arg_t<10>, AZ::s64>::value)); + static_assert((AZStd::is_same, AZ::u16>::value)); + static_assert((AZStd::function_traits::arity == 11)); - AZ_TEST_STATIC_ASSERT((AZStd::is_same::class_fp_type, void(MyInterface::*)(int)>::value)); - AZ_TEST_STATIC_ASSERT((AZStd::is_same::raw_fp_type, void(*)(int)>::value)); - AZ_TEST_STATIC_ASSERT((AZStd::is_same::class_type, MyInterface>::value)); - AZ_TEST_STATIC_ASSERT((AZStd::function_traits::arity == 1)); + static_assert((AZStd::is_same, float>::value)); + static_assert((AZStd::is_same, int(NotMyStruct::*)()>::value)); + static_assert((AZStd::function_traits::arity == 3)); - AZ_TEST_STATIC_ASSERT((AZStd::is_same::class_fp_type, bool(FunctionTestStruct::*)(FunctionTestStruct&) const> ::value)); - AZ_TEST_STATIC_ASSERT((AZStd::is_same::raw_fp_type, bool(*)(FunctionTestStruct&)> ::value)); - AZ_TEST_STATIC_ASSERT((AZStd::is_same::class_type, FunctionTestStruct>::value)); - AZ_TEST_STATIC_ASSERT((AZStd::is_same, FunctionTestStruct&>::value)); - AZ_TEST_STATIC_ASSERT((AZStd::function_traits::arity == 1)); - - AZ_TEST_STATIC_ASSERT((AZStd::is_same::class_fp_type, bool(FunctionTestStruct::*)(FunctionTestStruct&) const>::value)); + static_assert((AZStd::is_same::class_fp_type, void(MyInterface::*)(int)>::value)); + static_assert((AZStd::is_same::raw_fp_type, void(*)(int)>::value)); + static_assert((AZStd::is_same::class_type, MyInterface>::value)); + static_assert((AZStd::function_traits::arity == 1)); + + static_assert((AZStd::is_same::class_fp_type, bool(FunctionTestStruct::*)(FunctionTestStruct&) const> ::value)); + static_assert((AZStd::is_same::raw_fp_type, bool(*)(FunctionTestStruct&)> ::value)); + static_assert((AZStd::is_same::class_type, FunctionTestStruct>::value)); + static_assert((AZStd::is_same, FunctionTestStruct&>::value)); + static_assert((AZStd::function_traits::arity == 1)); + + static_assert((AZStd::is_same::class_fp_type, bool(FunctionTestStruct::*)(FunctionTestStruct&) const>::value)); auto lambdaFunction = [](FunctionTestStruct, int) -> bool { @@ -326,16 +326,16 @@ namespace UnitTest }; using LambdaType = decltype(lambdaFunction); - AZ_TEST_STATIC_ASSERT((AZStd::is_same::raw_fp_type, bool(*)(FunctionTestStruct, int)>::value)); - AZ_TEST_STATIC_ASSERT((AZStd::is_same::class_fp_type, bool(LambdaType::*)(FunctionTestStruct, int) const>::value)); - AZ_TEST_STATIC_ASSERT((AZStd::function_traits::arity == 2)); + static_assert((AZStd::is_same::raw_fp_type, bool(*)(FunctionTestStruct, int)>::value)); + static_assert((AZStd::is_same::class_fp_type, bool(LambdaType::*)(FunctionTestStruct, int) const>::value)); + static_assert((AZStd::function_traits::arity == 2)); static_assert(AZStd::is_same::return_type, bool>::value, "Lambda result type should be bool"); AZStd::function stdFunction; using StdFunctionType = decay_t; - AZ_TEST_STATIC_ASSERT((AZStd::is_same::raw_fp_type, void(*)(LambdaType*, ComplexFunction&)>::value)); - AZ_TEST_STATIC_ASSERT((AZStd::function_traits::arity == 2)); - } + static_assert((AZStd::is_same::raw_fp_type, void(*)(LambdaType*, ComplexFunction&)>::value)); + static_assert((AZStd::function_traits::arity == 2)); + } struct ConstMethodTestStruct { @@ -343,145 +343,264 @@ namespace UnitTest void NonConstMethod() { } }; - AZ_TEST_STATIC_ASSERT((static_cast(function_traits::qual_flags) & static_cast(Internal::qualifier_flags::const_)) != 0); - AZ_TEST_STATIC_ASSERT((static_cast(function_traits::qual_flags) & static_cast(Internal::qualifier_flags::const_)) == 0); -} + static_assert((static_cast(function_traits::qual_flags)& static_cast(Internal::qualifier_flags::const_)) != 0); + static_assert((static_cast(function_traits::qual_flags)& static_cast(Internal::qualifier_flags::const_)) == 0); -TEST(TypeTraits, StdRemoveConstCompiles) -{ - static_assert(AZStd::is_same_v>, "C++11 std::remove_const_t has failed"); - static_assert(AZStd::is_same_v>, "C++11 std::remove_const_t has failed"); - static_assert(AZStd::is_same_v>, "C++11 std::remove_const_t has failed"); - static_assert(AZStd::is_same_v>, "C++11 std::remove_const_t has failed"); - static_assert(AZStd::is_same_v>, "C++11 std::remove_const_t has failed"); - static_assert(AZStd::is_same_v>>, "C++11 std::remove_const_t has failed"); -} - -TEST(TypeTraits, StdRemoveVolatileCompiles) -{ - static_assert(AZStd::is_same_v>, "C++11 std::remove_volatile_t has failed"); - static_assert(AZStd::is_same_v>, "C++11 std::remove_volatile_t has failed"); - static_assert(AZStd::is_same_v>, "C++11 std::remove_volatile_t has failed"); - static_assert(AZStd::is_same_v>, "C++11 std::remove_volatile_t has failed"); - static_assert(AZStd::is_same_v>, "C++11 std::remove_volatile_t has failed"); - static_assert(AZStd::is_same_v>, "C++11 std::remove_volatile_t has failed"); - static_assert(AZStd::is_same_v>>, "C++11 std::remove_volatile_t has failed"); -} - -TEST(TypeTraits, StdIsConstCompiles) -{ - static_assert(!AZStd::is_const_v, "C++11 std::is_const has failed"); - static_assert(AZStd::is_const_v, "C++11 std::is_const has failed"); - // references are never const - static_assert(!AZStd::is_const_v, "C++11 std::is_const has failed"); - // pointer checks for constness - static_assert(!AZStd::is_const_v, "C++11 std::is_const has failed"); - static_assert(AZStd::is_const_v, "C++11 std::is_const has failed"); - static_assert(AZStd::is_const_v, "C++11 std::is_const has failed"); -} - -TEST(TypeTraits, StdIsVolatileCompiles) -{ - static_assert(!AZStd::is_volatile_v, "C++11 std::is_volatile has failed"); - static_assert(AZStd::is_volatile_v, "C++11 std::is_volatile has failed"); - // references are never volatile - static_assert(!AZStd::is_volatile_v, "C++11 std::is_volatile has failed"); - // pointer checks for volatile - static_assert(!AZStd::is_volatile_v, "C++11 std::is_volatile has failed"); - static_assert(AZStd::is_volatile_v, "C++11 std::is_volatile has failed"); - static_assert(!AZStd::is_volatile_v, "C++11 std::is_volatile has failed"); - static_assert(AZStd::is_volatile_v, "C++11 std::is_volatile has failed"); -} - -TEST(TypeTraits, TemplateIsCopyConstructible_WithCopyConstructibleValueType_ReturnsTrue) -{ - static_assert(AZStd::Internal::template_is_copy_constructible>::value, ""); - static_assert(AZStd::Internal::template_is_copy_constructible>::value, ""); - static_assert(AZStd::Internal::template_is_copy_constructible>::value, ""); - static_assert(AZStd::Internal::template_is_copy_constructible>::value, ""); - static_assert(AZStd::Internal::template_is_copy_constructible>::value, ""); - static_assert(AZStd::Internal::template_is_copy_constructible>::value, ""); - static_assert(AZStd::Internal::template_is_copy_constructible>::value, ""); - static_assert(AZStd::Internal::template_is_copy_constructible>::value, ""); - static_assert(AZStd::Internal::template_is_copy_constructible>::value, ""); - static_assert(AZStd::Internal::template_is_copy_constructible>::value, ""); - static_assert(AZStd::Internal::template_is_copy_constructible>::value, ""); - static_assert(AZStd::Internal::template_is_copy_constructible>::value, ""); - - struct CopyableType + TEST(TypeTraits, StdRemoveConstCompiles) { - CopyableType() = default; - CopyableType(const CopyableType&) = default; - }; - static_assert(AZStd::Internal::template_is_copy_constructible::value, ""); -} + static_assert(AZStd::is_same_v>, "C++11 std::remove_const_t has failed"); + static_assert(AZStd::is_same_v>, "C++11 std::remove_const_t has failed"); + static_assert(AZStd::is_same_v>, "C++11 std::remove_const_t has failed"); + static_assert(AZStd::is_same_v>, "C++11 std::remove_const_t has failed"); + static_assert(AZStd::is_same_v>, "C++11 std::remove_const_t has failed"); + static_assert(AZStd::is_same_v>>, "C++11 std::remove_const_t has failed"); + } -TEST(TypeTraits, TemplateIsCopyConstructible_WithOutCopyConstructibleValueType_ReturnsFalse) -{ - static_assert(!AZStd::Internal::template_is_copy_constructible>>::value, ""); - static_assert(!AZStd::Internal::template_is_copy_constructible>>::value, ""); - static_assert(!AZStd::Internal::template_is_copy_constructible>>::value, ""); - static_assert(!AZStd::Internal::template_is_copy_constructible, int>>::value, ""); - static_assert(!AZStd::Internal::template_is_copy_constructible>>::value, ""); - static_assert(!AZStd::Internal::template_is_copy_constructible, int>>::value, ""); - static_assert(!AZStd::Internal::template_is_copy_constructible>>::value, ""); - static_assert(!AZStd::Internal::template_is_copy_constructible, int>>::value, ""); - static_assert(!AZStd::Internal::template_is_copy_constructible>>::value, ""); - static_assert(!AZStd::Internal::template_is_copy_constructible, int>>::value, ""); - static_assert(!AZStd::Internal::template_is_copy_constructible>>::value, ""); - static_assert(!AZStd::Internal::template_is_copy_constructible>>::value, ""); - static_assert(!AZStd::Internal::template_is_copy_constructible>>::value, ""); - static_assert(!AZStd::Internal::template_is_copy_constructible>>::value, ""); - static_assert(!AZStd::Internal::template_is_copy_constructible>>::value, ""); - static_assert(!AZStd::Internal::template_is_copy_constructible, int>>::value, ""); - static_assert(!AZStd::Internal::template_is_copy_constructible>>::value, ""); - - struct MoveOnly + TEST(TypeTraits, StdRemoveVolatileCompiles) { - MoveOnly() = default; - MoveOnly(const MoveOnly&) = delete; - MoveOnly(MoveOnly&&) = default; - }; - static_assert(!AZStd::Internal::template_is_copy_constructible::value, ""); -} + static_assert(AZStd::is_same_v>, "C++11 std::remove_volatile_t has failed"); + static_assert(AZStd::is_same_v>, "C++11 std::remove_volatile_t has failed"); + static_assert(AZStd::is_same_v>, "C++11 std::remove_volatile_t has failed"); + static_assert(AZStd::is_same_v>, "C++11 std::remove_volatile_t has failed"); + static_assert(AZStd::is_same_v>, "C++11 std::remove_volatile_t has failed"); + static_assert(AZStd::is_same_v>, "C++11 std::remove_volatile_t has failed"); + static_assert(AZStd::is_same_v>>, "C++11 std::remove_volatile_t has failed"); + } -TEST(TypeTraits, MakeSignedCompiles) -{ - static_assert(AZStd::is_same_v::type, AZ::s8>); - static_assert(AZStd::is_same_v, AZ::s8>); - static_assert(AZStd::is_same_v, AZ::s16>); - static_assert(AZStd::is_same_v, AZ::s16>); - static_assert(AZStd::is_same_v, AZ::s32>); - static_assert(AZStd::is_same_v, AZ::s32>); - static_assert(AZStd::is_same_v, AZ::s64>); - static_assert(AZStd::is_same_v, AZ::s64>); -} - -TEST(TypeTraits, MakeUnsignedCompiles) -{ - static_assert(AZStd::is_same_v::type, AZ::u8>); - static_assert(AZStd::is_same_v, AZ::u8>); - static_assert(AZStd::is_same_v, AZ::u16>); - static_assert(AZStd::is_same_v, AZ::u16>); - static_assert(AZStd::is_same_v, AZ::u32>); - static_assert(AZStd::is_same_v, AZ::u32>); - static_assert(AZStd::is_same_v, AZ::u64>); - static_assert(AZStd::is_same_v, AZ::u64>); -} - -// VS2017 workaround, calling decltype directly on the fully specialized aznumeric_cast template -// function fails with error C3556: 'aznumeric_cast': incorrect argument to 'decltype' -// So invoke the attempt to invoke function in a non-evaluated context and SFINAE to prevent a compile -// error -template -constexpr bool NumericCastInvocable = false; -template -constexpr bool NumericCastInvocable(AZStd::declval()))>> = true; -TEST(TypeTraits, NumericCastConversionOperatorCompiles) -{ - struct AzNumericCastConvertibleCompileTest + TEST(TypeTraits, StdIsConstCompiles) { - constexpr operator int() { return {}; }; - }; - static_assert(NumericCastInvocable, "aznumeric_cast conversion operator overload is should be compilable"); + static_assert(!AZStd::is_const_v, "C++11 std::is_const has failed"); + static_assert(AZStd::is_const_v, "C++11 std::is_const has failed"); + // references are never const + static_assert(!AZStd::is_const_v, "C++11 std::is_const has failed"); + // pointer checks for constness + static_assert(!AZStd::is_const_v, "C++11 std::is_const has failed"); + static_assert(AZStd::is_const_v, "C++11 std::is_const has failed"); + static_assert(AZStd::is_const_v, "C++11 std::is_const has failed"); + } + + TEST(TypeTraits, StdIsVolatileCompiles) + { + static_assert(!AZStd::is_volatile_v, "C++11 std::is_volatile has failed"); + static_assert(AZStd::is_volatile_v, "C++11 std::is_volatile has failed"); + // references are never volatile + static_assert(!AZStd::is_volatile_v, "C++11 std::is_volatile has failed"); + // pointer checks for volatile + static_assert(!AZStd::is_volatile_v, "C++11 std::is_volatile has failed"); + static_assert(AZStd::is_volatile_v, "C++11 std::is_volatile has failed"); + static_assert(!AZStd::is_volatile_v, "C++11 std::is_volatile has failed"); + static_assert(AZStd::is_volatile_v, "C++11 std::is_volatile has failed"); + } + + + struct CommonReferenceSpecializationTest + {}; +} + +namespace AZStd +{ + template